From bbda921cc3fab8e40bbc22eb61be210864b57cf3 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Fri, 5 Jan 2024 14:07:38 +0100 Subject: [PATCH 1/2] Add MigrationRequiredException --- CHANGELOG.md | 1 + lib/src/native/realm_core.dart | 15 ++++++++++----- lib/src/realm_object.dart | 18 +++++++++++++++++- test/migration_test.dart | 6 +++++- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5e5c2e8f..0d51cbc9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ ``` The map keys may not contain `.` or start with `$`. (Issue [#685](https://github.com/realm/realm-dart/issues/685)) +* Added a new exception - `MigrationRequiredException` that will be thrown when a local Realm is opened with a schema that differs from the schema on disk and no migration callback is supplied. Additionally, a `helpLink` property has been added to `RealmException` and its subclasses to provide a link to the documentation for the error. (Issue [#1448](https://github.com/realm/realm-dart/issues/1448)) ### Fixed * Fixed warnings being emitted by the realm generator requesting that `xyz.g.dart` be included with `part 'xyz.g.dart';` for `xyz.dart` files that import `realm` but don't have realm models defined. Those should not need generated parts and including the part file would have resulted in an empty file with `// ignore_for_file: type=lint` being generated. (PR [#1443](https://github.com/realm/realm-dart/pull/1443)) diff --git a/lib/src/native/realm_core.dart b/lib/src/native/realm_core.dart index 242e11df8..bfccb4f8b 100644 --- a/lib/src/native/realm_core.dart +++ b/lib/src/native/realm_core.dart @@ -154,7 +154,13 @@ class _RealmCore { throw UserCallbackException(lastError!.userError!); } - throw RealmException('${errorMessage != null ? "$errorMessage. " : ""}${lastError ?? ""}'); + final message = '${errorMessage != null ? "$errorMessage. " : ""}${lastError ?? ""}'; + switch (lastError?.code) { + case realm_errno.RLM_ERR_SCHEMA_MISMATCH: + throw MigrationRequiredException(message); + default: + throw RealmException(message); + } }); } @@ -694,7 +700,8 @@ class _RealmCore { if (error != nullptr) { final err = arena(); bool success = _realmLib.realm_get_async_error(error, err); - completer.completeError(RealmException("Failed to open realm ${success ? err.ref.toLastError().toString() : ''}")); + final lastError = success ? err.ref.toLastError() : null; + completer.completeError(RealmException("Failed to open realm${lastError?.message ?? ''}")); return; } @@ -2888,9 +2895,7 @@ class LastError { LastError(this.code, [this.message, this.userError]); @override - String toString() { - return "Error code: $code ${(message != null ? ". Message: $message" : "")}"; - } + String toString() => message ?? ''; } // Flag to enable trace on finalization. diff --git a/lib/src/realm_object.dart b/lib/src/realm_object.dart index 6fd91b088..0741bc544 100644 --- a/lib/src/realm_object.dart +++ b/lib/src/realm_object.dart @@ -582,7 +582,10 @@ extension RealmObjectInternal on RealmObjectBase { class RealmException implements Exception { final String message; - RealmException(this.message); + /// A link to the documentation that explains how to resolve the error. + final String? helpLink; + + RealmException(this.message, {this.helpLink}); @override String toString() { @@ -590,6 +593,19 @@ class RealmException implements Exception { } } +/// An exception thrown when a Realm is opened with a different schema and a migration is required. +/// See [LocalConfiguration.migrationCallback] for more details. +class MigrationRequiredException extends RealmException { + MigrationRequiredException(String message) + : super(message, + helpLink: "https://www.mongodb.com/docs/realm/sdk/flutter/realm-database/model-data/update-realm-object-schema/#manually-migrate-schema"); + + @override + String toString() { + return "Migration required: $message. See $helpLink for more details."; + } +} + /// An exception throws during execution of a user callback - e.g. during migration or initial data population. /// {@category Realm} class UserCallbackException extends RealmException { diff --git a/test/migration_test.dart b/test/migration_test.dart index 15b7449e3..9d45307bd 100644 --- a/test/migration_test.dart +++ b/test/migration_test.dart @@ -109,7 +109,11 @@ Future main([List? args]) async { invoked = true; }); - expect(() => getRealm(config2), throws('Migration is required due to the following errors')); + expect( + () => getRealm(config2), + throwsA(isA() + .having((e) => e.message, 'message', contains('Migration is required due to the following errors')) + .having((e) => e.helpLink, 'helpLink', isNotNull))); expect(invoked, false); }); From d347441c0ef9f867b67fb80e1ae4ec970e8c9908 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Fri, 5 Jan 2024 16:33:07 +0100 Subject: [PATCH 2/2] Re-include the error code in the error message --- lib/src/native/realm_core.dart | 2 +- test/app_test.dart | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/src/native/realm_core.dart b/lib/src/native/realm_core.dart index bfccb4f8b..ed42cea62 100644 --- a/lib/src/native/realm_core.dart +++ b/lib/src/native/realm_core.dart @@ -2895,7 +2895,7 @@ class LastError { LastError(this.code, [this.message, this.userError]); @override - String toString() => message ?? ''; + String toString() => "${message ?? 'No message'}. Error code: $code."; } // Flag to enable trace on finalization. diff --git a/test/app_test.dart b/test/app_test.dart index edd0d6a4e..531f17906 100644 --- a/test/app_test.dart +++ b/test/app_test.dart @@ -19,9 +19,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:isolate'; -import 'dart:math'; import 'package:logging/logging.dart'; -import 'package:meta/meta.dart'; import 'package:test/expect.dart' hide throws; import 'package:path/path.dart' as path; import 'package:crypto/crypto.dart'; @@ -294,7 +292,7 @@ Future main([List? args]) async { expect(app.currentUser, user2); expect( () => app.switchUser(user1), - throws("Switch user failed. Error code: 4101 . Message: User is no longer valid or is logged out"), + throws("Switch user failed. User is no longer valid or is logged out"), ); });