From 3f6289e31798c5124fe6d46956ce29de7de92ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20Overg=C3=A5rd=20Nielsen?= Date: Thu, 3 Nov 2022 13:02:29 +0100 Subject: [PATCH] Expose embeddedObject.getParent --- lib/src/native/realm_core.dart | 21 +++++++++++++++++++-- lib/src/realm_class.dart | 15 +++++++++++++++ lib/src/realm_object.dart | 12 +++++++++++- lib/src/util.dart | 6 ++++++ test/embedded_test.dart | 30 ++++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 lib/src/util.dart diff --git a/lib/src/native/realm_core.dart b/lib/src/native/realm_core.dart index 40eebca369..d8b4b43d09 100644 --- a/lib/src/native/realm_core.dart +++ b/lib/src/native/realm_core.dart @@ -44,6 +44,7 @@ import '../scheduler.dart'; import '../subscription.dart'; import '../user.dart'; import '../session.dart'; +import '../util.dart'; import 'realm_bindings.dart'; import '../migration.dart'; @@ -716,8 +717,20 @@ class _RealmCore { } RealmObjectHandle createEmbeddedObject(RealmObjectBase obj, int propertyKey) { - final realmPtr = _realmLib.invokeGetPointer(() => _realmLib.realm_set_embedded(obj.handle._pointer, propertyKey)); - return RealmObjectHandle._(realmPtr, obj.realm.handle); + final objectPtr = _realmLib.invokeGetPointer(() => _realmLib.realm_set_embedded(obj.handle._pointer, propertyKey)); + return RealmObjectHandle._(objectPtr, obj.realm.handle); + } + + Tuple getEmbeddedParent(EmbeddedObject obj) { + return using((Arena arena) { + final parentPtr = arena>(); + final classKeyPtr = arena(); + _realmLib.invokeGetBool(() => _realmLib.realm_object_get_parent(obj.handle._pointer, parentPtr, classKeyPtr)); + + final handle = RealmObjectHandle._(parentPtr.value, obj.realm.handle); + + return Tuple(handle, classKeyPtr.value); + }); } RealmObjectHandle getOrCreateRealmObjectWithPrimaryKey(Realm realm, int classKey, Object? primaryKey) { @@ -1054,6 +1067,10 @@ class _RealmCore { return _realmLib.realm_equals(first._pointer.cast(), second._pointer.cast()); } + int getObjectKey(RealmObjectBase obj) { + return _realmLib.realm_object_get_key(obj.handle._pointer); + } + bool objectEquals(RealmObjectBase first, RealmObjectBase second) => _equals(first.handle, second.handle); bool realmEquals(Realm first, Realm second) => _equals(first.handle, second.handle); bool userEquals(User first, User second) => _equals(first.handle, second.handle); diff --git a/lib/src/realm_class.dart b/lib/src/realm_class.dart index 3854b1cc27..2ae7b21790 100644 --- a/lib/src/realm_class.dart +++ b/lib/src/realm_class.dart @@ -33,6 +33,7 @@ import 'results.dart'; import 'scheduler.dart'; import 'subscription.dart'; import 'session.dart'; +import 'util.dart'; export 'package:realm_common/realm_common.dart' show @@ -757,6 +758,20 @@ class RealmMetadata { return metadata; } + + Tuple getByClassKey(int key) { + final type = _typeMap.entries.firstWhereOrNull((e) => e.value.classKey == key); + if (type != null) { + return Tuple(type.key, type.value); + } + + final metadata = _stringMap.values.firstWhereOrNull((e) => e.classKey == key); + if (metadata != null) { + return Tuple(RealmObjectBase, metadata); + } + + throw RealmError("Object with classKey $key not found in the current Realm's schema."); + } } /// Exposes a set of dynamic methods on the Realm object. These don't use strongly typed diff --git a/lib/src/realm_object.dart b/lib/src/realm_object.dart index 08da7ae006..e4f7174fc3 100644 --- a/lib/src/realm_object.dart +++ b/lib/src/realm_object.dart @@ -411,7 +411,17 @@ mixin RealmObjectBase on RealmEntity implements Finalizable { mixin RealmObject on RealmObjectBase {} /// @nodoc -mixin EmbeddedObject on RealmObjectBase {} +mixin EmbeddedObject on RealmObjectBase { + RealmObjectBase? getParent() { + if (!isManaged) { + return null; + } + + final parent = realmCore.getEmbeddedParent(this); + final metadata = realm.metadata.getByClassKey(parent.item2); + return realm.createObject(metadata.item1, parent.item1, metadata.item2); + } +} /// @nodoc //RealmObject package internal members diff --git a/lib/src/util.dart b/lib/src/util.dart new file mode 100644 index 0000000000..389c548bfb --- /dev/null +++ b/lib/src/util.dart @@ -0,0 +1,6 @@ +class Tuple { + T1 item1; + T2 item2; + + Tuple(this.item1, this.item2); +} diff --git a/test/embedded_test.dart b/test/embedded_test.dart index a86f4db2ad..3fe3ed5167 100644 --- a/test/embedded_test.dart +++ b/test/embedded_test.dart @@ -811,6 +811,36 @@ Future main([List? args]) async { expect(parent.recursiveList, isEmpty); }); + + test('EmbeddedObject.getParent returns parent', () async { + final realm = getLocalRealm(); + + final parent = + ObjectWithEmbedded('123', recursiveObject: RecursiveEmbedded1('1.1', child: RecursiveEmbedded2('2.1')), recursiveList: [RecursiveEmbedded1('1.2')]); + + realm.write(() { + realm.add(parent); + }); + + final child1 = parent.recursiveObject!; + + expect(child1.getParent(), parent); + expect(child1.child!.getParent(), child1); + + expect(parent.recursiveList[0].getParent(), parent); + }); + + test('EmbeddedObject.getParent when unmanaged returns null', () async { + final parent = + ObjectWithEmbedded('123', recursiveObject: RecursiveEmbedded1('1.1', child: RecursiveEmbedded2('2.1')), recursiveList: [RecursiveEmbedded1('1.2')]); + + final child1 = parent.recursiveObject!; + + expect(child1.getParent(), null); + expect(child1.child!.getParent(), null); + + expect(parent.recursiveList[0].getParent(), null); + }); } extension on RealmObjectBase {