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

support realm refresh() #1046

Merged
merged 26 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
be353da
support realm refresh()
blagoev Nov 29, 2022
a68e61d
fix up changelog
blagoev Nov 29, 2022
964d0a1
support refresh callback
blagoev Nov 30, 2022
bcabb3a
Merge branch 'master' into blagoev/support-refresh
blagoev Nov 30, 2022
76bcbd1
fix tests, add not called test
blagoev Nov 30, 2022
9f6de65
make operation a no op if the callback was not registered successfully
blagoev Nov 30, 2022
47631b4
fix expectation
blagoev Nov 30, 2022
87fe8c6
fix refresh callback implementation.
blagoev Nov 30, 2022
68d116d
add refreshAsync to changelog
blagoev Dec 2, 2022
b94a141
use proper future timeout
blagoev Dec 2, 2022
ef3fe59
fix test
blagoev Dec 2, 2022
456ebf5
Merge branch 'main' into blagoev/support-refresh
desistefanova Jan 13, 2023
978378d
Merge branch 'main' into blagoev/support-refresh
desistefanova Jan 26, 2023
069fcaa
Update realm in another Isolate
desistefanova Jan 27, 2023
00a4005
Disable auto refresh realm and refresh manually
desistefanova Jan 29, 2023
80099d3
Merge branch 'main' into blagoev/support-refresh
desistefanova Jan 29, 2023
fb5d158
Return result from refreshAsync
desistefanova Jan 29, 2023
24c2d76
Fix API doc
desistefanova Jan 29, 2023
a19c354
Fix API doc
desistefanova Jan 29, 2023
2a2d879
Repair a test
desistefanova Jan 29, 2023
53dd35d
Code review changes
desistefanova Jan 30, 2023
e1bcd6e
Code review changes
desistefanova Jan 30, 2023
56a97c2
Code review changes
desistefanova Jan 30, 2023
00051e0
Apply suggestions from code review
desistefanova Jan 30, 2023
f7a1944
Merge branch 'main' into blagoev/support-refresh
desistefanova Jan 30, 2023
ecd453d
Code review changes
desistefanova Jan 30, 2023
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Enhancements
* Support setting `maxNumberOfActiveVersions` when creating a `Configuration`. ([#1036](https://github.com/realm/realm-dart/pull/1036))
* Add List.move extension method that moves an element from one index to another. Delegates to ManagedRealmList.move for managed lists. This allows notifications to correctly report moves, as opposed to reporting moves as deletes + inserts. ([#1037](https://github.com/realm/realm-dart/issues/1037))
* Add `Realm.refresh()` support. ([#1046](https://github.com/realm/realm-dart/pull/1046))
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
* Support setting `shouldDeleteIfMigrationNeeded` when creating a `Configuration.local`. ([#1049](https://github.com/realm/realm-dart/issues/1049))

### Fixed
Expand Down
29 changes: 28 additions & 1 deletion lib/src/native/realm_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -764,8 +764,35 @@ class _RealmCore {
_realmLib.invokeGetBool(() => _realmLib.realm_rollback(realm.handle._pointer), "Could not rollback write");
}

void realmRefresh(Realm realm) {
bool realmRefresh(Realm realm) {
_realmLib.invokeGetBool(() => _realmLib.realm_refresh(realm.handle._pointer), "Could not refresh");
//TODO: Remove this and return the correct result of calling `realm_refresh`.
//Currently there is a bug in C-API that does not return the refresh result correctly.
//Issue https://github.com/realm/realm-core/pull/6068
blagoev marked this conversation as resolved.
Show resolved Hide resolved
return true;
}

Future<void> realmRefreshAsync(Realm realm) {
nielsenko marked this conversation as resolved.
Show resolved Hide resolved
final completer = Completer<void>();
final callback = Pointer.fromFunction<Void Function(Pointer<Void>)>(_realmRefreshAsyncCallback);
Pointer<Void> completerPtr = _realmLib.realm_dart_object_to_persistent_handle(completer);
Pointer<realm_refresh_callback_token> result = _realmLib.realm_add_realm_refresh_callback(
realm.handle._pointer, callback.cast(), completerPtr, _realmLib.addresses.realm_dart_delete_persistent_handle);

if (result == nullptr) {
return Future.value();
}

return completer.future;
}

static void _realmRefreshAsyncCallback(Pointer<Void> userdata) {
if (userdata == nullptr) {
return;
}

final completer = _realmLib.realm_dart_persistent_handle_to_object(userdata) as Completer<void>;
completer.complete();
}

RealmObjectMetadata getObjectMetadata(Realm realm, SchemaObject schema) {
Expand Down
15 changes: 15 additions & 0 deletions lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,21 @@ class Realm implements Finalizable {
realm.close();
}
}

/// Update the `Realm` instance and outstanding objects to point to the most recent persisted version.
///
/// If another process or thread has made changes to the realm file, this causes
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
/// those changes to become visible in this realm instance.
/// Typically you don't need to call this method since Realm has auto-refresh built-in.
bool refresh() {
return realmCore.realmRefresh(this);
}

/// Returns a [Future] that will complete when the `Realm` is refreshed to the version which is the
/// latest version at the time when this method is called.
Future<void> refreshAsync() {
return realmCore.realmRefreshAsync(this);
}
}

/// Provides a scope to safely write data to a [Realm]. Can be created using [Realm.beginWrite] or
Expand Down
1 change: 0 additions & 1 deletion src/realm_dart.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#include <realm/util/functional.hpp>

struct realm_dart_userdata_async {
public:
realm_dart_userdata_async(Dart_Handle handle, void* callback, realm_scheduler_t* scheduler)
: handle(Dart_NewPersistentHandle_DL(handle))
, dart_callback(callback)
Expand Down
80 changes: 74 additions & 6 deletions test/realm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1416,7 +1416,7 @@ Future<void> main([List<String>? args]) async {

Future<int> createRealmForCompact(Configuration config) async {
var realm = getRealm(config);

if (config is FlexibleSyncConfiguration) {
realm.subscriptions.update((mutableSubscriptions) {
mutableSubscriptions.add(realm.query<Product>("stringQueryField CONTAINS '$compactTest'"));
Expand All @@ -1425,7 +1425,7 @@ Future<void> main([List<String>? args]) async {
}

addDataForCompact(realm);

if (config is FlexibleSyncConfiguration) {
await realm.syncSession.waitForDownload();
await realm.syncSession.waitForUpload();
Expand All @@ -1439,7 +1439,7 @@ Future<void> main([List<String>? args]) async {

void validateCompact(bool compacted, String realmPath, int beforeCompactSizeSize) async {
expect(compacted, true);
final afterCompactSize = await File(realmPath).stat().then((value) => value.size);
final afterCompactSize = await File(realmPath).stat().then((value) => value.size);
expect(beforeCompactSizeSize, greaterThan(afterCompactSize));
}

Expand All @@ -1455,7 +1455,7 @@ Future<void> main([List<String>? args]) async {
final realm = getRealm(config);
});

test('Realm - non existing realm can not be compacted', () async {
test('Realm - non existing realm can not be compacted', () async {
var config = Configuration.local([Product.schema], path: p.join(Configuration.defaultStoragePath, "${generateRandomString(8)}.realm"));
final compacted = Realm.compact(config);
expect(compacted, false);
Expand Down Expand Up @@ -1553,8 +1553,7 @@ Future<void> main([List<String>? args]) async {
final path = p.join(Configuration.defaultStoragePath, "${generateRandomString(8)}.realm");
var user = await app.logIn(credentials);
List<int> key = List<int>.generate(encryptionKeySize, (i) => random.nextInt(256));
final config =
Configuration.flexibleSync(user, [Product.schema], encryptionKey: key, path: path);
final config = Configuration.flexibleSync(user, [Product.schema], encryptionKey: key, path: path);
final beforeCompactSize = await createRealmForCompact(config);
user.logOut();
Future<void>.delayed(Duration(seconds: 5));
Expand All @@ -1567,6 +1566,75 @@ Future<void> main([List<String>? args]) async {
//test the realm can be opened.
final realm = getRealm(Configuration.disconnectedSync([Product.schema], path: path, encryptionKey: key));
});

test('Realm.refresh', () async {
final realm = getRealm(Configuration.local([Person.schema]));
final result = realm.refresh();
expect(result, true);
});

test('Realm.onRefresh sync transaction', () async {
final realm = getRealm(Configuration.local([Person.schema]));
var called = false;
final transaction = realm.beginWrite();
realm.refreshAsync().then((_) => called = true);
realm.add(Person("name"));
transaction.commit();

await Future<void>.delayed(Duration(milliseconds: 1));
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
expect(called, true, reason: "beginWrite onRefresh failed");

called = false;
realm.write(() {
realm.refreshAsync().then((_) => called = true);
realm.add(Person("name"));
});

await Future<void>.delayed(Duration(milliseconds: 1));
expect(called, true, reason: "write onRefresh failed");
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
});

test('Realm.onRefresh async transaction', () async {
final realm = getRealm(Configuration.local([Person.schema]));
bool called = false;
final transaction = await realm.beginWriteAsync();
realm.refreshAsync().then((_) => called = true);
realm.add(Person("name"));
await transaction.commitAsync();
expect(called, true);
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
});

test('Realm.onRefresh is called if registered outside a transaction', () async {
final realm = getRealm(Configuration.local([Person.schema]));
bool called = false;

realm.refreshAsync().then((_) => called = true);

realm.beginWrite().commit();

await Future<void>.delayed(Duration(milliseconds: 1));

expect(called, true);


realm.refreshAsync().then((_) => called = true);

realm.write(() {});

await Future<void>.delayed(Duration(milliseconds: 1));

expect(called, true);
blagoev marked this conversation as resolved.
Show resolved Hide resolved
});

test('Realm.onRefresh on frozen realm should be no-op', () async {
var realm = getRealm(Configuration.local([Person.schema]));
bool called = false;
realm = realm.freeze();

await Future.any([realm.refreshAsync().then((_) => called = true), Future<void>.delayed(Duration(milliseconds: 10))]);
desistefanova marked this conversation as resolved.
Show resolved Hide resolved

expect(called, true);
blagoev marked this conversation as resolved.
Show resolved Hide resolved
});
}

List<int> generateEncryptionKey() {
Expand Down