Merge pull request #1903 from realm/tg/setlink

Add object._setLink()
This commit is contained in:
Thomas Goyne 2018-07-03 11:08:02 -07:00 committed by GitHub
commit 7dd3951bef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 131 additions and 0 deletions

View File

@ -56,6 +56,7 @@ struct RealmObjectClass : ClassDefinition<T, realm::Object> {
static void linking_objects_count(ContextType, FunctionType, ObjectType, size_t, const ValueType [], ReturnValue &);
static void get_object_id(ContextType, ObjectType, Arguments, ReturnValue &);
static void is_same_object(ContextType, ObjectType, Arguments, ReturnValue &);
static void set_link(ContextType, ObjectType, Arguments, ReturnValue &);
const std::string name = "RealmObject";
@ -72,6 +73,7 @@ struct RealmObjectClass : ClassDefinition<T, realm::Object> {
{"linkingObjectsCount", wrap<linking_objects_count>},
{"_objectId", wrap<get_object_id>},
{"_isSameObject", wrap<is_same_object>},
{"_setLink", wrap<set_link>},
};
};
@ -140,6 +142,53 @@ bool RealmObjectClass<T>::set_property(ContextType ctx, ObjectType object, const
return true;
}
template<typename T>
void RealmObjectClass<T>::set_link(ContextType ctx, ObjectType object, Arguments args, ReturnValue& return_value) {
args.validate_count(2);
auto realm_object = get_internal<T, RealmObjectClass<T>>(object);
realm_object->realm()->verify_in_write();
NativeAccessor<T> accessor(ctx, realm_object->realm(), realm_object->get_object_schema());
std::string property_name = Value::validated_to_string(ctx, args[0], "propertyName");
const Property* prop = realm_object->get_object_schema().property_for_name(property_name);
if (!prop) {
throw std::invalid_argument(util::format("No such property: %1", property_name));
}
if (prop->type != realm::PropertyType::Object) {
throw TypeErrorException(accessor, realm_object->get_object_schema().name, *prop, args[1]);
}
auto& linked_schema = *realm_object->realm()->schema().find(prop->object_type);
auto linked_pk = linked_schema.primary_key_property();
if (!linked_pk) {
throw std::invalid_argument("Linked object type must have a primary key.");
}
auto table = realm_object->row().get_table();
auto linked_table = table->get_link_target(prop->table_column);
size_t row_ndx = realm::not_found;
if (linked_pk->type == realm::PropertyType::String) {
row_ndx = linked_table->find_first(linked_pk->table_column,
accessor.template unbox<StringData>(args[1]));
}
else if (is_nullable(linked_pk->type)) {
row_ndx = linked_table->find_first(linked_pk->table_column,
accessor.template unbox<util::Optional<int64_t>>(args[1]));
}
else {
row_ndx = linked_table->find_first(linked_pk->table_column,
accessor.template unbox<int64_t>(args[1]));
}
if (row_ndx == realm::not_found) {
realm_object->row().set_null(prop->table_column);
}
else {
realm_object->row().set_link(prop->table_column, row_ndx);
}
}
template<typename T>
std::vector<String<T>> RealmObjectClass<T>::get_property_names(ContextType ctx, ObjectType object) {
auto realm_object = get_internal<T, RealmObjectClass<T>>(object);

View File

@ -473,5 +473,87 @@ module.exports = {
TestCase.assertTrue(new Date('2017-12-07T20:16:03.837Z').toISOString() === objects[0].dateCol.toISOString())
realm.close()
},
testSetLink: function() {
const schema = [
{
name: 'PrimaryInt',
primaryKey: 'pk',
properties: {
pk: 'int',
value: 'int'
}
},
{
name: 'PrimaryOptionalInt',
primaryKey: 'pk',
properties: {
pk: 'int?',
value: 'int'
}
},
{
name: 'PrimaryString',
primaryKey: 'pk',
properties: {
pk: 'string?',
value: 'int'
}
},
{
name: 'Links',
properties: {
intLink: 'PrimaryInt',
optIntLink: 'PrimaryOptionalInt',
stringLink: 'PrimaryString'
}
}
];
const realm = new Realm({schema: schema});
realm.write(function() {
realm.create('PrimaryInt', {pk: 1, value: 2})
realm.create('PrimaryInt', {pk: 2, value: 4})
realm.create('PrimaryOptionalInt', {pk: 1, value: 2})
realm.create('PrimaryOptionalInt', {pk: 2, value: 4})
realm.create('PrimaryOptionalInt', {pk: null, value: 6})
realm.create('PrimaryString', {pk: 'a', value: 2})
realm.create('PrimaryString', {pk: 'b', value: 4})
realm.create('PrimaryString', {pk: null, value: 6})
const obj = realm.create('Links', {});
obj._setLink('intLink', 3);
TestCase.assertEqual(obj.intLink, null);
obj._setLink('intLink', 1);
TestCase.assertEqual(obj.intLink.value, 2);
obj._setLink('intLink', 2);
TestCase.assertEqual(obj.intLink.value, 4);
obj._setLink('intLink', 3);
TestCase.assertEqual(obj.intLink, null);
obj._setLink('optIntLink', 3);
TestCase.assertEqual(obj.optIntLink, null);
obj._setLink('optIntLink', 1);
TestCase.assertEqual(obj.optIntLink.value, 2);
obj._setLink('optIntLink', 2);
TestCase.assertEqual(obj.optIntLink.value, 4);
obj._setLink('optIntLink', null);
TestCase.assertEqual(obj.optIntLink.value, 6);
obj._setLink('optIntLink', 3);
TestCase.assertEqual(obj.optIntLink, null);
obj._setLink('stringLink', 'c');
TestCase.assertEqual(obj.stringLink, null);
obj._setLink('stringLink', 'a');
TestCase.assertEqual(obj.stringLink.value, 2);
obj._setLink('stringLink', 'b');
TestCase.assertEqual(obj.stringLink.value, 4);
obj._setLink('stringLink', null);
TestCase.assertEqual(obj.stringLink.value, 6);
obj._setLink('stringLink', 'c');
TestCase.assertEqual(obj.stringLink, null);
});
}
};