Skip to content

Commit

Permalink
(WIP) Move results of objects specific functionality to extension method
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsenko committed Sep 13, 2022
1 parent 02cedea commit d5c2af3
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 27 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"dart.lineLength": 160,
"cSpell.words": [
"apikeys",
"BEGINSWITH",
"bson",
"deallocated",
"deleter",
Expand Down
18 changes: 12 additions & 6 deletions lib/src/list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ abstract class RealmList<T extends Object?> with RealmEntityMixin implements Lis
/// and it's parent object hasn't been deleted.
bool get isValid;

RealmResults<T> get asResults;

factory RealmList._(RealmListHandle handle, Realm realm, RealmObjectMetadata? metadata) => ManagedRealmList._(handle, realm, metadata);
factory RealmList(Iterable<T> items) => UnmanagedRealmList(items);
}
Expand Down Expand Up @@ -126,6 +128,9 @@ class ManagedRealmList<T extends Object?> extends collection.ListBase<T> with Re

@override
bool get isValid => realmCore.listIsValid(this);

@override
RealmResults<T> get asResults => RealmResultsInternal.createFromList(handle, realm, _metadata);
}

class UnmanagedRealmList<T extends Object?> extends collection.ListBase<T> with RealmEntityMixin implements RealmList<T> {
Expand Down Expand Up @@ -160,6 +165,9 @@ class UnmanagedRealmList<T extends Object?> extends collection.ListBase<T> with

@override
bool get isValid => true;

@override
RealmResults<T> get asResults => throw RealmException("Unmanaged lists cannot be converted to results");
}

// The query operations on lists, as well as the ability to subscribe for notifications,
Expand All @@ -173,15 +181,13 @@ extension RealmListOfObject<T extends RealmObject> on RealmList<T> {
/// The Realm Dart and Realm Flutter SDKs supports querying based on a language inspired by [NSPredicate](https://academy.realm.io/posts/nspredicate-cheatsheet/)
/// and [Predicate Programming Guide.](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html#//apple_ref/doc/uid/TP40001789)
RealmResults<T> query(String query, [List<Object> arguments = const []]) {
final managedList = asManaged();
final handle = realmCore.queryList(managedList, query, arguments);
final handle = realmCore.queryList(asManaged, query, arguments);
return RealmResultsInternal.create<T>(handle, realm, _metadata);
}

/// Allows listening for changes when the contents of this collection changes.
Stream<RealmListChanges<T>> get changes {
final managedList = asManaged();
final controller = ListNotificationsController<T>(managedList);
final controller = ListNotificationsController<T>(asManaged);
return controller.createStream();
}
}
Expand All @@ -197,9 +203,9 @@ extension RealmListInternal<T extends Object?> on RealmList<T> {
}
}

ManagedRealmList<T> asManaged() => this is ManagedRealmList<T> ? this as ManagedRealmList<T> : throw RealmStateError('$this is not managed');
ManagedRealmList<T> get asManaged => this is ManagedRealmList<T> ? this as ManagedRealmList<T> : throw RealmStateError('$this is not managed');

RealmListHandle get handle => asManaged()._handle;
RealmListHandle get handle => asManaged._handle;

static RealmList<T> create<T extends Object?>(RealmListHandle handle, Realm realm, RealmObjectMetadata? metadata) => RealmList<T>._(handle, realm, metadata);

Expand Down
4 changes: 4 additions & 0 deletions lib/src/native/realm_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,10 @@ class _RealmCore {
});
}

RealmResultsHandle resultsFromList(RealmListHandle listHandle) {
return RealmResultsHandle._(listHandle._pointer.cast<realm_results>());
}

RealmObjectHandle getObjectAt(RealmResults results, int index) {
final pointer = _realmLib.invokeGetPointer(() => _realmLib.realm_results_get_object(results.handle._pointer, index));
return RealmObjectHandle._(pointer);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export 'credentials.dart' show Credentials, AuthProviderType, EmailPasswordAuthP
export 'list.dart' show RealmList, RealmListOfObject, RealmListChanges;
export 'realm_object.dart' show RealmEntityMixin, RealmObjectMixin, RealmException, RealmObject, RealmObjectChanges, DynamicRealmObject;
export 'realm_property.dart';
export 'results.dart' show RealmResults, RealmResultsChanges;
export 'results.dart' show RealmResults, RealmResultsChanges, RealmResultsOfObject;
export 'session.dart' show Session, SessionState, ConnectionState, ProgressDirection, ProgressMode, SyncProgress, ConnectionStateChange;
export 'subscription.dart' show Subscription, SubscriptionSet, SubscriptionSetState, MutableSubscriptionSet;
export 'user.dart' show User, UserState, UserIdentity;
Expand Down
48 changes: 35 additions & 13 deletions lib/src/results.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import 'dart:async';
import 'dart:collection' as collection;
import 'dart:ffi';

import 'package:realm_dart/src/type_utils.dart';

import 'collections.dart';
import 'native/realm_core.dart';
import 'realm_class.dart';
Expand All @@ -36,7 +38,7 @@ class RealmResults<T extends Object?> extends collection.IterableBase<T> impleme
/// The Realm instance this collection belongs to.
final Realm realm;

final _supportsSnapshot = <T>[] is List<RealmObject?>;
final _supportsSnapshot = isSubtype<T, RealmObject>();

RealmResults._(this._handle, this.realm, this._metadata);

Expand All @@ -46,15 +48,6 @@ class RealmResults<T extends Object?> extends collection.IterableBase<T> impleme
return RealmObjectInternal.create<T>(realm, handle, _metadata!);
}

