Add the invalid value to the type error exception message

This commit is contained in:
Thomas Goyne 2017-09-14 16:01:59 -07:00
parent e564ad1de8
commit b8fd4fb861
3 changed files with 30 additions and 32 deletions

View File

@ -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;
} }
@ -121,7 +120,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;

View File

@ -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))));
} }

View File

@ -26,6 +26,7 @@
#include <vector> #include <vector>
#include <realm/binary_data.hpp> #include <realm/binary_data.hpp>
#include <realm/string_data.hpp>
#include <realm/util/to_string.hpp> #include <realm/util/to_string.hpp>
#if defined(__GNUC__) && !(defined(DEBUG) && DEBUG) #if defined(__GNUC__) && !(defined(DEBUG) && DEBUG)
@ -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); \
} }