support defaults

This commit is contained in:
Ari Lazier 2015-09-04 15:43:26 -07:00
parent 0e665e605e
commit 16be837817
7 changed files with 80 additions and 11 deletions

View File

@ -120,6 +120,16 @@ template<> JSValueRef RJSAccessor::dict_value_for_key(JSContextRef ctx, JSValueR
return ret; return ret;
} }
template<> bool RJSAccessor::has_default_value_for_property(JSContextRef ctx, const ObjectSchema &object_schema, const std::string &prop_name) {
ObjectDefaults &defaults = RJSDefaultsForClassName(object_schema.name);
return defaults.find(prop_name) != defaults.end();
}
template<> JSValueRef RJSAccessor::default_value_for_property(JSContextRef ctx, const ObjectSchema &object_schema, const std::string &prop_name) {
ObjectDefaults &defaults = RJSDefaultsForClassName(object_schema.name);
return defaults[prop_name];
}
template<> bool RJSAccessor::is_null(JSContextRef ctx, JSValueRef &val) { template<> bool RJSAccessor::is_null(JSContextRef ctx, JSValueRef &val) {
return JSValueIsUndefined(ctx, val) || JSValueIsNull(ctx, val); return JSValueIsUndefined(ctx, val) || JSValueIsNull(ctx, val);
} }

View File

@ -17,9 +17,11 @@
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
#import "RJSUtil.hpp" #import "RJSUtil.hpp"
#import <map>
namespace realm { namespace realm {
class Schema; class Schema;
using ObjectDefaults = std::map<std::string, JSValueRef>;
} }
JSClassRef RJSSchemaClass(); JSClassRef RJSSchemaClass();
@ -28,3 +30,4 @@ JSObjectRef RJSSchemaCreate(JSContextRef ctx, realm::Schema *schema);
realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject); realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject);
JSValueRef RJSPrototypeForClassName(const std::string &className); JSValueRef RJSPrototypeForClassName(const std::string &className);
realm::ObjectDefaults &RJSDefaultsForClassName(const std::string &className);

View File

@ -45,6 +45,11 @@ JSObjectRef RJSSchemaCreate(JSContextRef ctx, Schema &schema) {
return RJSWrapObject(ctx, RJSSchemaClass(), wrapper); return RJSWrapObject(ctx, RJSSchemaClass(), wrapper);
} }
static std::map<std::string, ObjectDefaults> s_defaults;
ObjectDefaults &RJSDefaultsForClassName(const std::string &className) {
return s_defaults[className];
}
static std::map<std::string, JSValueRef> s_prototypes; static std::map<std::string, JSValueRef> s_prototypes;
JSValueRef RJSPrototypeForClassName(const std::string &className) { JSValueRef RJSPrototypeForClassName(const std::string &className) {
return s_prototypes[className]; return s_prototypes[className];
@ -117,15 +122,24 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
JSObjectRef propertiesObject = RJSValidatedObjectProperty(ctx, objectSchemaObject, propertiesString, "ObjectSchema object must have a 'properties' array."); JSObjectRef propertiesObject = RJSValidatedObjectProperty(ctx, objectSchemaObject, propertiesString, "ObjectSchema object must have a 'properties' array.");
ObjectSchema objectSchema; ObjectSchema objectSchema;
static JSStringRef nameString = JSStringCreateWithUTF8CString("name"); ObjectDefaults defaults;
static JSStringRef nameString = JSStringCreateWithUTF8CString("name");
objectSchema.name = RJSValidatedStringProperty(ctx, objectSchemaObject, nameString); objectSchema.name = RJSValidatedStringProperty(ctx, objectSchemaObject, nameString);
size_t numProperties = RJSValidatedArrayLength(ctx, propertiesObject); size_t numProperties = RJSValidatedArrayLength(ctx, propertiesObject);
for (unsigned int p = 0; p < numProperties; p++) { for (unsigned int p = 0; p < numProperties; p++) {
JSObjectRef property = RJSValidatedObjectAtIndex(ctx, propertiesObject, p); JSObjectRef property = RJSValidatedObjectAtIndex(ctx, propertiesObject, p);
objectSchema.properties.emplace_back(RJSParseProperty(ctx, property)); objectSchema.properties.emplace_back(RJSParseProperty(ctx, property));
static JSStringRef defaultString = JSStringCreateWithUTF8CString("default");
JSValueRef defaultValue = JSObjectGetProperty(ctx, property, defaultString, NULL);
if (!JSValueIsUndefined(ctx, defaultValue)) {
JSValueProtect(ctx, defaultValue);
defaults.emplace(objectSchema.properties.back().name, defaultValue);
}
} }
s_defaults.emplace(objectSchema.name, std::move(defaults));
static JSStringRef primaryString = JSStringCreateWithUTF8CString("primaryKey"); static JSStringRef primaryString = JSStringCreateWithUTF8CString("primaryKey");
JSValueRef primaryValue = RJSValidatedPropertyValue(ctx, objectSchemaObject, primaryString); JSValueRef primaryValue = RJSValidatedPropertyValue(ctx, objectSchemaObject, primaryString);
@ -141,7 +155,7 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
// store prototype // store prototype
if (prototypeObject) { if (prototypeObject) {
JSValueProtect(ctx, prototypeObject); JSValueProtect(ctx, prototypeObject);
s_prototypes[objectSchema.name] = prototypeObject; s_prototypes[objectSchema.name] = std::move(prototypeObject);
} }
return objectSchema; return objectSchema;
@ -158,3 +172,4 @@ realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject) {
return schema; return schema;
} }

View File

