Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose embeddedObject.getParent #979

Merged
merged 5 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Support notifications on all managed realm lists, including list of primitives, ie. `RealmList<int>.changes` is supported. ([#893](https://github.com/realm/realm-dart/pull/893))
* Support named backlinks on realm models. You can now add and annotate a realm object iterator field with `@Backlink(#fieldName)`. ([#996](https://github.com/realm/realm-dart/pull/996))
* Allow `@Indexed` attribute on all indexable type, and ensure appropriate indexes are created in the realm. ([#797](https://github.com/realm/realm-dart/issues/797))
* Add `parent` getter on embedded objects. ([#979](https://github.com/realm/realm-dart/pull/979))

### Fixed
* Fixed a wrong mapping for `AuthProviderType` returned by `User.provider` for google, facebook and apple credentials.
Expand Down
8 changes: 8 additions & 0 deletions common/lib/src/realm_common_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,11 @@ class Backlink {
final Symbol fieldName;
const Backlink(this.fieldName);
}

/// @nodoc
class Tuple<T1, T2> {
T1 item1;
T2 item2;

Tuple(this.item1, this.item2);
}
21 changes: 16 additions & 5 deletions lib/src/native/realm_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import 'dart:io';
import 'dart:typed_data';

import 'package:cancellation_token/cancellation_token.dart';
import 'package:collection/collection.dart';
// Hide StringUtf8Pointer.toNativeUtf8 and StringUtf16Pointer since these allows silently allocating memory. Use toUtf8Ptr instead
import 'package:ffi/ffi.dart' hide StringUtf8Pointer, StringUtf16Pointer;
import 'package:logging/logging.dart';
Expand All @@ -37,15 +36,15 @@ import '../configuration.dart';
import '../credentials.dart';
import '../init.dart';
import '../list.dart';
import '../migration.dart';
import '../realm_class.dart';
import '../realm_object.dart';
import '../results.dart';
import '../scheduler.dart';
import '../session.dart';
import '../subscription.dart';
import '../user.dart';
import '../session.dart';
import 'realm_bindings.dart';
import '../migration.dart';

late RealmLibrary _realmLib;

Expand Down Expand Up @@ -720,8 +719,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<RealmObjectHandle, int> getEmbeddedParent(EmbeddedObject obj) {
return using((Arena arena) {
final parentPtr = arena<Pointer<realm_object>>();
final classKeyPtr = arena<Uint32>();
_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) {
Expand Down
26 changes: 25 additions & 1 deletion lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,17 @@ export "configuration.dart"
export 'credentials.dart' show Credentials, AuthProviderType, EmailPasswordAuthProvider;
export 'list.dart' show RealmList, RealmListOfObject, RealmListChanges;
export 'realm_object.dart'
show RealmEntity, RealmException, UserCallbackException, RealmObject, RealmObjectBase, EmbeddedObject, RealmObjectChanges, DynamicRealmObject;
show
RealmEntity,
RealmException,
UserCallbackException,
RealmObject,
RealmObjectBase,
EmbeddedObject,
EmbeddedObjectExtension,
RealmObjectChanges,
DynamicRealmObject;

export 'realm_property.dart';
export 'results.dart' show RealmResults, RealmResultsChanges, RealmResultsOfObject;
export 'session.dart' show Session, SessionState, ConnectionState, ProgressDirection, ProgressMode, SyncProgress, ConnectionStateChange;
Expand Down Expand Up @@ -757,6 +767,20 @@ class RealmMetadata {

return metadata;
}

Tuple<Type, RealmObjectMetadata> 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
Expand Down
15 changes: 14 additions & 1 deletion lib/src/realm_object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ mixin RealmObjectBase on RealmEntity implements Finalizable {
}

/// @nodoc
static bool setDefaults<T extends RealmObject>(Map<String, Object> values) {
static bool setDefaults<T extends RealmObjectBase>(Map<String, Object> values) {
RealmAccessor.setDefaults<T>(values);
return true;
}
Expand Down Expand Up @@ -413,6 +413,19 @@ mixin RealmObject on RealmObjectBase {}
/// @nodoc
mixin EmbeddedObject on RealmObjectBase {}

extension EmbeddedObjectExtension on EmbeddedObject {
/// Retrieve the [parent] object of this embedded object.
RealmObjectBase? get parent {
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
extension RealmObjectInternal on RealmObjectBase {
Expand Down
30 changes: 30 additions & 0 deletions test/embedded_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,36 @@ Future<void> main([List<String>? 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.parent, parent);
expect(child1.child!.parent, child1);

expect(parent.recursiveList[0].parent, 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.parent, null);
expect(child1.child!.parent, null);

expect(parent.recursiveList[0].parent, null);
});
}

extension on RealmObjectBase {
Expand Down