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

Realm list.query #239

Merged
merged 4 commits into from
Feb 8, 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
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 []]) {
nielsenko marked this conversation as resolved.
Show resolved Hide resolved
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) {
nielsenko marked this conversation as resolved.
Show resolved Hide resolved
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']);
nielsenko marked this conversation as resolved.
Show resolved Hide resolved

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

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