Skip to content

Commit

Permalink
Add dynamic support to RealmObject
Browse files Browse the repository at this point in the history
  • Loading branch information
nirinchev committed May 3, 2022
1 parent 7a9f42d commit cb1a36f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 15 deletions.
2 changes: 1 addition & 1 deletion lib/src/realm_class.dart
Expand Up @@ -330,7 +330,7 @@ extension RealmInternal on Realm {
}

RealmList<T> createList<T extends Object?>(RealmListHandle handle, RealmObjectMetadata? metadata) {
return RealmListInternal.create(handle, this, metadata);
return RealmListInternal.create<T>(handle, this, metadata);
}

List<String> getPropertyNames(Type type, List<int> propertyKeys) {
Expand Down
39 changes: 26 additions & 13 deletions lib/src/realm_object.dart
Expand Up @@ -17,11 +17,14 @@
////////////////////////////////////////////////////////////////////////////////
import 'dart:async';
import 'dart:mirrors';

import 'list.dart';
import 'native/realm_core.dart';
import 'realm_class.dart';

typedef DartDynamic = dynamic;

abstract class RealmAccessor {
Object? get<T extends Object?>(RealmObject object, String name);
void set(RealmObject object, String name, Object? value, [bool isDefault = false]);
Expand Down Expand Up @@ -136,13 +139,21 @@ class RealmCoreAccessor implements RealmAccessor {
if (propertyMeta.collectionType == RealmCollectionType.list) {
final handle = realmCore.getListProperty(object, propertyMeta.key);
final listMeta = propertyMeta.objectType == null ? null : object.realm.metadata.getByName(propertyMeta.objectType!);
if (listMeta != null && _isTypeGenericObject<T>()) {
return object.realm.createList<RealmObject>(handle, listMeta);
}

return object.realm.createList<T>(handle, listMeta);
}

Object? value = realmCore.getProperty(object, propertyMeta.key);

if (value is RealmObjectHandle) {
final targetMetadata = propertyMeta.objectType != null ? object.realm.metadata.getByName(propertyMeta.objectType!) : object.realm.metadata.getByType(T);
if (_isTypeGenericObject<T>()) {
return object.realm.createObject(RealmObject, value, targetMetadata);
}

return object.realm.createObject(T, value, targetMetadata);
}

Expand Down Expand Up @@ -274,6 +285,16 @@ mixin RealmObject on RealmEntity {
return controller.createStream();
}

@override
DartDynamic noSuchMethod(Invocation invocation) {
if (invocation.isGetter) {
final name = MirrorSystem.getName(invocation.memberName);
return get(this, name);
}

return super.noSuchMethod(invocation);
}

late final DynamicRealmObject dynamic = DynamicRealmObject._(this);
}

Expand Down Expand Up @@ -383,28 +404,20 @@ class ConcreteRealmObject with RealmEntity, RealmObject {

Type _typeOf<T>() => T;

bool _isTypeGenericObject<T>() => T == Object || T == _typeOf<Object?>();

class DynamicRealmObject {
final RealmObject _obj;

DynamicRealmObject._(this._obj);

T get<T extends Object?>(String name) {
final prop = _validatePropertyType<T>(name, RealmCollectionType.none);
// If the user didn't provide a type argument, but the target is object, we should
// use RealmObject, otherwise we won't be able to find a Factory for the object.
if (T == _typeOf<Object?>() && prop?.propertyType == RealmPropertyType.object) {
return RealmObject.get<RealmObject>(_obj, name) as T;
}

_validatePropertyType<T>(name, RealmCollectionType.none);
return RealmObject.get<T>(_obj, name) as T;
}

List<T> getList<T extends Object>(String name) {
final prop = _validatePropertyType<T>(name, RealmCollectionType.list);
if (T == _typeOf<Object?>() && prop?.propertyType == RealmPropertyType.object) {
return RealmObject.get<RealmObject>(_obj, name) as List<T>;
}

List<T> getList<T extends Object?>(String name) {
_validatePropertyType<T>(name, RealmCollectionType.list);
return RealmObject.get<T>(_obj, name) as List<T>;
}

Expand Down
26 changes: 25 additions & 1 deletion test/dynamic_realm_test.dart
Expand Up @@ -96,7 +96,6 @@ Future<void> main([List<String>? args]) async {
void _validateDynamic(RealmObject actual, AllTypes expected) {
expect(actual.dynamic.get<String>('stringProp'), expected.stringProp);
expect(actual.dynamic.get('stringProp'), expected.stringProp);

expect(actual.dynamic.get<String?>('nullableStringProp'), expected.nullableStringProp);
expect(actual.dynamic.get('nullableStringProp'), expected.nullableStringProp);

Expand Down Expand Up @@ -129,6 +128,22 @@ Future<void> main([List<String>? args]) async {
expect(actual.dynamic.get('intProp'), expected.intProp);
expect(actual.dynamic.get<int?>('nullableIntProp'), expected.nullableIntProp);
expect(actual.dynamic.get('nullableIntProp'), expected.nullableIntProp);

dynamic actualDynamic = actual;
expect(actualDynamic.stringProp, expected.stringProp);
expect(actualDynamic.nullableStringProp, expected.nullableStringProp);
expect(actualDynamic.boolProp, expected.boolProp);
expect(actualDynamic.nullableBoolProp, expected.nullableBoolProp);
expect(actualDynamic.dateProp, expected.dateProp);
expect(actualDynamic.nullableDateProp, expected.nullableDateProp);
expect(actualDynamic.doubleProp, expected.doubleProp);
expect(actualDynamic.nullableDoubleProp, expected.nullableDoubleProp);
expect(actualDynamic.objectIdProp, expected.objectIdProp);
expect(actualDynamic.nullableObjectIdProp, expected.nullableObjectIdProp);
expect(actualDynamic.uuidProp, expected.uuidProp);
expect(actualDynamic.nullableUuidProp, expected.nullableUuidProp);
expect(actualDynamic.intProp, expected.intProp);
expect(actualDynamic.nullableIntProp, expected.nullableIntProp);
}

void _validateDynamicLists(RealmObject actual, AllCollections expected) {
Expand All @@ -152,6 +167,15 @@ Future<void> main([List<String>? args]) async {

expect(actual.dynamic.getList<int>('ints'), expected.ints);
expect(actual.dynamic.getList('ints'), expected.ints);

dynamic actualDynamic = actual;
expect(actualDynamic.strings, expected.strings);
expect(actualDynamic.bools, expected.bools);
expect(actualDynamic.dates, expected.dates);
expect(actualDynamic.doubles, expected.doubles);
expect(actualDynamic.objectIds, expected.objectIds);
expect(actualDynamic.uuids, expected.uuids);
expect(actualDynamic.ints, expected.ints);
}

for (var isDynamic in [true, false]) {
Expand Down

0 comments on commit cb1a36f

Please sign in to comment.