Skip to content

Commit

Permalink
RDART-930: Refactor handles (#1550)
Browse files Browse the repository at this point in the history
* Refactor handles subscription.dart

* Refactor: use import over part for handle_base.dart

* Fix regression: Check if close on handle deref

* TMP: Skip some tests (something broke with RootedHandle)

* Ups!

* Wip

* After rebase

* wip

* Fix after rebase

* Revert "TMP: Skip some tests (something broke with RootedHandle)"

This reverts commit 5081217.

* Use dart_test.yaml to configure tags. Make baas a tag instead of a prefix. Simplify

* Fix nullPtr related bug

* Doh! I'll go die in shame!!

* Refactor RealmHandle

* Refactor ConfigHandle

* Refactor _RealmQueryHandler (now QueryHandle)

* Refactor RealmObjectHandle (now ObjectHandle)

* Refactor RealmResultHandle (now ResultsHandle)

* More RealmHandle stuff

* Don't need Tuple

* Expose disableAutoRefreshForTesting

* Refactor UserHandle

* RealmHandle.findAll

* Realm.find/.findExiting/.renameProperty

* Drop superfluous this.

* Refactor AppHandle

* Refactor SchedulerHandle

* Move config handles

* Refactor SessionHandle

* UserHandle.linkCredentials/.createApiKey/.fetchApiKey/.fetchAllApiKeys.deleteApiKey/.disableApiKey/.enableApiKey

* Refactor RealmListHandle (now ListHandle)

* Refactor RealmSetHandle (now SetHandle)

* Refactor RealmAppCredentialsHandle (now CredentialsHandle)

* WIP

* WIP2

* Organize imports

* ResultsHandle stuff

* More UserHandle stuff

* subscribeForSchemaNotification (something rubs me the wrong way about this)

* Move MapHandle.query

* More ObjectHandle stuff

* Move callback functions into handle files

* Move resolveX to XHandle.resolveIn

* Make a bunch of function public in prep for getting rid of parts

* Refactor XChangesHandle

* Use CredentialsHandle not Credentils

* Traffic in ResultsHandle not RealmResult + dart fix stuff

* Split part files

* Move XTokenHandles

* toNative extension method replaces toRealmValue function

* Replace last use of deprecated Pointer.elementAt(i)

* More RealmHandle stuff

* Replace invokeGetBool and invokeGetPointer

* Run melos custom_format

* Move callAppFunction stuff

* Refactor equals

* Move raiseIfNull to HandleBase ctor. Rename to be explicit about call to getLastError

* Completely unrelated spelling corrections in CHANGELOG

* Seperate AsyncOpenTaskHandle and NotificationHandle from realm_core.dart

* moving guardSynchronousCallback and getApp out of realm_core.dart

* Split native convertion functions into separate files

* Last leg.. for now

* PR feedback

* Fix rebase

* Tweat memEquals perf test

* fixup! Last leg.. for now

* Fix after rebase

* more PR feedback
  • Loading branch information
nielsenko authored May 27, 2024
1 parent 14c7bd6 commit 5e4e6a7
Show file tree
Hide file tree
Showing 69 changed files with 4,642 additions and 4,245 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"geospatial",
"HRESULT",
"keepalive",
"keypaths",
"loggable",
"maccatalyst",
"mugaritz",
Expand Down
14 changes: 7 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
* Fixed a `DecryptionFailed` exception thrown when opening a small (<4k of data) Realm generated on a device with a page size of 4k if it was bundled and opened on a device with a larger page size.
* Fixed an issue during a subsequent open of an encrypted Realm for some rare allocation patterns when the top ref was within ~50 bytes of the end of a page. This could manifest as a DecryptionFailed exception or as an assertion: `encrypted_file_mapping.hpp:183: Assertion failed: local_ndx < m_page_state.size()`.
* Schema initialization could hit an assertion failure if the sync client applied a downloaded changeset while the Realm file was in the process of being opened. (Core 14.6.0)
* Improve perfomance of "chained OR equality" queries for UUID/ObjectId types and RQL parsed "IN" queries on string/int/uuid/objectid types. (Core 14.6.0)
* Improve performance of "chained OR equality" queries for UUID/ObjectId types and RQL parsed "IN" queries on string/int/uuid/objectid types. (Core 14.6.0)
* Fixed a bug when running a IN query (or a query of the pattern `x == 1 OR x == 2 OR x == 3`) when evaluating on a string property with an empty string in the search condition. Matches with an empty string would have been evaluated as if searching for a null string instead. (Core 14.6.2)

### Compatibility
Expand Down Expand Up @@ -184,9 +184,9 @@
```
* Removed `SchemaObject.properties` - instead, `SchemaObject` is now an iterable collection of `Property`. (Issue [#1449](https://github.com/realm/realm-dart/issues/1449))
* `SyncProgress.transferredBytes` and `SyncProgress.transferableBytes` have been consolidated into `SyncProgress.progressEstimate`. The values reported previously were incorrect and did not accurately represent bytes either. The new field better conveys the uncertainty around the progress being reported. With this release, we're reporting accurate estimates for upload progress, but estimating downloads is still unreliable. A future server and SDK release will add better estimations for download progress. (Issue [#1562](https://github.com/realm/realm-dart/issues/1562))
* `Realm.logger` is no longer settable, and no longer implements `Logger` from package `logging`. In particular you can no longer call `Realm.logger.level =`. Instead you should call `Realm.logger.setLogLevel(RealmLogLevel level, {RealmLogCategory? category})` that takes an optional category. If no category is exlicitly given, then `RealmLogCategory.realm` is assumed.
* `Realm.logger` is no longer settable, and no longer implements `Logger` from package `logging`. In particular you can no longer call `Realm.logger.level =`. Instead you should call `Realm.logger.setLogLevel(RealmLogLevel level, {RealmLogCategory? category})` that takes an optional category. If no category is explicitly given, then `RealmLogCategory.realm` is assumed.

Also, note that setting a level is no longer local to the current isolate, but shared accross all isolates. At the core level there is just one process wide logger.
Also, note that setting a level is no longer local to the current isolate, but shared across all isolates. At the core level there is just one process wide logger.

Categories form a hierarchy and setting the log level of a parent category will override the level of its children. The hierarchy is exposed in a type safe manner with:
```dart
Expand Down Expand Up @@ -928,7 +928,7 @@ class _Address {
* Queries on results didn't filter the existing results. ([#908](https://github.com/realm/realm-dart/issues/908)).
Example
```dart
expect(realm.query<Person>('FALSEPREDICATE').query('TRUEPREDICATE'), isEmpty); //<-- Fails if a Persion object exists
expect(realm.query<Person>('FALSEPREDICATE').query('TRUEPREDICATE'), isEmpty); //<-- Fails if a Person object exists
```
* Fixed copying of native structs for session errors and http requests. ([#924](https://github.com/realm/realm-dart/pull/924))
* Fixed a crash when closing the SyncSession on App instance teardown. ([#5752](https://github.com/realm/realm-core/issues/5752))
Expand Down Expand Up @@ -1091,7 +1091,7 @@ class _Address {

```dart
final subscription = realm.all<Dog>().changes.listen((changes) {
changes.inserted // indexes of inserted ojbects
changes.inserted // indexes of inserted objects
changes.modified // indexes of modified objects
changes.deleted // indexes of deleted objects
changes.newModified // indexes of modified objects after deletions and insertions are accounted for.
Expand Down Expand Up @@ -1231,7 +1231,7 @@ Notes: This release is a prerelease version. All API's might change without warn
Notes: This release is a prerelease version. All API's might change without warning and no guarantees are given about stability.
### Enhancements
* Completеly rewritten from the ground up with sound null safety and using Dart FFI
* Completely rewritten from the ground up with sound null safety and using Dart FFI
### Fixed
* Realm close stops internal scheduler.
Expand All @@ -1247,7 +1247,7 @@ Notes: This release is a prerelease version. All API's might change without warn
Notes: This release is a prerelease version. All API's might change without warning and no guarantees are given about stability.
### Enhancements
* Completеly rewritten from the ground up with sound null safety and using Dart FFI
* Completely rewritten from the ground up with sound null safety and using Dart FFI
### Compatibility
* Dart ^2.15 on Windows, MacOS and Linux
Expand Down
1 change: 0 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ linter:
rules:
avoid_relative_lib_imports: false
package_api_docs: true
dangling_library_doc_comments: false

# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
Expand Down
2 changes: 1 addition & 1 deletion packages/realm/bin/realm.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2021 MongoDB, Inc.
// SPDX-License-Identifier: Apache-2.0


import 'package:realm_dart/src/cli/main.dart' as x;

void main(List<String> arguments) => x.main(arguments);
8 changes: 0 additions & 8 deletions packages/realm_common/lib/src/realm_common_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,3 @@ class Backlink {
final Symbol fieldName;
const Backlink(this.fieldName);
}

/// @nodoc
class Tuple<T1, T2> {
T1 item1;
T2 item2;

Tuple(this.item1, this.item2);
}
10 changes: 5 additions & 5 deletions packages/realm_common/lib/src/realm_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ enum RealmCollectionType {
map;

String get plural => switch (this) {
RealmCollectionType.list => 'lists',
RealmCollectionType.set => 'sets',
RealmCollectionType.map => 'maps',
_ => 'none'
};
RealmCollectionType.list => 'lists',
RealmCollectionType.set => 'sets',
RealmCollectionType.map => 'maps',
_ => 'none',
};
}

/// A base class of all Realm errors.
Expand Down
2 changes: 1 addition & 1 deletion packages/realm_dart/bin/realm_dart.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2021 MongoDB, Inc.
// SPDX-License-Identifier: Apache-2.0


import 'package:realm_dart/src/cli/main.dart' as x;

void main(List<String> arguments) => x.main(arguments);
2 changes: 2 additions & 0 deletions packages/realm_dart/dart_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tags:
baas: { timeout: 2x }
29 changes: 15 additions & 14 deletions packages/realm_dart/lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import 'dart:io';
import 'dart:isolate';

import 'package:meta/meta.dart';
import 'package:path/path.dart' as _path;
import 'package:path/path.dart' as path;

import '../realm.dart';
import 'credentials.dart';
import 'logging.dart';
import 'native/app_handle.dart';
import 'native/realm_core.dart';
import 'user.dart';

Expand Down Expand Up @@ -125,7 +126,7 @@ class AppConfiguration {
this.maxConnectionTimeout = const Duration(minutes: 2),
HttpClient? httpClient,
}) : baseUrl = baseUrl ?? Uri.parse(realmCore.getDefaultBaseUrl()),
baseFilePath = baseFilePath ?? Directory(_path.dirname(Configuration.defaultRealmPath)),
baseFilePath = baseFilePath ?? Directory(path.dirname(Configuration.defaultRealmPath)),
httpClient = httpClient ?? _defaultClient {
if (appId == '') {
throw RealmException('Supplied appId must be a non-empty value');
Expand All @@ -144,7 +145,7 @@ class App implements Finalizable {

/// The id of this application. This is the same as the appId in the [AppConfiguration] used to
/// create this [App].
String get id => realmCore.appGetId(this);
String get id => handle.id;

/// Create an app with a particular [AppConfiguration]. This constructor should only be used on the main isolate and,
/// ideally, only once as soon as the app starts.
Expand All @@ -163,26 +164,26 @@ class App implements Finalizable {
/// on the main isolate. If an App hasn't been already constructed with the same id, will return null. This method is safe to call
/// on a background isolate.
static App? getById(String id, {Uri? baseUrl}) {
final handle = realmCore.getApp(id, baseUrl?.toString());
final handle = AppHandle.get(id, baseUrl?.toString());
return handle == null ? null : App._(handle);
}

App._(this._handle);

static AppHandle _createApp(AppConfiguration configuration) {
configuration.baseFilePath.createSync(recursive: true);
return realmCore.createApp(configuration);
return AppHandle.from(configuration);
}

/// Logs in a user with the given credentials.
Future<User> logIn(Credentials credentials) async {
var userHandle = await realmCore.logIn(this, credentials);
var userHandle = await handle.logIn(credentials.handle);
return UserInternal.create(userHandle, this);
}

/// Gets the currently logged in [User]. If none exists, `null` is returned.
User? get currentUser {
final userHandle = realmCore.getCurrentUser(_handle);
final userHandle = _handle.currentUser;
if (userHandle == null) {
return null;
}
Expand All @@ -191,30 +192,30 @@ class App implements Finalizable {

/// Gets all currently logged in users.
Iterable<User> get users {
return realmCore.getUsers(this).map((handle) => UserInternal.create(handle, this));
return handle.users.map((handle) => UserInternal.create(handle, this));
}

/// Removes a [user] and their local data from the device. If the user is logged in, they will be logged out in the process.
Future<void> removeUser(User user) async {
return await realmCore.removeUser(this, user);
return await handle.removeUser(user.handle);
}

/// Deletes a user and all its data from the device as well as the server.
Future<void> deleteUser(User user) async {
return await realmCore.deleteUser(this, user);
return await handle.deleteUser(user.handle);
}

/// Switches the [currentUser] to the one specified in [user].
void switchUser(User user) {
realmCore.switchUser(this, user);
handle.switchUser(user.handle);
}

/// Provide a hint to this app's sync client to reconnect.
/// Useful when the device has been offline and then receives a network reachability update.
///
/// The sync client will always attempt to reconnect eventually, this is just a hint.
void reconnect() {
realmCore.reconnect(this);
handle.reconnect();
}

/// Returns the current value of the base URL used to communicate with the server.
Expand All @@ -223,7 +224,7 @@ class App implements Finalizable {
/// be updated with the new value until that operation has completed.
@experimental
Uri get baseUrl {
return Uri.parse(realmCore.getBaseUrl(this));
return Uri.parse(handle.baseUrl);
}

/// Temporarily overrides the [baseUrl] value from [AppConfiguration] with a new [baseUrl] value
Expand All @@ -237,7 +238,7 @@ class App implements Finalizable {
/// The App will revert to using the value in [AppConfiguration] when it is restarted.
@experimental
Future<void> updateBaseUrl(Uri? baseUrl) async {
return await realmCore.updateBaseUrl(this, baseUrl);
return await handle.updateBaseUrl(baseUrl);
}

/// Returns an instance of [EmailPasswordAuthProvider]
Expand Down
1 change: 0 additions & 1 deletion packages/realm_dart/lib/src/cli/common/archive.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright 2021 MongoDB, Inc.
// SPDX-License-Identifier: Apache-2.0

///
import 'dart:io';
import 'package:tar/tar.dart';
import 'package:path/path.dart' as path;
Expand Down
2 changes: 1 addition & 1 deletion packages/realm_dart/lib/src/cli/common/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ extension StringEx on String {

bool isRealmCI = Platform.environment['REALM_CI'] != null;

FutureOr<T?> safe<T>(FutureOr<T> Function() f, {String message = 'Ignoring error', Function(Object e, StackTrace s)? onError}) async {
FutureOr<T?> safe<T>(FutureOr<T> Function() f, {String message = 'Ignoring error', void Function(Object e, StackTrace s)? onError}) async {
try {
return await f();
} catch (e, s) {
Expand Down
8 changes: 3 additions & 5 deletions packages/realm_dart/lib/src/collections.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import 'dart:ffi';
import 'native/realm_core.dart';
import 'native/collection_changes_handle.dart';

/// Contains index information about objects that moved within the same collection.
class Move {
Expand Down Expand Up @@ -47,13 +47,11 @@ class MapChanges {

/// Describes the changes in a Realm collection since the last time the notification callback was invoked.
class RealmCollectionChanges implements Finalizable {
final RealmCollectionChangesHandle _handle;
CollectionChanges? _values;
final CollectionChangesHandle _handle;
late final CollectionChanges _changes = _handle.changes;

RealmCollectionChanges(this._handle);

CollectionChanges get _changes => _values ??= realmCore.getCollectionChanges(_handle);

/// The indexes in the previous version of the collection which have been removed from this one.
List<int> get deleted => _changes.deletions;

Expand Down
15 changes: 10 additions & 5 deletions packages/realm_dart/lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ import 'dart:io';

// ignore: no_leading_underscores_for_library_prefixes
import 'package:path/path.dart' as _path;

import 'app.dart';
import 'init.dart';
import 'logging.dart';
import 'native/from_native.dart';
import 'native/realm_core.dart';
import 'realm_class.dart';
import 'init.dart';
import 'user.dart';

const encryptionKeySize = 64;

/// The signature of a callback used to determine if compaction
/// should be attempted.
///
Expand Down Expand Up @@ -225,8 +230,8 @@ abstract class Configuration implements Finalizable {
return;
}

if (key.length != realmCore.encryptionKeySize) {
throw RealmException("Wrong encryption key size (must be ${realmCore.encryptionKeySize}, but was ${key.length})");
if (key.length != encryptionKeySize) {
throw RealmException("Wrong encryption key size (must be $encryptionKeySize, but was ${key.length})");
}

int notAByteElement = key.firstWhere((e) => e > 255, orElse: () => -1);
Expand Down Expand Up @@ -368,7 +373,7 @@ class FlexibleSyncConfiguration extends Configuration {
}) : super._();

@override
String get _defaultPath => realmCore.getPathForUser(user);
String get _defaultPath => user.handle.path;
}

extension FlexibleSyncConfigurationInternal on FlexibleSyncConfiguration {
Expand Down Expand Up @@ -653,7 +658,7 @@ class ClientResetError extends SyncError {
throw RealmException("Missing `originalFilePath`");
}

return realmCore.immediatelyRunFileActions(_app!, originalFilePath!);
return _app.handle.resetRealm(originalFilePath!);
}
}

Expand Down
Loading

0 comments on commit 5e4e6a7

Please sign in to comment.