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

RDART-1020: Fix writeAsync behaviour #1666

Merged
merged 7 commits into from
May 30, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* None

### Fixed
* `Realm.writeAsync` did not handle async callbacks (`Future<T> Function()`) correctly. (Issue [#1667](https://github.com/realm/realm-dart/issues/1667))
* Fixed an issue that would cause macOS apps to be rejected with `Invalid Code Signing Entitlements` error. (Issue [#1679](https://github.com/realm/realm-dart/issues/1679))
* Fixed a regression that makes it inconvenient to run unit tests using realm. (Issue [#1619](https://github.com/realm/realm-dart/issues/1619))

Expand Down
6 changes: 5 additions & 1 deletion packages/realm_dart/lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -355,11 +355,15 @@ class Realm {
/// Checks whether the `Realm` is in write transaction.
bool get isInTransaction => handle.isWritable;

bool _isSubtype<S, T>() => <S>[] is List<T>;
bool _isFuture<T>() => T != Never && _isSubtype<T, Future>();

/// Synchronously calls the provided callback inside a write transaction.
///
/// If no exception is thrown from within the callback, the transaction will be committed.
/// It is more efficient to update several properties or even create multiple objects in a single write transaction.
T write<T>(T Function() writeCallback) {
assert(!_isFuture<T>(), 'writeCallback must be synchronous');
final transaction = beginWrite();

try {
Expand Down Expand Up @@ -388,8 +392,8 @@ class Realm {
/// Executes the provided [writeCallback] in a temporary write transaction. Both acquiring the write
/// lock and committing the transaction will be done asynchronously.
Future<T> writeAsync<T>(T Function() writeCallback, [CancellationToken? cancellationToken]) async {
assert(!_isFuture<T>(), 'writeCallback must be synchronous');
final transaction = await beginWriteAsync(cancellationToken);

try {
T result = writeCallback();
await transaction.commitAsync(cancellationToken);
Expand Down
12 changes: 11 additions & 1 deletion packages/realm_dart/test/realm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ void main() {
expect(realm2.all<Person>().length, 0);
});

test("Realm.writeAsync with multiple transactions doesnt't deadlock", () async {
test("Realm.writeAsync with multiple transactions doesn't deadlock", () async {
final realm = getRealm(Configuration.local([Person.schema]));
final t1 = await realm.beginWriteAsync();
realm.add(Person('Marco'));
Expand Down Expand Up @@ -1200,6 +1200,16 @@ void main() {
expect(realm.isInTransaction, false);
});

test('Realm.writeAsync with async callback fails with assert', () async {
final realm = getRealm(Configuration.local([Person.schema]));
await expectLater(realm.writeAsync(() async {}), throwsA(isA<AssertionError>()));
});

test('Realm.write with async callback', () {
final realm = getRealm(Configuration.local([Person.schema]));
expect(() => realm.write(() async {}), throwsA(isA<AssertionError>()));
});

test('Transaction.commitAsync with a canceled token throws', () async {
final realm = getRealm(Configuration.local([Person.schema]));

Expand Down
Loading