Add the invalid value to the type error exception message
This commit is contained in:
parent
944ef57b59
commit
cb9a3c9f76
|
@ -22,8 +22,6 @@
|
||||||
#include "js_realm_object.hpp"
|
#include "js_realm_object.hpp"
|
||||||
#include "js_schema.hpp"
|
#include "js_schema.hpp"
|
||||||
|
|
||||||
#include "util/format.hpp"
|
|
||||||
|
|
||||||
namespace realm {
|
namespace realm {
|
||||||
class List;
|
class List;
|
||||||
class Object;
|
class Object;
|
||||||
|
@ -65,8 +63,9 @@ public:
|
||||||
ValueType value = Object::get_property(m_ctx, object, prop_name);
|
ValueType value = Object::get_property(m_ctx, object, prop_name);
|
||||||
const auto& prop = m_object_schema.persisted_properties[prop_index];
|
const auto& prop = m_object_schema.persisted_properties[prop_index];
|
||||||
if (!Value::is_valid_for_property(m_ctx, value, prop)) {
|
if (!Value::is_valid_for_property(m_ctx, value, prop)) {
|
||||||
throw TypeErrorException(util::format("%1.%2", m_object_schema.name, prop.name),
|
throw TypeErrorException(m_object_schema.name, prop.name,
|
||||||
js_type_name_for_property_type(prop.type));
|
js_type_name_for_property_type(prop.type),
|
||||||
|
print(value));
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +128,7 @@ public:
|
||||||
void will_change(realm::Object&, realm::Property const&) { }
|
void will_change(realm::Object&, realm::Property const&) { }
|
||||||
void did_change() { }
|
void did_change() { }
|
||||||
|
|
||||||
std::string print(ValueType const&) { return "not implemented"; }
|
std::string print(ValueType const& v) { return Value::to_string(m_ctx, v); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ContextType m_ctx;
|
ContextType m_ctx;
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct RealmObjectClass : ClassDefinition<T, realm::Object> {
|
||||||
static void get_property(ContextType, ObjectType, const String &, ReturnValue &);
|
static void get_property(ContextType, ObjectType, const String &, ReturnValue &);
|
||||||
static bool set_property(ContextType, ObjectType, const String &, ValueType);
|
static bool set_property(ContextType, ObjectType, const String &, ValueType);
|
||||||
static std::vector<String> get_property_names(ContextType, ObjectType);
|
static std::vector<String> get_property_names(ContextType, ObjectType);
|
||||||
|
|
||||||
static void is_valid(ContextType, FunctionType, ObjectType, size_t, const ValueType [], ReturnValue &);
|
static void is_valid(ContextType, FunctionType, ObjectType, size_t, const ValueType [], ReturnValue &);
|
||||||
static void get_object_schema(ContextType, FunctionType, ObjectType, size_t, const ValueType [], ReturnValue &);
|
static void get_object_schema(ContextType, FunctionType, ObjectType, size_t, const ValueType [], ReturnValue &);
|
||||||
static void linking_objects(ContextType, FunctionType, ObjectType, size_t, const ValueType [], ReturnValue &);
|
static void linking_objects(ContextType, FunctionType, ObjectType, size_t, const ValueType [], ReturnValue &);
|
||||||
|
@ -73,13 +73,13 @@ template<typename T>
|
||||||
void RealmObjectClass<T>::is_valid(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
|
void RealmObjectClass<T>::is_valid(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
|
||||||
return_value.set(get_internal<T, RealmObjectClass<T>>(this_object)->is_valid());
|
return_value.set(get_internal<T, RealmObjectClass<T>>(this_object)->is_valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void RealmObjectClass<T>::get_object_schema(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
|
void RealmObjectClass<T>::get_object_schema(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
|
||||||
auto object = get_internal<T, RealmObjectClass<T>>(this_object);
|
auto object = get_internal<T, RealmObjectClass<T>>(this_object);
|
||||||
return_value.set(Schema<T>::object_for_object_schema(ctx, object->get_object_schema()));
|
return_value.set(Schema<T>::object_for_object_schema(ctx, object->get_object_schema()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
typename T::Object RealmObjectClass<T>::create_instance(ContextType ctx, realm::Object realm_object) {
|
typename T::Object RealmObjectClass<T>::create_instance(ContextType ctx, realm::Object realm_object) {
|
||||||
static String prototype_string = "prototype";
|
static String prototype_string = "prototype";
|
||||||
|
@ -100,7 +100,7 @@ typename T::Object RealmObjectClass<T>::create_instance(ContextType ctx, realm::
|
||||||
if (result != object && !Value::is_null(ctx, result) && !Value::is_undefined(ctx, result)) {
|
if (result != object && !Value::is_null(ctx, result) && !Value::is_undefined(ctx, result)) {
|
||||||
throw std::runtime_error("Realm object constructor must not return another value");
|
throw std::runtime_error("Realm object constructor must not return another value");
|
||||||
}
|
}
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,12 +127,13 @@ bool RealmObjectClass<T>::set_property(ContextType ctx, ObjectType object, const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NativeAccessor<T> accessor(ctx, realm_object->realm(), realm_object->get_object_schema());
|
||||||
if (!Value::is_valid_for_property(ctx, value, *prop)) {
|
if (!Value::is_valid_for_property(ctx, value, *prop)) {
|
||||||
throw TypeErrorException(util::format("%1.%2", realm_object->get_object_schema().name, property_name),
|
throw TypeErrorException(realm_object->get_object_schema().name, property_name,
|
||||||
js_type_name_for_property_type(prop->type));
|
js_type_name_for_property_type(prop->type),
|
||||||
|
accessor.print(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeAccessor<T> accessor(ctx, realm_object->realm(), realm_object->get_object_schema());
|
|
||||||
realm_object->set_property_value(accessor, property_name, value, true);
|
realm_object->set_property_value(accessor, property_name, value, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -162,29 +163,29 @@ std::vector<String<T>> RealmObjectClass<T>::get_property_names(ContextType ctx,
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void realm::js::RealmObjectClass<T>::linking_objects(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
|
void realm::js::RealmObjectClass<T>::linking_objects(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
|
||||||
validate_argument_count(argc, 2);
|
validate_argument_count(argc, 2);
|
||||||
|
|
||||||
std::string object_type = Value::validated_to_string(ctx, arguments[0], "objectType");
|
std::string object_type = Value::validated_to_string(ctx, arguments[0], "objectType");
|
||||||
std::string property_name = Value::validated_to_string(ctx, arguments[1], "property");
|
std::string property_name = Value::validated_to_string(ctx, arguments[1], "property");
|
||||||
|
|
||||||
auto object = get_internal<T, RealmObjectClass<T>>(this_object);
|
auto object = get_internal<T, RealmObjectClass<T>>(this_object);
|
||||||
|
|
||||||
auto target_object_schema = object->realm()->schema().find(object_type);
|
auto target_object_schema = object->realm()->schema().find(object_type);
|
||||||
if (target_object_schema == object->realm()->schema().end()) {
|
if (target_object_schema == object->realm()->schema().end()) {
|
||||||
throw std::logic_error(util::format("Could not find schema for type '%1'", object_type));
|
throw std::logic_error(util::format("Could not find schema for type '%1'", object_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto link_property = target_object_schema->property_for_name(property_name);
|
auto link_property = target_object_schema->property_for_name(property_name);
|
||||||
if (!link_property) {
|
if (!link_property) {
|
||||||
throw std::logic_error(util::format("Type '%1' does not contain property '%2'", object_type, property_name));
|
throw std::logic_error(util::format("Type '%1' does not contain property '%2'", object_type, property_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link_property->object_type != object->get_object_schema().name) {
|
if (link_property->object_type != object->get_object_schema().name) {
|
||||||
throw std::logic_error(util::format("'%1.%2' is not a relationship to '%3'", object_type, property_name, object->get_object_schema().name));
|
throw std::logic_error(util::format("'%1.%2' is not a relationship to '%3'", object_type, property_name, object->get_object_schema().name));
|
||||||
}
|
}
|
||||||
|
|
||||||
realm::TableRef table = ObjectStore::table_for_object_type(object->realm()->read_group(), target_object_schema->name);
|
realm::TableRef table = ObjectStore::table_for_object_type(object->realm()->read_group(), target_object_schema->name);
|
||||||
auto row = object->row();
|
auto row = object->row();
|
||||||
auto tv = row.get_table()->get_backlink_view(row.get_index(), table.get(), link_property->table_column);
|
auto tv = row.get_table()->get_backlink_view(row.get_index(), table.get(), link_property->table_column);
|
||||||
|
|
||||||
return_value.set(ResultsClass<T>::create_instance(ctx, realm::Results(object->realm(), std::move(tv))));
|
return_value.set(ResultsClass<T>::create_instance(ctx, realm::Results(object->realm(), std::move(tv))));
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "execution_context_id.hpp"
|
#include "execution_context_id.hpp"
|
||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
|
#include "util/format.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -80,18 +81,16 @@ struct Context {
|
||||||
|
|
||||||
class TypeErrorException : public std::invalid_argument {
|
class TypeErrorException : public std::invalid_argument {
|
||||||
public:
|
public:
|
||||||
std::string const& prefix() const { return m_prefix; }
|
TypeErrorException(StringData object_type, StringData property,
|
||||||
std::string const& type() const { return m_type; }
|
std::string const& type, std::string const& value)
|
||||||
|
: std::invalid_argument(util::format("%1.%2 must be of type '%3', got (%4)",
|
||||||
|
object_type, property, type, value))
|
||||||
|
{}
|
||||||
|
|
||||||
TypeErrorException(std::string prefix, std::string type) :
|
TypeErrorException(const char *name, std::string const& type, std::string const& value)
|
||||||
std::invalid_argument(prefix + " must be of type: " + type),
|
: std::invalid_argument(util::format("%1 must be of type '%2', got (%3)",
|
||||||
m_prefix(std::move(prefix)),
|
name ? name : "JS value", type, value))
|
||||||
m_type(std::move(type))
|
{}
|
||||||
{}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_prefix;
|
|
||||||
std::string m_type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -138,8 +137,7 @@ struct Value {
|
||||||
#define VALIDATED(return_t, type) \
|
#define VALIDATED(return_t, type) \
|
||||||
static return_t validated_to_##type(ContextType ctx, const ValueType &value, const char *name = nullptr) { \
|
static return_t validated_to_##type(ContextType ctx, const ValueType &value, const char *name = nullptr) { \
|
||||||
if (!is_##type(ctx, value)) { \
|
if (!is_##type(ctx, value)) { \
|
||||||
std::string prefix = name ? std::string("'") + name + "'" : "JS value"; \
|
throw TypeErrorException(name, #type, to_string(ctx, value)); \
|
||||||
throw TypeErrorException(prefix, #type); \
|
|
||||||
} \
|
} \
|
||||||
return to_##type(ctx, value); \
|
return to_##type(ctx, value); \
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ module.exports = {
|
||||||
TestCase.assertThrows(function() {
|
TestCase.assertThrows(function() {
|
||||||
new Realm({schemaVersion: 1, schema: []});
|
new Realm({schemaVersion: 1, schema: []});
|
||||||
}, "Realm already opened at a different schema version");
|
}, "Realm already opened at a different schema version");
|
||||||
|
|
||||||
TestCase.assertEqual(new Realm().schemaVersion, 0);
|
TestCase.assertEqual(new Realm().schemaVersion, 0);
|
||||||
TestCase.assertEqual(new Realm({schemaVersion: 0}).schemaVersion, 0);
|
TestCase.assertEqual(new Realm({schemaVersion: 0}).schemaVersion, 0);
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}]});
|
}]});
|
||||||
}, "Property 'InvalidObject.integer' declared as origin of linking objects property 'InvalidObject.linkingObjects' is not a link")
|
}, "Property 'InvalidObject.integer' declared as origin of linking objects property 'InvalidObject.linkingObjects' is not a link")
|
||||||
|
|
||||||
// linkingObjects property where the source property links elsewhere
|
// linkingObjects property where the source property links elsewhere
|
||||||
TestCase.assertThrows(function() {
|
TestCase.assertThrows(function() {
|
||||||
new Realm({schema: [{
|
new Realm({schema: [{
|
||||||
|
@ -204,7 +204,7 @@ module.exports = {
|
||||||
|
|
||||||
testRealmSchemaVersion: function() {
|
testRealmSchemaVersion: function() {
|
||||||
TestCase.assertEqual(Realm.schemaVersion(Realm.defaultPath), -1);
|
TestCase.assertEqual(Realm.schemaVersion(Realm.defaultPath), -1);
|
||||||
|
|
||||||
var realm = new Realm({schema: []});
|
var realm = new Realm({schema: []});
|
||||||
TestCase.assertEqual(realm.schemaVersion, 0);
|
TestCase.assertEqual(realm.schemaVersion, 0);
|
||||||
TestCase.assertEqual(Realm.schemaVersion(Realm.defaultPath), 0);
|
TestCase.assertEqual(Realm.schemaVersion(Realm.defaultPath), 0);
|
||||||
|
@ -216,7 +216,7 @@ module.exports = {
|
||||||
|
|
||||||
testRealmWrite: function() {
|
testRealmWrite: function() {
|
||||||
var realm = new Realm({schema: [schemas.IntPrimary, schemas.AllTypes, schemas.TestObject, schemas.LinkToAllTypes]});
|
var realm = new Realm({schema: [schemas.IntPrimary, schemas.AllTypes, schemas.TestObject, schemas.LinkToAllTypes]});
|
||||||
|
|
||||||
// exceptions should be propogated
|
// exceptions should be propogated
|
||||||
TestCase.assertThrows(function() {
|
TestCase.assertThrows(function() {
|
||||||
realm.write(function() {
|
realm.write(function() {
|
||||||
|
@ -301,7 +301,7 @@ module.exports = {
|
||||||
links = realm.create('LinkTypesObject', {});
|
links = realm.create('LinkTypesObject', {});
|
||||||
});
|
});
|
||||||
for (var name in schemas.NullableBasicTypes.properties) {
|
for (var name in schemas.NullableBasicTypes.properties) {
|
||||||
TestCase.assertEqual(basic[name], null);
|
TestCase.assertEqual(basic[name], null);
|
||||||
}
|
}
|
||||||
TestCase.assertEqual(links.objectCol, null);
|
TestCase.assertEqual(links.objectCol, null);
|
||||||
TestCase.assertEqual(links.arrayCol.length, 0);
|
TestCase.assertEqual(links.arrayCol.length, 0);
|
||||||
|
@ -825,9 +825,9 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
testSchema: function() {
|
testSchema: function() {
|
||||||
var originalSchema = [schemas.TestObject, schemas.BasicTypes, schemas.NullableBasicTypes, schemas.IndexedTypes, schemas.IntPrimary,
|
var originalSchema = [schemas.TestObject, schemas.BasicTypes, schemas.NullableBasicTypes, schemas.IndexedTypes, schemas.IntPrimary,
|
||||||
schemas.PersonObject, schemas.LinkTypes, schemas.LinkingObjectsObject];
|
schemas.PersonObject, schemas.LinkTypes, schemas.LinkingObjectsObject];
|
||||||
|
|
||||||
var schemaMap = {};
|
var schemaMap = {};
|
||||||
originalSchema.forEach(function(objectSchema) {
|
originalSchema.forEach(function(objectSchema) {
|
||||||
if (objectSchema.schema) { // for PersonObject
|
if (objectSchema.schema) { // for PersonObject
|
||||||
|
@ -857,11 +857,11 @@ module.exports = {
|
||||||
var prop1 = returned.properties[propName];
|
var prop1 = returned.properties[propName];
|
||||||
var prop2 = original.properties[propName];
|
var prop2 = original.properties[propName];
|
||||||
if (prop1.type == 'object') {
|
if (prop1.type == 'object') {
|
||||||
TestCase.assertEqual(prop1.objectType, isString(prop2) ? prop2 : prop2.objectType);
|
TestCase.assertEqual(prop1.objectType, isString(prop2) ? prop2 : prop2.objectType);
|
||||||
TestCase.assertEqual(prop1.optional, true);
|
TestCase.assertEqual(prop1.optional, true);
|
||||||
}
|
}
|
||||||
else if (prop1.type == 'list') {
|
else if (prop1.type == 'list') {
|
||||||
TestCase.assertEqual(prop1.objectType, prop2.objectType);
|
TestCase.assertEqual(prop1.objectType, prop2.objectType);
|
||||||
TestCase.assertEqual(prop1.optional, undefined);
|
TestCase.assertEqual(prop1.optional, undefined);
|
||||||
}
|
}
|
||||||
else if (prop1.type == 'linking objects') {
|
else if (prop1.type == 'linking objects') {
|
||||||
|
@ -870,7 +870,7 @@ module.exports = {
|
||||||
TestCase.assertEqual(prop1.optional, undefined);
|
TestCase.assertEqual(prop1.optional, undefined);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TestCase.assertEqual(prop1.type, isString(prop2) ? prop2 : prop2.type);
|
TestCase.assertEqual(prop1.type, isString(prop2) ? prop2 : prop2.type);
|
||||||
TestCase.assertEqual(prop1.optional, prop2.optional || undefined);
|
TestCase.assertEqual(prop1.optional, prop2.optional || undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,13 +904,13 @@ module.exports = {
|
||||||
|
|
||||||
testErrorMessageFromInvalidWrite: function() {
|
testErrorMessageFromInvalidWrite: function() {
|
||||||
var realm = new Realm({schema: [schemas.PersonObject]});
|
var realm = new Realm({schema: [schemas.PersonObject]});
|
||||||
|
|
||||||
TestCase.assertThrowsException(function() {
|
TestCase.assertThrowsException(function() {
|
||||||
realm.write(function () {
|
realm.write(function () {
|
||||||
var p1 = realm.create('PersonObject', { name: 'Ari', age: 10 });
|
var p1 = realm.create('PersonObject', { name: 'Ari', age: 10 });
|
||||||
p1.age = "Ten";
|
p1.age = "Ten";
|
||||||
});
|
});
|
||||||
}, new Error("PersonObject.age must be of type: number"));
|
}, new Error("PersonObject.age must be of type 'number', got (Ten)"));
|
||||||
},
|
},
|
||||||
|
|
||||||
testErrorMessageFromInvalidCreate: function() {
|
testErrorMessageFromInvalidCreate: function() {
|
||||||
|
@ -920,7 +920,7 @@ module.exports = {
|
||||||
realm.write(function () {
|
realm.write(function () {
|
||||||
var p1 = realm.create('PersonObject', { name: 'Ari', age: 'Ten' });
|
var p1 = realm.create('PersonObject', { name: 'Ari', age: 'Ten' });
|
||||||
});
|
});
|
||||||
}, new Error("PersonObject.age must be of type: number"));
|
}, new Error("PersonObject.age must be of type 'number', got (Ten)"));
|
||||||
},
|
},
|
||||||
|
|
||||||
testValidTypesForListProperties: function() {
|
testValidTypesForListProperties: function() {
|
||||||
|
|
Loading…
Reference in New Issue