realm-dart icon indicating copy to clipboard operation
realm-dart copied to clipboard

Open realm async

Open desistefanova opened this issue 2 years ago • 4 comments

Support async Realm open syntax. Fixes #71 Done:

  • [x] Implement Realm.open only in Dart without using C-API.
  • [x] CancellableFuture implementation.
  • [x] Update Changelog.md
  • [x] API documentation
  • [x] Add more tests for download progress.
  • [x] Test opening many realms with different configs and try to cancel one of them.

desistefanova avatar Jul 30 '22 21:07 desistefanova

I have tried to advocate that we add this functionality without involving core at all.

Here are different styles this can be implemented in pure dart:

  static Future<Realm> open(FlexibleSyncConfiguration config, [void Function(int, int)? progressCallback]) async {
    final realm = Realm(config);
    final session = realm.syncSession;
    await session
        .getProgressStream(ProgressDirection.download, ProgressMode.forCurrentlyOutstandingWork)
        .forEach((s) => progressCallback?.call(s.transferredBytes, s.transferableBytes));
    await session.waitForDownload(); // should be redundant except for bug in progress stream
    return realm;
  }

  static CancelableOperation<Realm> openReturnsCancelableOperation(FlexibleSyncConfiguration config, [void Function(int, int)? progressCallback]) =>
      CancelableOperation.fromFuture(open(config));

  static Future<Realm> openDotnetStyle(FlexibleSyncConfiguration config, {void Function(int, int)? progressCallback, Completer<void>? cancelToken}) =>
      StreamGroup.merge([
        open(config).asStream(),
        if (cancelToken != null) cancelToken.future.asStream().cast<Realm>(), // only used to cancel
      ]).first;

Personally I prefer the first. If you don't need to cancel, you just do:

final realm = await Realm.open(config)

if you just need a timeout, you do:

final realm = await Realm.open(config).timeout(duration);

If you need to be able to cancel, you do:

final op = CancelableOperation.fromFuture(Realm.open(config));
// pass op to somewhere that may call op.cancel()
final realm = await op.valueOrCancellation(null); // will return null, if cancelled 

You can say, that won't really cancel anything in core, but neither does the current PR, since download will proceed in the background no matter what, and this is very much by design.

Also, the open async api in core is buggy, in that If you cancel one operation you cancel all in-flight ops. I think the above this is much simpler. Obviously we should only support one of the 3, but I include them all to show the options.

nielsenko avatar Sep 13 '22 08:09 nielsenko

Pull Request Test Coverage Report for Build 3047873462

  • -7 of 28 (75.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+5.7%) to 92.891%

Changes Missing Coverage Covered Lines Changed/Added Lines %
lib/src/realm_class.dart 21 28 75.0%
<!-- Total: 21 28
Totals Coverage Status
Change from base Build 3036688559: 5.7%
Covered Lines: 392
Relevant Lines: 422

💛 - Coveralls

coveralls avatar Sep 13 '22 19:09 coveralls

Pull Request Test Coverage Report for Build 3273456870

  • 21 of 21 (100.0%) changed or added relevant lines in 3 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+4.1%) to 92.558%

Totals Coverage Status
Change from base Build 3273161537: 4.1%
Covered Lines: 398
Relevant Lines: 430

💛 - Coveralls

coveralls avatar Sep 13 '22 19:09 coveralls

@nielsenko Could you please check the changes now?

desistefanova avatar Oct 12 '22 17:10 desistefanova