Switch to throwing exceptions with all of the info needed to build error messages
This commit is contained in:
parent
9dc5165a58
commit
d1175fe364
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
using namespace realm;
|
using namespace realm;
|
||||||
|
|
||||||
|
namespace {
|
||||||
const char * const c_metadataTableName = "metadata";
|
const char * const c_metadataTableName = "metadata";
|
||||||
const char * const c_versionColumnName = "version";
|
const char * const c_versionColumnName = "version";
|
||||||
const size_t c_versionColumnIndex = 0;
|
const size_t c_versionColumnIndex = 0;
|
||||||
|
@ -42,8 +43,8 @@ const size_t c_primaryKeyPropertyNameColumnIndex = 1;
|
||||||
|
|
||||||
const size_t c_zeroRowIndex = 0;
|
const size_t c_zeroRowIndex = 0;
|
||||||
|
|
||||||
const std::string c_object_table_prefix = "class_";
|
const char c_object_table_prefix[] = "class_";
|
||||||
const size_t c_object_table_prefix_length = c_object_table_prefix.length();
|
}
|
||||||
|
|
||||||
const uint64_t ObjectStore::NotVersioned = std::numeric_limits<uint64_t>::max();
|
const uint64_t ObjectStore::NotVersioned = std::numeric_limits<uint64_t>::max();
|
||||||
|
|
||||||
|
@ -119,15 +120,15 @@ void ObjectStore::set_primary_key_for_object(Group *group, StringData object_typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ObjectStore::object_type_for_table_name(const std::string &table_name) {
|
StringData ObjectStore::object_type_for_table_name(StringData table_name) {
|
||||||
if (table_name.size() >= c_object_table_prefix_length && table_name.compare(0, c_object_table_prefix_length, c_object_table_prefix) == 0) {
|
if (table_name.begins_with(c_object_table_prefix)) {
|
||||||
return table_name.substr(c_object_table_prefix_length, table_name.length() - c_object_table_prefix_length);
|
return table_name.substr(sizeof(c_object_table_prefix) - 1);
|
||||||
}
|
}
|
||||||
return std::string();
|
return StringData();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ObjectStore::table_name_for_object_type(const std::string &object_type) {
|
std::string ObjectStore::table_name_for_object_type(StringData object_type) {
|
||||||
return c_object_table_prefix + object_type;
|
return std::string(c_object_table_prefix) + object_type.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
TableRef ObjectStore::table_for_object_type(Group *group, StringData object_type) {
|
TableRef ObjectStore::table_for_object_type(Group *group, StringData object_type) {
|
||||||
|
@ -138,7 +139,7 @@ ConstTableRef ObjectStore::table_for_object_type(const Group *group, StringData
|
||||||
return group->get_table(table_name_for_object_type(object_type));
|
return group->get_table(table_name_for_object_type(object_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
TableRef ObjectStore::table_for_object_type_create_if_needed(Group *group, const StringData &object_type, bool &created) {
|
TableRef ObjectStore::table_for_object_type_create_if_needed(Group *group, StringData object_type, bool &created) {
|
||||||
return group->get_or_add_table(table_name_for_object_type(object_type), &created);
|
return group->get_or_add_table(table_name_for_object_type(object_type), &created);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,7 +495,7 @@ void ObjectStore::validate_primary_column_uniqueness(const Group *group, Schema
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectStore::delete_data_for_object(Group *group, const StringData &object_type) {
|
void ObjectStore::delete_data_for_object(Group *group, StringData object_type) {
|
||||||
TableRef table = table_for_object_type(group, object_type);
|
TableRef table = table_for_object_type(group, object_type);
|
||||||
if (table) {
|
if (table) {
|
||||||
group->remove_table(table->get_index_in_group());
|
group->remove_table(table->get_index_in_group());
|
||||||
|
|
|
@ -68,11 +68,14 @@ namespace realm {
|
||||||
static Schema schema_from_group(const Group *group);
|
static Schema schema_from_group(const Group *group);
|
||||||
|
|
||||||
// deletes the table for the given type
|
// deletes the table for the given type
|
||||||
static void delete_data_for_object(Group *group, const StringData &object_type);
|
static void delete_data_for_object(Group *group, StringData object_type);
|
||||||
|
|
||||||
// indicates if this group contains any objects
|
// indicates if this group contains any objects
|
||||||
static bool is_empty(const Group *group);
|
static bool is_empty(const Group *group);
|
||||||
|
|
||||||
|
static std::string table_name_for_object_type(StringData class_name);
|
||||||
|
static StringData object_type_for_table_name(StringData table_name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// set a new schema version
|
// set a new schema version
|
||||||
static void set_schema_version(Group *group, uint64_t version);
|
static void set_schema_version(Group *group, uint64_t version);
|
||||||
|
@ -102,9 +105,7 @@ namespace realm {
|
||||||
// must be in write transaction to set
|
// must be in write transaction to set
|
||||||
static void set_primary_key_for_object(Group *group, StringData object_type, StringData primary_key);
|
static void set_primary_key_for_object(Group *group, StringData object_type, StringData primary_key);
|
||||||
|
|
||||||
static TableRef table_for_object_type_create_if_needed(Group *group, const StringData &object_type, bool &created);
|
static TableRef table_for_object_type_create_if_needed(Group *group, StringData object_type, bool &created);
|
||||||
static std::string table_name_for_object_type(const std::string &class_name);
|
|
||||||
static std::string object_type_for_table_name(const std::string &table_name);
|
|
||||||
|
|
||||||
// returns if any indexes were changed
|
// returns if any indexes were changed
|
||||||
static bool update_indexes(Group *group, Schema &schema);
|
static bool update_indexes(Group *group, Schema &schema);
|
||||||
|
|
28
results.cpp
28
results.cpp
|
@ -52,17 +52,17 @@ Results::Results(SharedRealm r, Table& table)
|
||||||
|
|
||||||
void Results::validate_read() const
|
void Results::validate_read() const
|
||||||
{
|
{
|
||||||
if (m_realm && !m_realm->check_thread())
|
if (m_realm)
|
||||||
throw Error::IncorrectThread;
|
m_realm->verify_thread();
|
||||||
if (m_table && !m_table->is_attached())
|
if (m_table && !m_table->is_attached())
|
||||||
throw Error::Invalidated;
|
throw InvalidatedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Results::validate_write() const
|
void Results::validate_write() const
|
||||||
{
|
{
|
||||||
validate_read();
|
validate_read();
|
||||||
if (!m_realm || !m_realm->is_in_transaction())
|
if (!m_realm || !m_realm->is_in_transaction())
|
||||||
throw Error::NotInWrite;
|
throw InvalidTransactionException("Must be in a write transaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Results::size()
|
size_t Results::size()
|
||||||
|
@ -96,7 +96,7 @@ RowExpr Results::get(size_t row_ndx)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw Error::OutOfBoundsIndex;
|
throw OutOfBoundsIndexException{row_ndx, size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Optional<RowExpr> Results::first()
|
util::Optional<RowExpr> Results::first()
|
||||||
|
@ -157,10 +157,10 @@ size_t Results::index_of(Row const& row)
|
||||||
{
|
{
|
||||||
validate_read();
|
validate_read();
|
||||||
if (!row) {
|
if (!row) {
|
||||||
throw Error::DetachedAccessor;
|
throw DetatchedAccessorException{};
|
||||||
}
|
}
|
||||||
if (m_table && row.get_table() != m_table) {
|
if (m_table && row.get_table() != m_table) {
|
||||||
throw Error::IncorrectTable;
|
throw IncorrectTableException{m_table, row.get_table()};
|
||||||
}
|
}
|
||||||
return index_of(row.get_index());
|
return index_of(row.get_index());
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,7 @@ util::Optional<Mixed> Results::aggregate(size_t column, bool return_none_for_emp
|
||||||
if (!m_table)
|
if (!m_table)
|
||||||
return none;
|
return none;
|
||||||
if (column > m_table->get_column_count())
|
if (column > m_table->get_column_count())
|
||||||
throw Error::OutOfBoundsIndex;
|
throw OutOfBoundsIndexException{column, m_table->get_column_count()};
|
||||||
|
|
||||||
auto do_agg = [&](auto const& getter) -> util::Optional<Mixed> {
|
auto do_agg = [&](auto const& getter) -> util::Optional<Mixed> {
|
||||||
switch (m_mode) {
|
switch (m_mode) {
|
||||||
|
@ -220,7 +220,7 @@ util::Optional<Mixed> Results::aggregate(size_t column, bool return_none_for_emp
|
||||||
case type_Float: return do_agg(agg_float);
|
case type_Float: return do_agg(agg_float);
|
||||||
case type_Int: return do_agg(agg_int);
|
case type_Int: return do_agg(agg_int);
|
||||||
default:
|
default:
|
||||||
throw Error::UnsupportedColumnType;
|
throw UnsupportedColumnTypeException{column, m_table};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ util::Optional<Mixed> Results::sum(size_t column)
|
||||||
[=](auto const& table) { return table.sum_int(column); },
|
[=](auto const& table) { return table.sum_int(column); },
|
||||||
[=](auto const& table) { return table.sum_float(column); },
|
[=](auto const& table) { return table.sum_float(column); },
|
||||||
[=](auto const& table) { return table.sum_double(column); },
|
[=](auto const& table) { return table.sum_double(column); },
|
||||||
[=](auto const&) -> util::None { throw Error::UnsupportedColumnType; });
|
[=](auto const&) -> util::None { throw UnsupportedColumnTypeException{column, m_table}; });
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Optional<Mixed> Results::average(size_t column)
|
util::Optional<Mixed> Results::average(size_t column)
|
||||||
|
@ -257,7 +257,7 @@ util::Optional<Mixed> Results::average(size_t column)
|
||||||
[=](auto const& table) { return table.average_int(column); },
|
[=](auto const& table) { return table.average_int(column); },
|
||||||
[=](auto const& table) { return table.average_float(column); },
|
[=](auto const& table) { return table.average_float(column); },
|
||||||
[=](auto const& table) { return table.average_double(column); },
|
[=](auto const& table) { return table.average_double(column); },
|
||||||
[=](auto const&) -> util::None { throw Error::UnsupportedColumnType; });
|
[=](auto const&) -> util::None { throw UnsupportedColumnTypeException{column, m_table}; });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Results::clear()
|
void Results::clear()
|
||||||
|
@ -319,3 +319,9 @@ Results Results::filter(Query&& q) const
|
||||||
{
|
{
|
||||||
return Results(m_realm, get_query().and_query(q), get_sort());
|
return Results(m_realm, get_query().and_query(q), get_sort());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Results::UnsupportedColumnTypeException::UnsupportedColumnTypeException(size_t column, const Table* table) {
|
||||||
|
column_index = column;
|
||||||
|
column_name = table->get_column_name(column);
|
||||||
|
column_type = table->get_column_type(column);
|
||||||
|
}
|
||||||
|
|
55
results.hpp
55
results.hpp
|
@ -70,7 +70,7 @@ public:
|
||||||
size_t size();
|
size_t size();
|
||||||
|
|
||||||
// Get the row accessor for the given index
|
// Get the row accessor for the given index
|
||||||
// Throws OutOfBoundsIndex if index >= size()
|
// Throws OutOfBoundsIndexException if index >= size()
|
||||||
RowExpr get(size_t index);
|
RowExpr get(size_t index);
|
||||||
|
|
||||||
// Get a row accessor for the first/last row, or none if the results are empty
|
// Get a row accessor for the first/last row, or none if the results are empty
|
||||||
|
@ -79,14 +79,14 @@ public:
|
||||||
util::Optional<RowExpr> last();
|
util::Optional<RowExpr> last();
|
||||||
|
|
||||||
// Get the first index of the given row in this results, or not_found
|
// Get the first index of the given row in this results, or not_found
|
||||||
// Throws DetachedAccessor if row is not attached
|
// Throws DetachedAccessorException if row is not attached
|
||||||
// Throws IncorrectTable if row belongs to a different table
|
// Throws IncorrectTableException if row belongs to a different table
|
||||||
size_t index_of(size_t row_ndx);
|
size_t index_of(size_t row_ndx);
|
||||||
size_t index_of(Row const& row);
|
size_t index_of(Row const& row);
|
||||||
|
|
||||||
// Delete all of the rows in this Results from the Realm
|
// Delete all of the rows in this Results from the Realm
|
||||||
// size() will always be zero afterwards
|
// size() will always be zero afterwards
|
||||||
// Throws NotInWrite
|
// Throws InvalidTransactionException if not in a write transaction
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
// Create a new Results by further filtering or sorting this Results
|
// Create a new Results by further filtering or sorting this Results
|
||||||
|
@ -96,8 +96,8 @@ public:
|
||||||
// Get the min/max/average/sum of the given column
|
// Get the min/max/average/sum of the given column
|
||||||
// All but sum() returns none when there are zero matching rows
|
// All but sum() returns none when there are zero matching rows
|
||||||
// sum() returns 0, except for when it returns none
|
// sum() returns 0, except for when it returns none
|
||||||
// Throws UnsupportedColumnType for sum/average on datetime or non-numeric column
|
// Throws UnsupportedColumnTypeException for sum/average on datetime or non-numeric column
|
||||||
// Throws OutOfBoundsIndex for an out-of-bounds column
|
// Throws OutOfBoundsIndexException for an out-of-bounds column
|
||||||
util::Optional<Mixed> max(size_t column);
|
util::Optional<Mixed> max(size_t column);
|
||||||
util::Optional<Mixed> min(size_t column);
|
util::Optional<Mixed> min(size_t column);
|
||||||
util::Optional<Mixed> average(size_t column);
|
util::Optional<Mixed> average(size_t column);
|
||||||
|
@ -113,25 +113,32 @@ public:
|
||||||
// Ideally this would not be public but it's needed for some KVO stuff
|
// Ideally this would not be public but it's needed for some KVO stuff
|
||||||
Mode get_mode() const { return m_mode; }
|
Mode get_mode() const { return m_mode; }
|
||||||
|
|
||||||
// All errors thrown by Results are one of the following error codes
|
// The Results object has been invalidated (due to the Realm being invalidated)
|
||||||
// Invalidated and IncorrectThread can be thrown by all non-noexcept functions
|
// All non-noexcept functions can throw this
|
||||||
// Other errors are thrown only where indicated
|
struct InvalidatedException {};
|
||||||
enum class Error {
|
|
||||||
// The Results object has been invalidated (due to the Realm being invalidated)
|
|
||||||
Invalidated,
|
|
||||||
// The Results object is being accessed from the wrong thread
|
|
||||||
IncorrectThread,
|
|
||||||
// The containing Realm is not in a write transaction
|
|
||||||
NotInWrite,
|
|
||||||
|
|
||||||
// The input index parameter was out of bounds
|
// The input index parameter was out of bounds
|
||||||
OutOfBoundsIndex,
|
struct OutOfBoundsIndexException {
|
||||||
// The input Row object belongs to a different table
|
size_t requested;
|
||||||
IncorrectTable,
|
size_t valid_count;
|
||||||
// The input Row object is not attached
|
};
|
||||||
DetachedAccessor,
|
|
||||||
// The requested aggregate operation is not supported for the column type
|
// The input Row object is not attached
|
||||||
UnsupportedColumnType
|
struct DetatchedAccessorException { };
|
||||||
|
|
||||||
|
// The input Row object belongs to a different table
|
||||||
|
struct IncorrectTableException {
|
||||||
|
const Table* expected;
|
||||||
|
const Table* actual;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The requested aggregate operation is not supported for the column type
|
||||||
|
struct UnsupportedColumnTypeException {
|
||||||
|
size_t column_index;
|
||||||
|
StringData column_name;
|
||||||
|
DataType column_type;
|
||||||
|
|
||||||
|
UnsupportedColumnTypeException(size_t column, const Table* table);
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -236,15 +236,17 @@ static void check_read_write(Realm *realm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Realm::check_thread() const noexcept
|
|
||||||
{
|
|
||||||
return m_thread_id == std::this_thread::get_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Realm::verify_thread() const
|
void Realm::verify_thread() const
|
||||||
{
|
{
|
||||||
if (!check_thread()) {
|
if (m_thread_id != std::this_thread::get_id()) {
|
||||||
throw IncorrectThreadException("Realm accessed from incorrect thread.");
|
throw IncorrectThreadException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Realm::verify_in_write() const
|
||||||
|
{
|
||||||
|
if (!is_in_transaction()) {
|
||||||
|
throw InvalidTransactionException("Cannot modify persisted objects outside of a write transaction.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,8 +98,8 @@ namespace realm {
|
||||||
bool compact();
|
bool compact();
|
||||||
|
|
||||||
std::thread::id thread_id() const { return m_thread_id; }
|
std::thread::id thread_id() const { return m_thread_id; }
|
||||||
bool check_thread() const noexcept;
|
|
||||||
void verify_thread() const;
|
void verify_thread() const;
|
||||||
|
void verify_in_write() const;
|
||||||
|
|
||||||
// Close this Realm and remove it from the cache. Continuing to use a
|
// Close this Realm and remove it from the cache. Continuing to use a
|
||||||
// Realm after closing it will produce undefined behavior.
|
// Realm after closing it will produce undefined behavior.
|
||||||
|
@ -145,11 +145,9 @@ namespace realm {
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RealmFileException : public std::runtime_error
|
class RealmFileException : public std::runtime_error {
|
||||||
{
|
public:
|
||||||
public:
|
enum class Kind {
|
||||||
enum class Kind
|
|
||||||
{
|
|
||||||
/** Thrown for any I/O related exception scenarios when a realm is opened. */
|
/** Thrown for any I/O related exception scenarios when a realm is opened. */
|
||||||
AccessError,
|
AccessError,
|
||||||
/** Thrown if the user does not have permission to open or create
|
/** Thrown if the user does not have permission to open or create
|
||||||
|
@ -169,32 +167,28 @@ namespace realm {
|
||||||
Kind kind() const { return m_kind; }
|
Kind kind() const { return m_kind; }
|
||||||
const std::string& path() const { return m_path; }
|
const std::string& path() const { return m_path; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Kind m_kind;
|
Kind m_kind;
|
||||||
std::string m_path;
|
std::string m_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MismatchedConfigException : public std::runtime_error
|
class MismatchedConfigException : public std::runtime_error {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
MismatchedConfigException(std::string message) : std::runtime_error(message) {}
|
MismatchedConfigException(std::string message) : std::runtime_error(message) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class InvalidTransactionException : public std::runtime_error
|
class InvalidTransactionException : public std::runtime_error {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
InvalidTransactionException(std::string message) : std::runtime_error(message) {}
|
InvalidTransactionException(std::string message) : std::runtime_error(message) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class IncorrectThreadException : public std::runtime_error
|
class IncorrectThreadException : public std::runtime_error {
|
||||||
{
|
public:
|
||||||
public:
|
IncorrectThreadException() : std::runtime_error("Realm accessed from incorrect thread.") {}
|
||||||
IncorrectThreadException(std::string message) : std::runtime_error(message) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnitializedRealmException : public std::runtime_error
|
class UnitializedRealmException : public std::runtime_error {
|
||||||
{
|
public:
|
||||||
public:
|
|
||||||
UnitializedRealmException(std::string message) : std::runtime_error(message) {}
|
UnitializedRealmException(std::string message) : std::runtime_error(message) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue