Skip to content

Commit 641956d

Browse files
author
Kasper Overgård Nielsen
authored
RDART-1020: Fix writeAsync behaviour (#1666)
* Add test that illustrates problem with async callback to writeAsync * Fix async callback issue * Update CHANGELOG * Add assert that callback to write is not async * Handle Never, which is a subtype of any type, but not a future * Disallow async callbacks even on writeAsync * Drop new async callback tests again
1 parent 2b476a7 commit 641956d

File tree

3 files changed

+17
-2
lines changed

3 files changed

+17
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* None
55

66
### Fixed
7+
* `Realm.writeAsync` did not handle async callbacks (`Future<T> Function()`) correctly. (Issue [#1667](https://github.com/realm/realm-dart/issues/1667))
78
* 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))
89
* Fixed a regression that makes it inconvenient to run unit tests using realm. (Issue [#1619](https://github.com/realm/realm-dart/issues/1619))
910

packages/realm_dart/lib/src/realm_class.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,11 +355,15 @@ class Realm {
355355
/// Checks whether the `Realm` is in write transaction.
356356
bool get isInTransaction => handle.isWritable;
357357

358+
bool _isSubtype<S, T>() => <S>[] is List<T>;
359+
bool _isFuture<T>() => T != Never && _isSubtype<T, Future>();
360+
358361
/// Synchronously calls the provided callback inside a write transaction.
359362
///
360363
/// If no exception is thrown from within the callback, the transaction will be committed.
361364
/// It is more efficient to update several properties or even create multiple objects in a single write transaction.
362365
T write<T>(T Function() writeCallback) {
366+
assert(!_isFuture<T>(), 'writeCallback must be synchronous');
363367
final transaction = beginWrite();
364368

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

packages/realm_dart/test/realm_test.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@ void main() {
10711071
expect(realm2.all<Person>().length, 0);
10721072
});
10731073

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

1203+
test('Realm.writeAsync with async callback fails with assert', () async {
1204+
final realm = getRealm(Configuration.local([Person.schema]));
1205+
await expectLater(realm.writeAsync(() async {}), throwsA(isA<AssertionError>()));
1206+
});
1207+
1208+
test('Realm.write with async callback', () {
1209+
final realm = getRealm(Configuration.local([Person.schema]));
1210+
expect(() => realm.write(() async {}), throwsA(isA<AssertionError>()));
1211+
});
1212+
12031213
test('Transaction.commitAsync with a canceled token throws', () async {
12041214
final realm = getRealm(Configuration.local([Person.schema]));
12051215

0 commit comments

Comments
 (0)