Skip to content

Commit

Permalink
Merge cb156f6 into fa9fb59
Browse files Browse the repository at this point in the history
  • Loading branch information
blagoev committed Feb 23, 2022
2 parents fa9fb59 + cb156f6 commit 8c890b7
Show file tree
Hide file tree
Showing 18 changed files with 433 additions and 55 deletions.
8 changes: 8 additions & 0 deletions example/bin/myapp.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions flutter/realm_flutter/example/lib/main.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions flutter/realm_flutter/tests/test_driver/realm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:test_api/src/backend/state.dart' as test_api;

import '../test/configuration_test.dart' as configuration_test;
import '../test/realm_test.dart' as realm_tests;
import '../test/realm_object_test.dart' as realm_object_tests;
import '../test/list_test.dart' as list_tests;
import '../test/results_test.dart' as results_tests;

Expand All @@ -19,6 +20,8 @@ Future<String> main(List<String> args) async {
await realm_tests.main(args);
await list_tests.main(args);
await results_tests.main(args);
await results_tests.main(args);
await realm_object_tests.main(args);

tearDown(() {
if (Invoker.current?.liveTest.state.result == test_api.Result.error || Invoker.current?.liveTest.state.result == test_api.Result.failure) {
Expand Down
4 changes: 4 additions & 0 deletions generator/lib/src/realm_model_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ class RealmModelInfo {
'',
]);

yield '@override';
yield 'Stream<RealmObjectChanges<$name>> get changes => RealmObject.getChanges<$name>(this);';
yield '';

yield 'static SchemaObject get schema => _schema ??= _initSchema();';
yield 'static SchemaObject? _schema;';
yield 'static SchemaObject _initSchema() {';
Expand Down
4 changes: 4 additions & 0 deletions generator/test/generator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class _Foo {
' @override\n'
' set x(int value) => RealmObject.set(this, \'x\', value);\n'
'\n'
' @override\n'
' Stream<RealmObjectChanges<Foo>> get changes =>\n'
' RealmObject.getChanges<Foo>(this);\n'
'\n'
' static SchemaObject get schema => _schema ??= _initSchema();\n'
' static SchemaObject? _schema;\n'
' static SchemaObject _initSchema() {\n'
Expand Down
20 changes: 20 additions & 0 deletions generator/test/good_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class _Person {
' @override\n'
' set age(int value) => RealmObject.set(this, \'age\', value);\n'
'\n'
' @override\n'
' Stream<RealmObjectChanges<Person>> get changes =>\n'
' RealmObject.getChanges<Person>(this);\n'
'\n'
' static SchemaObject get schema => _schema ??= _initSchema();\n'
' static SchemaObject? _schema;\n'
' static SchemaObject _initSchema() {\n'
Expand Down Expand Up @@ -92,6 +96,10 @@ class _Person {
' @override\n'
' set name(String value) => throw RealmUnsupportedSetError();\n'
'\n'
' @override\n'
' Stream<RealmObjectChanges<Person>> get changes =>\n'
' RealmObject.getChanges<Person>(this);\n'
'\n'
' static SchemaObject get schema => _schema ??= _initSchema();\n'
' static SchemaObject? _schema;\n'
' static SchemaObject _initSchema() {\n'
Expand Down Expand Up @@ -142,6 +150,10 @@ class _Person {
' set children(covariant List<Person> value) =>\n'
' throw RealmUnsupportedSetError();\n'
'\n'
' @override\n'
' Stream<RealmObjectChanges<Person>> get changes =>\n'
' RealmObject.getChanges<Person>(this);\n'
'\n'
' static SchemaObject get schema => _schema ??= _initSchema();\n'
' static SchemaObject? _schema;\n'
' static SchemaObject _initSchema() {\n'
Expand Down Expand Up @@ -191,6 +203,10 @@ class _Person {
' @override\n'
' set spouse(covariant Person? value) => RealmObject.set(this, \'spouse\', value);\n'
'\n'
' @override\n'
' Stream<RealmObjectChanges<Person>> get changes =>\n'
' RealmObject.getChanges<Person>(this);\n'
'\n'
' static SchemaObject get schema => _schema ??= _initSchema();\n'
' static SchemaObject? _schema;\n'
' static SchemaObject _initSchema() {\n'
Expand Down Expand Up @@ -241,6 +257,10 @@ class _Person {
' @override\n'
' set name(String value) => RealmObject.set(this, \'name\', value);\n'
'\n'
' @override\n'
' Stream<RealmObjectChanges<Person>> get changes =>\n'
' RealmObject.getChanges<Person>(this);\n'
'\n'
' static SchemaObject get schema => _schema ??= _initSchema();\n'
' static SchemaObject? _schema;\n'
' static SchemaObject _initSchema() {\n'
Expand Down
6 changes: 5 additions & 1 deletion lib/src/list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,11 @@ class ListNotificationsController<T extends Object> extends NotificationsControl
}

@override
void onChanges(RealmCollectionChangesHandle changesHandle) {
void onChanges(Handle changesHandle) {
if (changesHandle is! RealmCollectionChangesHandle) {
throw RealmError("Invalid changes handle. RealmCollectionChangesHandle expected");
}

final changes = RealmListChanges._(changesHandle, list);
streamController.add(changes);
}
Expand Down
42 changes: 42 additions & 0 deletions lib/src/native/realm_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7018,6 +7018,45 @@ class RealmLibrary {
realm_dart_on_collection_change_func_t,
ffi.Pointer<realm_scheduler_t>)>();

/// Subscribe for notifications of changes to a realm object.
///
/// @param realm_object The realm object to subscribe to.
/// @param notification_controller A handle to a Dart NotificationController instance that will be passed to the callback.
/// @param on_change The callback to invoke, if the realm list changes.
/// @return A notification token that can be released to unsubscribe.
///
/// This is a dart specific wrapper for realm_object_add_notification_callback.
ffi.Pointer<realm_notification_token_t>
realm_dart_object_add_notification_callback(
ffi.Pointer<realm_object_t> list,
Object notification_controller,
realm_dart_on_object_change_func_t on_change,
ffi.Pointer<realm_scheduler_t> scheduler,
) {
return _realm_dart_object_add_notification_callback(
list,
notification_controller,
on_change,
scheduler,
);
}

late final _realm_dart_object_add_notification_callbackPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<realm_notification_token_t> Function(
ffi.Pointer<realm_object_t>,
ffi.Handle,
realm_dart_on_object_change_func_t,
ffi.Pointer<realm_scheduler_t>)>>(
'realm_dart_object_add_notification_callback');
late final _realm_dart_object_add_notification_callback =
_realm_dart_object_add_notification_callbackPtr.asFunction<
ffi.Pointer<realm_notification_token_t> Function(
ffi.Pointer<realm_object_t>,
Object,
realm_dart_on_object_change_func_t,
ffi.Pointer<realm_scheduler_t>)>();

ffi.Pointer<ffi.Int8> realm_dart_get_files_path() {
return _realm_dart_get_files_path();
}
Expand Down Expand Up @@ -7942,3 +7981,6 @@ typedef realm_dart_on_collection_change_func_t = ffi.Pointer<
ffi.NativeFunction<
ffi.Void Function(
ffi.Handle, ffi.Pointer<realm_collection_changes_t>)>>;
typedef realm_dart_on_object_change_func_t = ffi.Pointer<
ffi.NativeFunction<
ffi.Void Function(ffi.Handle, ffi.Pointer<realm_object_changes_t>)>>;
52 changes: 49 additions & 3 deletions lib/src/native/realm_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ class _RealmCore {
});
}

//TODO: Use Finalizers, when available, instead of native WeakHandles https://github.com/dart-lang/language/issues/1847
SchemaHandle createSchema(List<SchemaObject> schema) {
return using((Arena arena) {
final classCount = schema.length;
Expand Down Expand Up @@ -548,6 +547,25 @@ class _RealmCore {
}
}

static void object_change_callback(Object object, Pointer<realm_object_changes> data) {
assert(object is NotificationsController, "Notification controller expected");

final controller = object as NotificationsController;

if (data == nullptr) {
//realm_collection_changes data clone is done in native code before this callback is invoked. nullptr data means cloning failed.
controller.onError(RealmError("Invalid notifications data received"));
return;
}

try {
final changesHandle = RealmObjectChangesHandle._(data);
controller.onChanges(changesHandle);
} catch (e) {
controller.onError(RealmError("Error handling collection change notifications. Error: $e"));
}
}

RealmNotificationTokenHandle subscribeResultsNotifications(RealmResultsHandle handle, NotificationsController controller, SchedulerHandle schedulerHandle) {
final onChangeCallback = Pointer.fromFunction<Void Function(ffi.Handle, Pointer<realm_collection_changes>)>(collection_change_callback);

Expand All @@ -560,11 +578,35 @@ class _RealmCore {
RealmNotificationTokenHandle subscribeListNotifications(RealmListHandle handle, NotificationsController controller, SchedulerHandle schedulerHandle) {
final onChangeCallback = Pointer.fromFunction<Void Function(ffi.Handle, Pointer<realm_collection_changes>)>(collection_change_callback);

final pointer = _realmLib.invokeGetPointer(
() => _realmLib.realm_dart_list_add_notification_callback(handle._pointer, controller, onChangeCallback, schedulerHandle._pointer));
final pointer = _realmLib
.invokeGetPointer(() => _realmLib.realm_dart_list_add_notification_callback(handle._pointer, controller, onChangeCallback, schedulerHandle._pointer));

return RealmNotificationTokenHandle._(pointer);
}

RealmNotificationTokenHandle subscribeObjectNotifications(RealmObjectHandle handle, NotificationsController controller, SchedulerHandle schedulerHandle) {
final onChangeCallback = Pointer.fromFunction<Void Function(ffi.Handle, Pointer<realm_object_changes>)>(object_change_callback);

final pointer = _realmLib
.invokeGetPointer(() => _realmLib.realm_dart_object_add_notification_callback(handle._pointer, controller, onChangeCallback, schedulerHandle._pointer));

return RealmNotificationTokenHandle._(pointer);
}

bool getObjectChangesIsDeleted(RealmObjectChangesHandle handle) {
return _realmLib.realm_object_changes_is_deleted(handle._pointer);
}

List<int> getObjectChangesProperties(RealmObjectChangesHandle handle) {
return using((arena) {
final count = _realmLib.realm_object_changes_get_num_modified_properties(handle._pointer);

final out_modified = arena<realm_property_key_t>(count);
_realmLib.realm_object_changes_get_modified_properties(handle._pointer, out_modified, count);

return out_modified.asTypedList(count).toList();
});
}
}

class LastError {
Expand Down Expand Up @@ -653,6 +695,10 @@ class RealmCollectionChangesHandle extends Handle<realm_collection_changes> {
RealmCollectionChangesHandle._(Pointer<realm_collection_changes> pointer) : super(pointer, 256);
}

class RealmObjectChangesHandle extends Handle<realm_object_changes> {
RealmObjectChangesHandle._(Pointer<realm_object_changes> pointer) : super(pointer, 256);
}

extension _StringEx on String {
Pointer<Int8> toUtf8Ptr(Allocator allocator) {
final units = utf8.encode(this);
Expand Down
18 changes: 15 additions & 3 deletions lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export 'package:realm_common/realm_common.dart'
show Ignored, Indexed, MapTo, PrimaryKey, RealmError, RealmModel, RealmUnsupportedSetError, RealmStateError, RealmCollectionType, RealmPropertyType;
export "configuration.dart" show Configuration, RealmSchema, SchemaObject;
export 'list.dart' show RealmList, RealmListOfObject, RealmListChanges;
export 'realm_object.dart' show RealmException, RealmObject;
export 'realm_object.dart' show RealmException, RealmObject, RealmObjectChanges;
export 'realm_property.dart';
export 'results.dart' show RealmResults, RealmResultsChanges;

Expand Down Expand Up @@ -267,7 +267,7 @@ class Scheduler {
extension RealmInternal on Realm {
RealmHandle get handle => _handle;
Scheduler get scheduler => _scheduler;

RealmObject createObject(Type type, RealmObjectHandle handle) {
RealmMetadata metadata = _getMetadata(type);

Expand All @@ -279,14 +279,26 @@ extension RealmInternal on Realm {
RealmList<T> createList<T extends Object>(RealmListHandle handle) {
return RealmListInternal.create(handle, this);
}

List<String> getPropertyNames(Type type, List<int> propertyKeys) {
RealmMetadata metadata = _getMetadata(type);
final result = <String>[];
for (var key in propertyKeys) {
final name = metadata.getPropertyName(key);
if (name != null) {
result.add(name);
}
}
return result;
}
}

/// @nodoc
abstract class NotificationsController {
RealmNotificationTokenHandle? handle;

RealmNotificationTokenHandle subscribe();
void onChanges(RealmCollectionChangesHandle changesHandle);
void onChanges(Handle changesHandle);
void onError(RealmError error);

void start() {
Expand Down

0 comments on commit 8c890b7

Please sign in to comment.