/// Returns a new [RealmResults] filtered according to the provided query.
///
/// The Realm Dart and Realm Flutter SDKs supports querying based on a language inspired by [NSPredicate](https://academy.realm.io/posts/nspredicate-cheatsheet/)
/// and [Predicate Programming Guide.](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html#//apple_ref/doc/uid/TP40001789)
RealmResults<T> query(String query, [List<Object> args = const []]) {
final handle = realmCore.queryResults(this, query, args);
return RealmResultsInternal.create<T>(handle, realm, _metadata);
}

/// `true` if the `Results` collection is empty.
@override
bool get isEmpty => length == 0;
Expand All @@ -73,6 +66,25 @@ class RealmResults<T extends Object?> extends collection.IterableBase<T> impleme
/// The number of values in this `Results` collection.
@override
int get length => realmCore.getResultsCount(this);
}

// The query operations on results, as well as the ability to subscribe for notifications,
// only work for results of objects (core restriction), so we add these as an extension methods
// to allow the compiler to prevent misuse.
extension RealmResultsOfObject<T extends RealmObject> on RealmResults<T> {
RealmResults<T> snapshot() {
final handle = realmCore.resultsSnapshot(this);
return RealmResults<T>._(handle, realm, _metadata);
}

/// Returns a new [RealmResults] filtered according to the provided query.
///
/// The Realm Dart and Realm Flutter SDKs supports querying based on a language inspired by [NSPredicate](https://academy.realm.io/posts/nspredicate-cheatsheet/)
/// and [Predicate Programming Guide.](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html#//apple_ref/doc/uid/TP40001789)
RealmResults<T> query(String query, [List<Object> args = const []]) {
final handle = realmCore.queryResults(this, query, args);
return RealmResultsInternal.create<T>(handle, realm, _metadata);
}

/// Allows listening for changes when the contents of this collection changes.
Stream<RealmResultsChanges<T>> get changes {
Expand All @@ -91,9 +103,19 @@ extension RealmResultsInternal on RealmResults {

RealmResultsHandle get handle => _handle;

static RealmResults<T> create<T extends Object?>(RealmResultsHandle handle, Realm realm, RealmObjectMetadata? metadata) {
return RealmResults<T>._(handle, realm, metadata);
}
static RealmResults<T> create<T extends Object?>(
RealmResultsHandle handle,
Realm realm,
RealmObjectMetadata? metadata,
) =>
RealmResults<T>._(handle, realm, metadata);

static RealmResults<T> createFromList<T extends Object?>(
RealmListHandle handle,
Realm realm,
RealmObjectMetadata? metadata,
) =>
RealmResults<T>._(realmCore.resultsFromList(handle), realm, metadata);
}

/// Describes the changes in a Realm results collection since the last time the notification callback was invoked.
Expand Down
14 changes: 7 additions & 7 deletions test/subscription_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -295,18 +295,18 @@ Future<void> main([List<String>? args]) async {

ObjectId newOid() => ObjectId.fromBytes(randomBytes(12));

final oids = <ObjectId>{};
final objectIds = <ObjectId>{};
const max = 1000;
subscriptions.update((mutableSubscriptions) {
oids.addAll([
objectIds.addAll([
for (int i = 0; i < max; ++i) mutableSubscriptions.add(realm.query<Task>(r'_id == $0', [newOid()])).id
]);
});
expect(oids.length, max); // no collisions
expect(objectIds.length, max); // no collisions
expect(subscriptions.length, max);

for (final sub in subscriptions) {
expect(sub.id, isIn(oids));
expect(sub.id, isIn(objectIds));
}
});

Expand Down Expand Up @@ -499,7 +499,7 @@ Future<void> main([List<String>? args]) async {
expect(() => realm.write(() => realm.add(Task(ObjectId()))), throws<RealmException>("no flexible sync subscription has been created"));
});

testSubscriptions('Subscription on unqueryable field sould throw', (realm) async {
testSubscriptions('Subscription on non-queryable field should throw', (realm) async {
realm.subscriptions.update((mutableSubscriptions) {
mutableSubscriptions.add(realm.all<Event>());
});
Expand All @@ -513,7 +513,7 @@ Future<void> main([List<String>? args]) async {
isCompleted: false,
durationInMinutes: 10,
),
Event(ObjectId(), name: "Some other eveent", isCompleted: true, durationInMinutes: 60),
Event(ObjectId(), name: "Some other event", isCompleted: true, durationInMinutes: 60),
]);
});

Expand Down Expand Up @@ -550,7 +550,7 @@ Future<void> main([List<String>? args]) async {
realm.addAll([
Event(ObjectId(), name: "NPMG Event", isCompleted: true, durationInMinutes: 30),
Event(ObjectId(), name: "NPMG Meeting", isCompleted: false, durationInMinutes: 10),
Event(ObjectId(), name: "Some other eveent", isCompleted: true, durationInMinutes: 60),
Event(ObjectId(), name: "Some other event", isCompleted: true, durationInMinutes: 60),
]);
});

Expand Down

0 comments on commit d5c2af3

Please sign in to comment.