Skip to content

Commit

Permalink
Realm list.query (#239)
Browse files Browse the repository at this point in the history
* Add RealmList.query method

* Add test of RealmList.query

* Update CHANGELOG, and add TODO to remember to get rid of cast when possible

* Apply suggestions for comments from code review

Co-authored-by: blagoev <lubo@blagoev.com>
  • Loading branch information
nielsenko and blagoev authored Feb 8, 2022
1 parent 512974c commit a1d5ba5
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 14 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ vNext
### Changes
* Primary key annotation no longer requires field to be final.

### Enhancements
* Support query on lists of realm objects


0.2.0+alpha Release notes (2022-01-31)
==============================================================
Expand Down
37 changes: 30 additions & 7 deletions lib/src/list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ import 'native/realm_core.dart';

import 'realm_object.dart';
import 'realm_class.dart';
import 'results.dart';

/// Instances of this class are live collections and will update as new elements are either
/// Instances of this class are live collections and will update as new elements are either
/// added to or deleted from the Realm that match the underlying query.
///
///{@category Realm}
class RealmList<T extends Object> extends collection.ListBase<T> {
late final RealmListHandle _handle;
late final Realm _realm;
final RealmListHandle _handle;
final Realm _realm;

RealmList._(this._handle, this._realm);

Expand Down Expand Up @@ -72,9 +73,9 @@ class RealmList<T extends Object> extends collection.ListBase<T> {

/// Clears the collection in memory and the references
/// to the objects in this collection in Realm.
/// Removes all elements from this list.
///
/// Removes all elements from this list.
///
/// The length of the list becomes zero.
/// If the elements are managed [RealmObject]s, they all remain in the Realm.
@override
Expand All @@ -83,10 +84,32 @@ class RealmList<T extends Object> extends collection.ListBase<T> {
}
}

// The query operations on lists only work for list of objects (core restriction),
// so we add it as an extension method to allow the compiler to prevent misuse.
extension RealmListOfObject<T extends RealmObject> on RealmList<T> {
/// Filters the list and returns a new [RealmResults] according to the provided query.
///
/// Only works for lists of Realm objects.
///
/// @param query The query used to filter the list
/// @param args Optional parameters for substitution in the query
///
/// @return The live result
///
/// 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)
///
/// Only works for lists of objects.
RealmResults<T> query(String query, [List<Object> args = const []]) {
final handle = realmCore.queryList(this, query, args);
return RealmResultsInternal.create<T>(handle, realm);
}
}

/// @nodoc
extension RealmListInternal on RealmList {
RealmListHandle get handle => _handle;
Realm? get realm => _realm;
Realm get realm => _realm;

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

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


// For debugging
// ignore: unused_element
int get _threadId => _realmLib.get_thread_id();
Expand Down Expand Up @@ -364,6 +363,26 @@ class _RealmCore {
});
}

RealmResultsHandle queryList(RealmList target, String query, List<Object> args) {
return using((arena) {
final length = args.length;
final argsPointer = arena<realm_value_t>(length);
for (var i = 0; i < length; ++i) {
_intoRealmValue(args[i], argsPointer.elementAt(i), arena);
}
final queryHandle = RealmQueryHandle._(_realmLib.invokeGetPointer(
() => _realmLib.realm_query_parse_for_list(
target.handle._pointer,
query.toUtf8Ptr(arena),
length,
argsPointer,
),
));
final resultsPointer = _realmLib.invokeGetPointer(() => _realmLib.realm_query_find_all(queryHandle._pointer));
return RealmResultsHandle._(resultsPointer);
});
}

RealmObjectHandle getObjectAt(RealmResults results, int index) {
final pointer = _realmLib.invokeGetPointer(() => _realmLib.realm_results_get_object(results.handle._pointer, index));
return RealmObjectHandle._(pointer);
Expand Down Expand Up @@ -404,7 +423,7 @@ class _RealmCore {
return using((Arena arena) {
final realm_value = arena<realm_value_t>();
_realmLib.invokeGetBool(() => _realmLib.realm_list_get(list.handle._pointer, index, realm_value));
return realm_value.toDartValue(list.realm!);
return realm_value.toDartValue(list.realm);
});
}

Expand Down Expand Up @@ -456,8 +475,8 @@ abstract class Handle<T extends NativeType> {

Handle(this._pointer, int size) {
if (_realmLib.realm_attach_finalizer(this, _pointer.cast(), size) == false) {
throw Exception("Error creating $runtimeType");
}
throw Exception("Error creating $runtimeType");
}
}

@override
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 @@ -32,7 +32,7 @@ export 'package:realm_common/realm_common.dart'
show Ignored, Indexed, MapTo, PrimaryKey, RealmError, RealmModel, RealmUnsupportedSetError, RealmCollectionType, RealmPropertyType;

export "configuration.dart" show Configuration, RealmSchema, SchemaObject;
export 'list.dart' show RealmList;
export 'list.dart' show RealmList, RealmListOfObject;
export 'realm_object.dart' show RealmException, RealmObject;
export 'realm_property.dart';
export 'results.dart' show RealmResults;
Expand Down
4 changes: 2 additions & 2 deletions lib/src/results.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import 'realm_class.dart';
///
/// {@category Realm}
class RealmResults<T extends RealmObject> extends collection.IterableBase<T> {
late final RealmResultsHandle _handle;
late final Realm _realm;
final RealmResultsHandle _handle;
final Realm _realm;

RealmResults._(this._handle, this._realm);

Expand Down
20 changes: 20 additions & 0 deletions test/realm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,26 @@ Future<void> main([List<String>? args]) async {
realm.close();
});

test('Query list', () {
final config = Configuration([Team.schema, Person.schema]);
final realm = Realm(config);

final person = Person('Kasper');
final team = Team('Realm-dart', players: [
Person('Lubo'),
person,
Person('Desi'),
]);

realm.write(() => realm.add(team));

// TODO: Get rid of cast, once type signature of team.players is a RealmList<Person>
// as opposed to the List<Person> we have today.
final result = (team.players as RealmList<Person>).query(r'name BEGINSWITH $0', ['K']);

expect(result, [person]);
});

test('Sort result', () {
var config = Configuration([Person.schema]);
var realm = Realm(config);
Expand Down

0 comments on commit a1d5ba5

Please sign in to comment.