primary keys and upsert

This commit is contained in:
Ari Lazier 2015-09-03 14:05:56 -07:00
parent df05636e7a
commit ee87cbc17a
7 changed files with 72 additions and 3 deletions

View File

@ -221,8 +221,8 @@
0270BC7B1B7D020100010E03 /* RealmJSTests.mm */, 0270BC7B1B7D020100010E03 /* RealmJSTests.mm */,
0270BC7C1B7D020100010E03 /* RealmTests.js */, 0270BC7C1B7D020100010E03 /* RealmTests.js */,
0270BC7D1B7D020100010E03 /* ResultsTests.js */, 0270BC7D1B7D020100010E03 /* ResultsTests.js */,
0270BC7E1B7D020100010E03 /* TestCase.js */,
0270BC7F1B7D020100010E03 /* TestObjects.js */, 0270BC7F1B7D020100010E03 /* TestObjects.js */,
0270BC7E1B7D020100010E03 /* TestCase.js */,
); );
path = RealmJSTests; path = RealmJSTests;
sourceTree = "<group>"; sourceTree = "<group>";

View File

@ -221,7 +221,12 @@ JSValueRef RealmCreateObject(JSContextRef ctx, JSObjectRef function, JSObjectRef
object = RJSDictForPropertyArray(ctx, object_schema->second, object); object = RJSDictForPropertyArray(ctx, object_schema->second, object);
} }
return RJSObjectCreate(ctx, Object::create<JSValueRef>(ctx, sharedRealm, object_schema->second, object, false)); bool update = false;
if (argumentCount == 3) {
update = RJSValidatedValueToBool(ctx, arguments[2]);
}
return RJSObjectCreate(ctx, Object::create<JSValueRef>(ctx, sharedRealm, object_schema->second, object, update));
} }
catch (std::exception &exp) { catch (std::exception &exp) {
if (jsException) { if (jsException) {

View File

@ -118,6 +118,7 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
ObjectSchema objectSchema; ObjectSchema objectSchema;
static JSStringRef nameString = JSStringCreateWithUTF8CString("name"); 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);
@ -126,6 +127,17 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
objectSchema.properties.emplace_back(RJSParseProperty(ctx, property)); objectSchema.properties.emplace_back(RJSParseProperty(ctx, property));
} }
static JSStringRef primaryString = JSStringCreateWithUTF8CString("primaryKey");
JSValueRef primaryValue = RJSValidatedPropertyValue(ctx, objectSchemaObject, primaryString);
if (!JSValueIsUndefined(ctx, primaryValue)) {
objectSchema.primary_key = RJSValidatedStringForValue(ctx, primaryValue);
Property *property = objectSchema.primary_key_property();
if (!property) {
throw std::runtime_error("Missing primary key property '" + objectSchema.primary_key + "'");
}
property->is_primary = true;
}
// store prototype // store prototype
if (prototypeObject) { if (prototypeObject) {
JSValueProtect(ctx, prototypeObject); JSValueProtect(ctx, prototypeObject);

View File

@ -112,6 +112,18 @@ static inline double RJSValidatedValueToNumber(JSContextRef ctx, JSValueRef valu
return number; return number;
} }
static inline bool RJSValidatedValueToBool(JSContextRef ctx, JSValueRef value) {
JSValueRef exception = NULL;
if (!JSValueIsBoolean(ctx, value)) {
throw std::runtime_error("Value is not a boolean");
}
bool b = JSValueToNumber(ctx, value, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
return b;
}
static inline JSValueRef RJSValidatedPropertyValue(JSContextRef ctx, JSObjectRef object, JSStringRef property) { static inline JSValueRef RJSValidatedPropertyValue(JSContextRef ctx, JSObjectRef object, JSStringRef property) {
JSValueRef exception = NULL; JSValueRef exception = NULL;
JSValueRef propertyValue = JSObjectGetProperty(ctx, object, property, &exception); JSValueRef propertyValue = JSObjectGetProperty(ctx, object, property, &exception);

View File

@ -158,7 +158,7 @@ namespace realm {
size_t row_index = realm::not_found; size_t row_index = realm::not_found;
realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name); realm::TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name);
Property *primary_prop = object_schema.primary_key_property(); Property *primary_prop = object_schema.primary_key_property();
if (try_update && primary_prop) { if (primary_prop) {
// search for existing object based on primary key type // search for existing object based on primary key type
ValueType primary_value = Accessor::dict_value_for_key(ctx, value, object_schema.primary_key); ValueType primary_value = Accessor::dict_value_for_key(ctx, value, object_schema.primary_key);
if (primary_prop->type == PropertyTypeString) { if (primary_prop->type == PropertyTypeString) {
@ -167,6 +167,10 @@ namespace realm {
else { else {
row_index = table->find_first_int(primary_prop->table_column, Accessor::to_long(ctx, primary_value)); row_index = table->find_first_int(primary_prop->table_column, Accessor::to_long(ctx, primary_value));
} }
if (!try_update && row_index != realm::not_found) {
throw std::runtime_error("Attempting to create an object of type '" + object_schema.name + "' with an exising primary key value.");
}
} }
// if no existing, create row // if no existing, create row

View File

@ -82,6 +82,23 @@ var RealmTests = {
TestCase.assertEqual(objects.length, 2, 'wrong object count'); TestCase.assertEqual(objects.length, 2, 'wrong object count');
TestCase.assertEqual(objects[0].doubleCol, 1, 'wrong object property value'); TestCase.assertEqual(objects[0].doubleCol, 1, 'wrong object property value');
TestCase.assertEqual(objects[1].doubleCol, 2, 'wrong object property value'); TestCase.assertEqual(objects[1].doubleCol, 2, 'wrong object property value');
// test primary object
realm = new Realm({path: TestUtil.realmPathForFile('intPrimary.realm'), schema: [IntPrimaryObjectSchema, StringPrimaryObjectSchema]});
realm.write(function() {
var obj0 = realm.create('IntPrimaryObject', [0, 'val0']);
TestCase.assertThrows(function() {
realm.create('IntPrimaryObject', [0, 'val0']);
});
realm.create('IntPrimaryObject', [1, 'val1'], true);
var objects = realm.objects('IntPrimaryObject');
TestCase.assertEqual(objects.length, 2);
realm.create('IntPrimaryObject', [0, 'newVal0'], true);
TestCase.assertEqual(obj0.valueCol, 'newVal0');
TestCase.assertEqual(objects.length, 2);
});
}, },
testRealmDelete: function() { testRealmDelete: function() {
@ -167,3 +184,4 @@ var RealmTests = {
TestCase.assertEqual(notificationCount, 1); TestCase.assertEqual(notificationCount, 1);
}, },
}; };

View File

@ -58,3 +58,21 @@ var LinkTypesObjectSchema = {
{name: 'arrayCol', type: RealmType.Array, objectType: 'TestObject'}, {name: 'arrayCol', type: RealmType.Array, objectType: 'TestObject'},
] ]
}; };
var IntPrimaryObjectSchema = {
name: 'IntPrimaryObject',
primaryKey: 'primaryCol',
properties: [
{name: 'primaryCol', type: RealmType.Int},
{name: 'valueCol', type: RealmType.String},
]
};
var StringPrimaryObjectSchema = {
name: 'StringPrimaryObject',
primaryKey: 'primaryCol',
properties: [
{name: 'primaryCol', type: RealmType.String},
{name: 'valueCol', type: RealmType.String},
]
};