@ -32,6 +32,9 @@ namespace realm {
static bool dict_has_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name); static bool dict_has_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name);
static ValueType dict_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name); static ValueType dict_value_for_key(ContextType ctx, ValueType dict, const std::string &prop_name);
static bool has_default_value_for_property(ContextType ctx, const ObjectSchema &object_schema, const std::string &prop_name);
static ValueType default_value_for_property(ContextType ctx, const ObjectSchema &object_schema, const std::string &prop_name);
static bool to_bool(ContextType ctx, ValueType &val); static bool to_bool(ContextType ctx, ValueType &val);
static long long to_long(ContextType ctx, ValueType &val); static long long to_long(ContextType ctx, ValueType &val);
static float to_float(ContextType ctx, ValueType &val); static float to_float(ContextType ctx, ValueType &val);
@ -184,14 +187,18 @@ namespace realm {
// populate // populate
Object object(realm, object_schema, table->get(row_index)); Object object(realm, object_schema, table->get(row_index));
for (Property &prop : object_schema.properties) { for (Property &prop : object_schema.properties) {
if (Accessor::dict_has_value_for_key(ctx, value, prop.name)) { if (created || !prop.is_primary) {
if (created || !prop.is_primary) { if (Accessor::dict_has_value_for_key(ctx, value, prop.name)) {
ValueType prop_value = Accessor::dict_value_for_key(ctx, value, prop.name); object.set_property_value_impl(ctx, prop, Accessor::dict_value_for_key(ctx, value, prop.name), try_update);
object.set_property_value_impl(ctx, prop, prop_value, try_update); }
else if (created) {
if (Accessor::has_default_value_for_property(ctx, object_schema, prop.name)) {
object.set_property_value_impl(ctx, prop, Accessor::default_value_for_property(ctx, object_schema, prop.name), try_update);
}
else {
throw std::runtime_error("Missing property value for property " + prop.name);
}
} }
}
else if (created) {
throw std::runtime_error("Missing property value for property " + prop.name);
} }
} }
return object; return object;

View File

@ -86,7 +86,7 @@ var ObjectTests = {
var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]}); var realm = new Realm({schema: [LinkTypesObjectSchema, TestObjectSchema]});
var obj = null; var obj = null;
realm.write(function() { realm.write(function() {
obj = realm.create('LinkTypesObject', [[1], undefined, [[3]]]); obj = realm.create('LinkTypesObject', [[1], null, [[3]]]);
}); });
TestCase.assertEqual(realm.objects('TestObject').length, 2); TestCase.assertEqual(realm.objects('TestObject').length, 2);
@ -99,7 +99,7 @@ var ObjectTests = {
TestCase.assertEqual(realm.objects('TestObject').length, 2); TestCase.assertEqual(realm.objects('TestObject').length, 2);
realm.write(function() { realm.write(function() {
obj.objectCol = undefined; obj.objectCol = null;
obj.objectCol1 = null; obj.objectCol1 = null;
}); });
TestCase.assertEqual(obj.objectCol, null); TestCase.assertEqual(obj.objectCol, null);

View File

@ -142,6 +142,24 @@ var RealmTests = {
}); });
}, },
testRealmCreateWithDefaults: function() {
var realm = new Realm({schema: [DefaultValuesObjectSchema, TestObjectSchema]});
realm.write(function() {
var obj = realm.create('DefaultValuesObject', {});
TestCase.assertEqual(obj.boolCol, DefaultValuesObjectSchema.properties[0].default);
TestCase.assertEqual(obj.intCol, DefaultValuesObjectSchema.properties[1].default);
TestCase.assertEqualWithTolerance(obj.floatCol, DefaultValuesObjectSchema.properties[2].default, 0.000001);
TestCase.assertEqual(obj.doubleCol, DefaultValuesObjectSchema.properties[3].default);
TestCase.assertEqual(obj.stringCol, DefaultValuesObjectSchema.properties[4].default);
TestCase.assertEqual(obj.dateCol.getTime(), DefaultValuesObjectSchema.properties[5].default.getTime());
TestCase.assertEqual(obj.dataCol, DefaultValuesObjectSchema.properties[6].default);
TestCase.assertEqual(obj.objectCol.doubleCol, DefaultValuesObjectSchema.properties[7].default[0]);
TestCase.assertEqual(obj.nullObjectCol, null);
TestCase.assertEqual(obj.arrayCol.length, DefaultValuesObjectSchema.properties[9].default.length);
TestCase.assertEqual(obj.arrayCol[0].doubleCol, DefaultValuesObjectSchema.properties[9].default[0][0]);
});
},
testRealmDelete: function() { testRealmDelete: function() {
var realm = new Realm({schema: [TestObjectSchema]}); var realm = new Realm({schema: [TestObjectSchema]});
realm.write(function() { realm.write(function() {

View File

@ -85,3 +85,19 @@ var AllTypesObjectSchema = {
] ]
}; };
var DefaultValuesObjectSchema = {
name: 'DefaultValuesObject',
properties: [
{name: 'boolCol', type: RealmType.Bool, default: true},
{name: 'intCol', type: RealmType.Int, default: -1},
{name: 'floatCol', type: RealmType.Float, default: -1.1},
{name: 'doubleCol', type: RealmType.Double, default: -1.11},
{name: 'stringCol', type: RealmType.String, default: 'defaultString'},
{name: 'dateCol', type: RealmType.Date, default: new Date(1.111)},
{name: 'dataCol', type: RealmType.Data, default: 'defaultData'},
{name: 'objectCol', type: 'TestObject', default: [1]},
{name: 'nullObjectCol', type: 'TestObject', default: null},
{name: 'arrayCol', type: RealmType.Array, objectType: 'TestObject', default: [[2]]},
]
};