mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-10 22:36:01 +00:00
use enum for dict/info keys, support per platform/language exception messages
This commit is contained in:
parent
a29037b47f
commit
c3e82a58ae
@ -55,7 +55,10 @@ ObjectSchema::ObjectSchema(Group *group, const std::string &name) : name(name) {
|
||||
if (primary_key.length()) {
|
||||
auto primary_key_prop = primary_key_property();
|
||||
if (!primary_key_prop) {
|
||||
throw ObjectStoreValidationException({"No property matching primary key '" + primary_key + "'"}, name);
|
||||
throw ObjectStoreException(ObjectStoreException::Kind::ObjectSchemaMismatchedPrimaryKey, {
|
||||
{ObjectStoreException::InfoKey::ObjectType, name},
|
||||
{ObjectStoreException::InfoKey::PrimaryKey, ""},
|
||||
{ObjectStoreException::InfoKey::OldPrimaryKey, primary_key}});
|
||||
}
|
||||
primary_key_prop->is_primary = true;
|
||||
}
|
||||
|
@ -161,8 +161,8 @@ TableRef ObjectStore::table_for_object_type_create_if_needed(Group *group, const
|
||||
return group->get_or_add_table(table_name_for_object_type(object_type), &created);
|
||||
}
|
||||
|
||||
std::vector<std::string> ObjectStore::validate_schema(Group *group, ObjectSchema &target_schema) {
|
||||
vector<string> validation_errors;
|
||||
std::vector<ObjectStoreException> ObjectStore::validate_schema(Group *group, ObjectSchema &target_schema) {
|
||||
vector<ObjectStoreException> exceptions;
|
||||
ObjectSchema table_schema(group, target_schema.name);
|
||||
|
||||
// check to see if properties are the same
|
||||
@ -170,29 +170,20 @@ std::vector<std::string> ObjectStore::validate_schema(Group *group, ObjectSchema
|
||||
auto target_prop = target_schema.property_for_name(current_prop.name);
|
||||
|
||||
if (!target_prop) {
|
||||
validation_errors.push_back("Property '" + current_prop.name + "' is missing from latest object model.");
|
||||
exceptions.emplace_back(ObjectStoreException(ObjectStoreException::Kind::ObjectSchemaMissingProperty,
|
||||
table_schema.name, current_prop));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current_prop.type != target_prop->type) {
|
||||
validation_errors.push_back("Property types for '" + target_prop->name + "' property do not match. " +
|
||||
"Old type '" + string_for_property_type(current_prop.type) +
|
||||
"', new type '" + string_for_property_type(target_prop->type) + "'");
|
||||
exceptions.emplace_back(ObjectStoreException(ObjectStoreException::Kind::ObjectSchemaMismatchedTypes,
|
||||
table_schema.name, current_prop, *target_prop));
|
||||
continue;
|
||||
}
|
||||
if (current_prop.type == PropertyTypeObject || target_prop->type == PropertyTypeArray) {
|
||||
if (current_prop.object_type != target_prop->object_type) {
|
||||
validation_errors.push_back("Target object type for property '" + current_prop.name + "' does not match. " +
|
||||
"Old type '" + current_prop.object_type +
|
||||
"', new type '" + target_prop->object_type + "'.");
|
||||
}
|
||||
}
|
||||
if (current_prop.is_primary != target_prop->is_primary) {
|
||||
if (current_prop.is_primary) {
|
||||
validation_errors.push_back("Property '" + current_prop.name + "' is no longer a primary key.");
|
||||
}
|
||||
else {
|
||||
validation_errors.push_back("Property '" + current_prop.name + "' has been made a primary key.");
|
||||
exceptions.emplace_back(ObjectStoreException(ObjectStoreException::Kind::ObjectSchemaMismatchedObjectTypes,
|
||||
table_schema.name, current_prop, *target_prop));
|
||||
}
|
||||
}
|
||||
if (current_prop.is_nullable != target_prop->is_nullable) {
|
||||
@ -208,14 +199,24 @@ std::vector<std::string> ObjectStore::validate_schema(Group *group, ObjectSchema
|
||||
target_prop->table_column = current_prop.table_column;
|
||||
}
|
||||
|
||||
// check for change to primary key
|
||||
if (table_schema.primary_key != target_schema.primary_key) {
|
||||
exceptions.emplace_back(ObjectStoreException(ObjectStoreException::Kind::ObjectSchemaMismatchedPrimaryKey, {
|
||||
{ObjectStoreException::InfoKey::ObjectType, target_schema.name},
|
||||
{ObjectStoreException::InfoKey::PrimaryKey, target_schema.primary_key},
|
||||
{ObjectStoreException::InfoKey::OldPrimaryKey, table_schema.primary_key},
|
||||
}));
|
||||
}
|
||||
|
||||
// check for new missing properties
|
||||
for (auto& target_prop : target_schema.properties) {
|
||||
if (!table_schema.property_for_name(target_prop.name)) {
|
||||
validation_errors.push_back("Property '" + target_prop.name + "' has been added to latest object model.");
|
||||
exceptions.emplace_back(ObjectStoreException(ObjectStoreException::Kind::ObjectSchemaNewProperty,
|
||||
table_schema.name, target_prop));
|
||||
}
|
||||
}
|
||||
|
||||
return validation_errors;
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
void ObjectStore::update_column_mapping(Group *group, ObjectSchema &target_schema) {
|
||||
@ -345,8 +346,9 @@ bool ObjectStore::create_tables(Group *group, ObjectStore::Schema &target_schema
|
||||
bool ObjectStore::is_schema_at_version(Group *group, uint64_t version) {
|
||||
uint64_t old_version = get_schema_version(group);
|
||||
if (old_version > version && old_version != NotVersioned) {
|
||||
throw ObjectStoreException(ObjectStoreException::Kind::RealmVersionGreaterThanSchemaVersion,
|
||||
{{"old_version", to_string(old_version)}, {"new_version", to_string(version)}});
|
||||
throw ObjectStoreException(ObjectStoreException::Kind::RealmVersionGreaterThanSchemaVersion, {
|
||||
{ObjectStoreException::InfoKey::OldVersion, to_string(old_version)},
|
||||
{ObjectStoreException::InfoKey::NewVersion, to_string(version)}});
|
||||
}
|
||||
return old_version != version;
|
||||
}
|
||||
@ -371,7 +373,7 @@ bool ObjectStore::update_realm_with_schema(Group *group,
|
||||
if (table) {
|
||||
auto errors = validate_schema(group, target_schema);
|
||||
if (errors.size()) {
|
||||
throw ObjectStoreValidationException(errors, target_schema.name);
|
||||
throw ObjectStoreException(errors, target_schema.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -440,11 +442,7 @@ bool ObjectStore::update_indexes(Group *group, Schema &schema) {
|
||||
table->add_search_index(property.table_column);
|
||||
}
|
||||
catch (LogicError const&) {
|
||||
throw ObjectStoreException(ObjectStoreException::Kind::RealmPropertyTypeNotIndexable, {
|
||||
{"object_type", object_schema.name},
|
||||
{"property_name", property.name},
|
||||
{"property_type", string_for_property_type(property.type)}
|
||||
});
|
||||
throw ObjectStoreException(ObjectStoreException::Kind::RealmPropertyTypeNotIndexable, object_schema.name, property);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -464,8 +462,7 @@ void ObjectStore::validate_primary_column_uniqueness(Group *group, Schema &schem
|
||||
|
||||
TableRef table = table_for_object_type(group, object_schema.name);
|
||||
if (table->get_distinct_view(primary_prop->table_column).size() != table->size()) {
|
||||
throw ObjectStoreException(ObjectStoreException::Kind::RealmDuplicatePrimaryKeyValue,
|
||||
{{"object_type", object_schema.name}, {"property_name", primary_prop->name}});
|
||||
throw ObjectStoreException(ObjectStoreException::Kind::RealmDuplicatePrimaryKeyValue, object_schema.name, *primary_prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ namespace realm {
|
||||
// updates the column mapping on the target_schema
|
||||
// if no table is provided it is fetched from the group
|
||||
// returns array of validation errors
|
||||
static std::vector<std::string> validate_schema(Group *group, ObjectSchema &target_schema);
|
||||
static std::vector<ObjectStoreException> validate_schema(Group *group, ObjectSchema &target_schema);
|
||||
|
||||
// updates the target_column member for all properties based on the column indexes in the passed in group
|
||||
static void update_column_mapping(Group *group, ObjectSchema &target_schema);
|
||||
|
@ -17,29 +17,92 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "object_store_exceptions.hpp"
|
||||
#include "property.hpp"
|
||||
|
||||
#include <realm/util/assert.hpp>
|
||||
|
||||
using namespace realm;
|
||||
using namespace std;
|
||||
|
||||
ObjectStoreException::ObjectStoreException(Kind kind, Dict dict) : m_kind(kind), m_dict(dict) {
|
||||
ObjectStoreException::CustomWhat ObjectStoreException::s_custom_what = nullptr;
|
||||
|
||||
ObjectStoreException::ObjectStoreException(Kind kind, Info info) : m_kind(kind), m_info(info) {
|
||||
set_what();
|
||||
}
|
||||
|
||||
ObjectStoreException::ObjectStoreException(Kind kind, const std::string &object_type, const Property &prop) : m_kind(kind) {
|
||||
m_info[InfoKey::ObjectType] = object_type;
|
||||
m_info[InfoKey::PropertyName] = prop.name;
|
||||
m_info[InfoKey::PropertyType] = string_for_property_type(prop.type);
|
||||
m_info[InfoKey::PropertyObjectType] = prop.object_type;
|
||||
set_what();
|
||||
}
|
||||
|
||||
ObjectStoreException::ObjectStoreException(Kind kind, const std::string &object_type, const Property &prop, const Property &oldProp) :
|
||||
m_kind(kind) {
|
||||
m_info[InfoKey::ObjectType] = object_type;
|
||||
m_info[InfoKey::PropertyName] = prop.name;
|
||||
m_info[InfoKey::PropertyType] = string_for_property_type(prop.type);
|
||||
m_info[InfoKey::OldPropertyType] = string_for_property_type(oldProp.type);
|
||||
m_info[InfoKey::PropertyObjectType] = prop.object_type;
|
||||
m_info[InfoKey::OldPropertyObjectType] = oldProp.object_type;
|
||||
set_what();
|
||||
}
|
||||
|
||||
void ObjectStoreException::set_what() {
|
||||
if (s_custom_what) {
|
||||
string custom = s_custom_what(*this);
|
||||
if (custom.length()) {
|
||||
m_what = custom;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (m_kind) {
|
||||
case Kind::RealmVersionGreaterThanSchemaVersion:
|
||||
m_what = "Provided schema version " + m_dict.at("old_version") + " is less than last set version " + m_dict.at("new_version") + ".";
|
||||
m_what = "Provided schema version " + m_info[InfoKey::OldVersion] +
|
||||
" is less than last set version " + m_info[InfoKey::NewVersion] + ".";
|
||||
break;
|
||||
case Kind::RealmPropertyTypeNotIndexable:
|
||||
m_what = "Can't index property '" + m_dict.at("object_type") + "." + m_dict.at("property_name") + "': " +
|
||||
"indexing properties of type '" + m_dict.at("property_type") + "' is currently not supported";
|
||||
m_what = "Can't index property '" + m_info[InfoKey::ObjectType] + "." + m_info[InfoKey::PropertyName] + "': " +
|
||||
"indexing properties of type '" + m_info[InfoKey::PropertyType] + "' is currently not supported";
|
||||
break;
|
||||
case Kind::RealmDuplicatePrimaryKeyValue:
|
||||
m_what = "Primary key property '" + m_dict["property_name"] + "' has duplicate values after migration.";
|
||||
m_what = "Primary key property '" + m_info[InfoKey::PropertyType] + "' has duplicate values after migration.";
|
||||
break;
|
||||
case Kind::ObjectSchemaMissingProperty:
|
||||
m_what = "Property '" + m_info[InfoKey::PropertyName] + "' is missing from latest object model.";
|
||||
break;
|
||||
case Kind::ObjectSchemaNewProperty:
|
||||
m_what = "Property '" + m_info[InfoKey::PropertyName] + "' has been added to latest object model.";
|
||||
break;
|
||||
case Kind::ObjectSchemaMismatchedTypes:
|
||||
m_what = "Property types for '" + m_info[InfoKey::PropertyName] + "' property do not match. " +
|
||||
"Old type '" + m_info[InfoKey::OldPropertyType] + "', new type '" + m_info[InfoKey::PropertyType] + "'";
|
||||
break;
|
||||
case Kind::ObjectSchemaMismatchedObjectTypes:
|
||||
m_what = "Target object type for property '" + m_info[InfoKey::PropertyName] + "' does not match. " +
|
||||
"Old type '" + m_info[InfoKey::OldPropertyObjectType] + "', new type '" + m_info[InfoKey::PropertyObjectType] + "'.";
|
||||
break;
|
||||
case Kind::ObjectSchemaMismatchedPrimaryKey:
|
||||
if (!m_info[InfoKey::PrimaryKey].length()) {
|
||||
m_what = "Property '" + m_info[InfoKey::OldPrimaryKey] + "' is no longer a primary key.";
|
||||
}
|
||||
else {
|
||||
m_what = "Property '" + m_info[InfoKey::PrimaryKey] + "' has been made a primary key.";
|
||||
}
|
||||
break;
|
||||
case Kind::ObjectStoreValidationFailure:
|
||||
m_what = "Migration is required for object type '" + info().at(InfoKey::ObjectType) + "' due to the following errors:";
|
||||
for (auto error : m_validation_errors) {
|
||||
m_what += string("\n- ") + error.what();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectStoreValidationException::ObjectStoreValidationException(std::vector<std::string> validation_errors, std::string object_type) :
|
||||
m_validation_errors(validation_errors), m_object_type(object_type) {
|
||||
m_what = "Migration is required for object type '" + m_object_type + "' due to the following errors:";
|
||||
for (auto error : m_validation_errors) {
|
||||
m_what += "\n- " + error;
|
||||
}
|
||||
ObjectStoreException::ObjectStoreException(vector<ObjectStoreException> validation_errors, const string &object_type) :
|
||||
m_validation_errors(validation_errors), m_kind(Kind::ObjectStoreValidationFailure), m_info({{InfoKey::ObjectType, object_type}}) {
|
||||
set_what();
|
||||
}
|
||||
|
||||
|
@ -24,42 +24,63 @@
|
||||
#include <string>
|
||||
|
||||
namespace realm {
|
||||
class Property;
|
||||
|
||||
class ObjectStoreException : public std::exception {
|
||||
public:
|
||||
enum class Kind {
|
||||
// thrown when calling update_realm_to_schema and the realm version is greater than the given version
|
||||
RealmVersionGreaterThanSchemaVersion, // old_version, new_version
|
||||
RealmPropertyTypeNotIndexable, // object_type, property_name, property_type
|
||||
RealmDuplicatePrimaryKeyValue, // object_type, property_name
|
||||
RealmVersionGreaterThanSchemaVersion, // OldVersion, NewVersion
|
||||
RealmPropertyTypeNotIndexable, // ObjectType, PropertyName, PropertyType
|
||||
RealmDuplicatePrimaryKeyValue, // ObjectType, PropertyName, PropertyType
|
||||
ObjectSchemaMissingProperty, // ObjectType, PropertyName, PropertyType
|
||||
ObjectSchemaNewProperty, // ObjectType, PropertyName, PropertyType
|
||||
ObjectSchemaMismatchedTypes, // ObjectType, PropertyName, PropertyType, OldPropertyType
|
||||
ObjectSchemaMismatchedObjectTypes, // ObjectType, PropertyName, PropertyType, ObjectType, OldObjectType
|
||||
ObjectSchemaMismatchedPrimaryKey, // ObjectType, PrimaryKey, OldPrimaryKey
|
||||
ObjectStoreValidationFailure, // ObjectType, vector<ObjectStoreException>
|
||||
};
|
||||
typedef std::map<std::string, std::string> Dict;
|
||||
|
||||
ObjectStoreException(Kind kind, Dict dict = Dict());
|
||||
enum class InfoKey {
|
||||
OldVersion,
|
||||
NewVersion,
|
||||
ObjectType,
|
||||
PropertyName,
|
||||
PropertyType,
|
||||
OldPropertyType,
|
||||
PropertyObjectType,
|
||||
OldPropertyObjectType,
|
||||
PrimaryKey,
|
||||
OldPrimaryKey,
|
||||
};
|
||||
typedef std::map<InfoKey, std::string> Info;
|
||||
|
||||
ObjectStoreException(Kind kind, Info info = Info());
|
||||
ObjectStoreException(Kind kind, const std::string &object_type, const Property &prop);
|
||||
ObjectStoreException(Kind kind, const std::string &object_type, const Property &prop, const Property &oldProp);
|
||||
|
||||
// ObjectStoreValidationFailure
|
||||
ObjectStoreException(std::vector<ObjectStoreException> validation_errors, const std::string &object_type);
|
||||
|
||||
ObjectStoreException::Kind kind() const { return m_kind; }
|
||||
const ObjectStoreException::Dict &dict() const { return m_dict; }
|
||||
const ObjectStoreException::Info &info() const { return m_info; }
|
||||
const std::vector<ObjectStoreException> &validation_errors() { return m_validation_errors; }
|
||||
|
||||
const char *what() const noexcept override { return m_what.c_str(); }
|
||||
|
||||
// implement CustomWhat to customize exception messages per platform/language
|
||||
typedef std::string (*CustomWhat)(ObjectStoreException &);
|
||||
static void set_custom_what(CustomWhat message_generator) { s_custom_what = message_generator; }
|
||||
|
||||
private:
|
||||
Kind m_kind;
|
||||
Dict m_dict;
|
||||
Info m_info;
|
||||
std::vector<ObjectStoreException> m_validation_errors;
|
||||
|
||||
std::string m_what;
|
||||
};
|
||||
void set_what();
|
||||
|
||||
class ObjectStoreValidationException : public std::exception {
|
||||
public:
|
||||
ObjectStoreValidationException(std::vector<std::string> validation_errors, std::string object_type);
|
||||
|
||||
const std::vector<std::string> &validation_errors() const { return m_validation_errors; }
|
||||
std::string object_type() const { return m_object_type; }
|
||||
const char *what() const noexcept override { return m_what.c_str(); }
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_validation_errors;
|
||||
std::string m_object_type;
|
||||
std::string m_what;
|
||||
static CustomWhat s_custom_what;
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user