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

Compensating write error details #1291

Merged
merged 78 commits into from
Jun 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
e8219f2
reading ompensating writers
desistefanova May 18, 2023
9bcd009
Merge branch 'main' into ds/compensating_write_error_details
desistefanova May 25, 2023
0fe2315
Merge branch 'main' into ds/compensating_write_error_details
desistefanova May 25, 2023
0256377
SyncError details implementation
desistefanova May 26, 2023
41d9189
Extend the test for compensatingWrite
desistefanova May 26, 2023
60feb81
update changelog
desistefanova May 26, 2023
3662acd
ClientResetError details
desistefanova May 26, 2023
5064f1b
Fix the message text
desistefanova May 26, 2023
444eda9
Update changelog
desistefanova May 26, 2023
6b0c5d5
Detailed message added
desistefanova May 26, 2023
6b457b2
Update changelog
desistefanova May 26, 2023
79bde07
Refactor realm_core methods
desistefanova May 26, 2023
b381db8
fix changelog
desistefanova May 26, 2023
c140f05
Code review changes
desistefanova May 30, 2023
64df956
Update lib/src/native/realm_core.dart
desistefanova May 30, 2023
b11d845
function renamed
desistefanova May 30, 2023
744190a
Code review changes
desistefanova May 30, 2023
4cd98a7
Code review changes
desistefanova May 30, 2023
4f249c8
ObjectId bytes size constant
desistefanova May 30, 2023
1b95699
Code review changes
desistefanova May 30, 2023
a2eb435
Fix the native build
desistefanova May 30, 2023
ea068bd
Merge branch 'main' into ds/compensating_write_error_details
desistefanova May 30, 2023
a5be0e7
Update changelog
desistefanova May 30, 2023
c37d061
Fix Instance(length:17) of '_GrowableList'
desistefanova May 30, 2023
cebbea1
Fix toDartValue function
desistefanova Jun 1, 2023
8778292
Fix toDartValue function
desistefanova Jun 1, 2023
4b2608b
Merge branch 'main' into ds/compensating_write_error_details
desistefanova Jun 2, 2023
264c276
Fix after merge
desistefanova Jun 2, 2023
6c8a2df
Update CHANGELOG.md
desistefanova Jun 5, 2023
42fe489
Update CHANGELOG.md
desistefanova Jun 5, 2023
3e69943
Update CHANGELOG.md
desistefanova Jun 5, 2023
a6d4bd7
Update lib/src/configuration.dart
desistefanova Jun 5, 2023
c86c20e
Code review changes
desistefanova Jun 5, 2023
f2aa4a3
Merge branch 'ds/compensating_write_error_details' of https://github.…
desistefanova Jun 5, 2023
60566f9
detailedMessage named parameter for base class
desistefanova Jun 5, 2023
ac7bc51
Code review changes
desistefanova Jun 5, 2023
7589f22
Code review changes
desistefanova Jun 5, 2023
2ea9b5f
Code review changes
desistefanova Jun 5, 2023
59c09ab
Merge branch 'main' into ds/compensating_write_error_details
desistefanova Jun 7, 2023
ef46439
Move SyncError.create to _RealmCore.dart
desistefanova Jun 7, 2023
08ac1c1
Code review changes
desistefanova Jun 7, 2023
268aa96
Changelog update
desistefanova Jun 7, 2023
0a3e08a
Update changelog
desistefanova Jun 7, 2023
12d32d6
Force update
desistefanova Jun 7, 2023
953332c
force update
desistefanova Jun 7, 2023
f453b9b
Merge branch 'main' into ds/compensating_write_error_details
desistefanova Jun 8, 2023
f16a92a
Merge branch 'main' into ds/compensating_write_error_details
desistefanova Jun 9, 2023
5d999a1
Fix ClientResetError
desistefanova Jun 12, 2023
789fcde
Code review changes
desistefanova Jun 15, 2023
36e1b82
Update test/client_reset_test.dart
desistefanova Jun 15, 2023
e7d36e5
Update lib/src/configuration.dart
desistefanova Jun 15, 2023
fb45fcd
Update CHANGELOG.md
desistefanova Jun 15, 2023
275adfe
fix ClientResetError params
desistefanova Jun 15, 2023
987bdc7
Merge branch 'ds/compensating_write_error_details' of https://github.…
desistefanova Jun 15, 2023
d13044c
Refactor _createSyncError
desistefanova Jun 16, 2023
8fd315e
Automatic client reset and session errors
desistefanova Jun 16, 2023
76bf609
Update changelog and toUserInfo
desistefanova Jun 16, 2023
fd67dd5
Merge branch 'main' into ds/compensating_write_error_details
desistefanova Jun 16, 2023
b85af1b
properties reordered
desistefanova Jun 16, 2023
6df68f8
rename a class
desistefanova Jun 16, 2023
56d0c7d
Removed breacking changes
desistefanova Jun 19, 2023
8581373
Fix API text
desistefanova Jun 19, 2023
a90e31a
Fixes
desistefanova Jun 19, 2023
3251403
retuned old code of deprecated method
desistefanova Jun 19, 2023
f38798e
Code formatting
desistefanova Jun 19, 2023
6cc0e07
Fix tests
desistefanova Jun 19, 2023
ac7aacf
Nullable compensatingWrites
desistefanova Jun 19, 2023
35c8a36
Simplify getting recoveryFilePathKey
desistefanova Jun 19, 2023
b17a183
Introduce breaking changes only in the the `ClientResetError` constru…
desistefanova Jun 20, 2023
1f8305a
Merge branch 'ds/compensating_write_error_details' of https://github.…
desistefanova Jun 20, 2023
63a2e63
Merge branch 'main' into ds/compensating_write_error_details
desistefanova Jun 20, 2023
02906b9
Fix errors after merge
desistefanova Jun 20, 2023
6c2d70b
Deprecate SyncError constructors
desistefanova Jun 20, 2023
c790b64
Update changelog
desistefanova Jun 20, 2023
1d6d787
Merge branch 'main' into ds/compensating_write_error_details
desistefanova Jun 20, 2023
7a61816
Update lib/src/configuration.dart
desistefanova Jun 21, 2023
0a97ebb
Merge branch 'main' into ds/compensating_write_error_details
desistefanova Jun 21, 2023
b5be0e8
Remove redundant files
desistefanova Jun 21, 2023
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
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
## vNext (TBD)

### Enhancements
* None
* Added support binary data type. ([#1320](https://github.com/realm/realm-dart/pull/1320))
* Extended `ClientResetError` to return the `backupFilePath` where the backup copy of the realm will be placed once the client reset process has completed. ([#1291](https://github.com/realm/realm-dart/pull/1291))
* Added `CompensatingWriteError` containing detailed error information about the writes that have been reverted by the server due to permissions or subscription view restrictions. The `Configuration.flexibleSync.syncErrorHandler` will be invoked with this error type when this error occurs ([#1291](https://github.com/realm/realm-dart/pull/1291)).

### Fixed
* The constructors of all `SyncError` types are deprecated. The sync errors will be created only internally ([#1291](https://github.com/realm/realm-dart/pull/1291)).
* Getting `Backlink` properties of unmanaged Realm objects will throw an error: "Using backlinks is only possible for managed objects" ([#1293](https://github.com/realm/realm-dart/pull/1293)).
* Properties in the frozen _before_ Realm instance in the client reset callbacks may have had properties reordered which could lead to exceptions if accessed. (Core upgrade, since v13.11.0)

Expand All @@ -18,7 +21,6 @@
## 1.2.0 (2023-06-08)

### Enhancements
* Added support binary data type. ([#1320](https://github.com/realm/realm-dart/pull/1320))
* Added support for Full-Text search (simple term) queries. ([#1300](https://github.com/realm/realm-dart/pull/1300))
* To enable FTS queries on string properties, add the `@Indexed(RealmIndexType.fullText)` annotation.
* To run queries, use the `TEXT` operator: `realm.all<Book>().query("description TEXT \$0", "fantasy novel")`.
Expand Down
168 changes: 153 additions & 15 deletions lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -600,15 +600,42 @@ enum ClientResyncModeInternal {
/// An error type that describes a client reset error condition.
/// {@category Sync}
class ClientResetError extends SyncError {
final App? _app;

/// If true the received error is fatal.
final bool isFatal = true;
// The instance of [Configuration] that [ClientResetError] is thrown for.
final Configuration? _config;

/// The path to the original copy of the realm when the client reset was triggered.
/// This realm may contain unsynced changes.
final String? originalFilePath;

/// The path where the backup copy of the realm will be placed once the client reset process is complete.
final String? backupFilePath;

/// The [ClientResetError] has error code of [SyncClientErrorCode.autoClientResetFailure]
SyncClientErrorCode get code => SyncClientErrorCode.autoClientResetFailure;
/// when a client reset fails and `onManualResetFallback` occurs. Otherwise, it is [SyncClientErrorCode.unknown]
SyncClientErrorCode get code => SyncClientErrorCode.fromInt(codeValue);

ClientResetError(String message, [this._config]) : super(message, SyncErrorCategory.client, SyncClientErrorCode.autoClientResetFailure.code);
/// The [SyncSessionErrorCode] value indicating the type of the sync error.
/// This property will be [SyncSessionErrorCode.unknown] if `onManualResetFallback` occurs on client reset.
SyncSessionErrorCode get sessionErrorCode => SyncSessionErrorCode.fromInt(codeValue);

@Deprecated("ClientResetError constructor is deprecated and will be removed in the future")
ClientResetError(
String message, {
App? app,
SyncErrorCategory category = SyncErrorCategory.client,
int? errorCodeValue,
this.backupFilePath,
this.originalFilePath,
String? detailedMessage,
}) : _app = app,
super(
message,
category,
errorCodeValue ?? SyncClientErrorCode.autoClientResetFailure.code,
detailedMessage: detailedMessage,
);

@override
String toString() {
Expand All @@ -619,11 +646,13 @@ class ClientResetError extends SyncError {
///
/// Returns `true` if actions were run successfully, `false` otherwise.
bool resetRealm() {
if (_config is! FlexibleSyncConfiguration) {
throw RealmException("The current configuration is not FlexibleSyncConfiguration.");
if (_app == null) {
throw RealmException("This `ClientResetError` does not have an `Application` instance.");
}
if (originalFilePath == null) {
throw RealmException("Missing `originalFilePath`");
}
final flexibleConfig = _config as FlexibleSyncConfiguration;
return realmCore.immediatelyRunFileActions(flexibleConfig.user.app, flexibleConfig.path);
return realmCore.immediatelyRunFileActions(_app!, originalFilePath!);
}
}

Expand All @@ -636,9 +665,15 @@ class SyncError extends RealmError {
/// The category of the sync error
final SyncErrorCategory category;

SyncError(String message, this.category, this.codeValue) : super(message);
/// Detailed error message.
/// In case of server error, it contains the link to the server log.
final String? detailedMessage;

@Deprecated("SyncError constructor is deprecated and will be removed in the future")
SyncError(String message, this.category, this.codeValue, {this.detailedMessage}) : super(message);

/// Creates a specific type of [SyncError] instance based on the [category] and the [code] supplied.
@Deprecated("This method is deprecated and will be removed in the future")
static SyncError create(String message, SyncErrorCategory category, int code, {bool isFatal = false}) {
switch (category) {
case SyncErrorCategory.client:
Expand Down Expand Up @@ -678,12 +713,14 @@ class SyncClientError extends SyncError {
/// The [SyncClientErrorCode] value indicating the type of the sync error.
SyncClientErrorCode get code => SyncClientErrorCode.fromInt(codeValue);

@Deprecated("SyncClientError constructor is deprecated and will be removed in the future")
SyncClientError(
String message,
SyncErrorCategory category,
SyncClientErrorCode errorCode, {
String? detailedMessage,
this.isFatal = false,
}) : super(message, category, errorCode.code);
}) : super(message, category, errorCode.code, detailedMessage: detailedMessage);

@override
String toString() {
Expand All @@ -700,12 +737,14 @@ class SyncConnectionError extends SyncError {
/// The [SyncConnectionErrorCode] value indicating the type of the sync error.
SyncConnectionErrorCode get code => SyncConnectionErrorCode.fromInt(codeValue);

@Deprecated("SyncConnectionError constructor is deprecated and will be removed in the future")
SyncConnectionError(
String message,
SyncErrorCategory category,
SyncConnectionErrorCode errorCode, {
String? detailedMessage,
this.isFatal = false,
}) : super(message, category, errorCode.code);
}) : super(message, category, errorCode.code, detailedMessage: detailedMessage);

@override
String toString() {
Expand All @@ -722,12 +761,14 @@ class SyncSessionError extends SyncError {
/// The [SyncSessionErrorCode] value indicating the type of the sync error.
SyncSessionErrorCode get code => SyncSessionErrorCode.fromInt(codeValue);

@Deprecated("SyncSessionError constructor is deprecated and will be removed in the future")
SyncSessionError(
String message,
SyncErrorCategory category,
SyncSessionErrorCode errorCode, {
String? detailedMessage,
this.isFatal = false,
}) : super(message, category, errorCode.code);
}) : super(message, category, errorCode.code, detailedMessage: detailedMessage);

@override
String toString() {
Expand All @@ -744,7 +785,11 @@ class SyncResolveError extends SyncError {
/// The numeric value indicating the type of the network resolution sync error.
SyncResolveErrorCode get code => SyncResolveErrorCode.fromInt(codeValue);

SyncResolveError(String message, SyncErrorCategory category, SyncResolveErrorCode errorCode) : super(message, category, errorCode.index);
SyncResolveError(
blagoev marked this conversation as resolved.
Show resolved Hide resolved
String message,
SyncErrorCategory category,
SyncResolveErrorCode errorCode,
) : super(message, category, errorCode.index);

@override
String toString() {
Expand All @@ -757,7 +802,13 @@ class SyncWebSocketError extends SyncError {
/// The numeric value indicating the type of the web socket error.
SyncWebSocketErrorCode get code => SyncWebSocketErrorCode.fromInt(codeValue);

SyncWebSocketError(String message, SyncErrorCategory category, SyncWebSocketErrorCode errorCode) : super(message, category, errorCode.code);
@Deprecated("SyncWebSocketError constructor is deprecated and will be removed in the future")
SyncWebSocketError(
String message,
SyncErrorCategory category,
SyncWebSocketErrorCode errorCode, {
String? detailedMessage,
}) : super(message, category, errorCode.code, detailedMessage: detailedMessage);

@override
String toString() {
Expand All @@ -770,7 +821,13 @@ class GeneralSyncError extends SyncError {
/// The numeric value indicating the type of the general sync error.
int get code => codeValue;

GeneralSyncError(String message, SyncErrorCategory category, int code) : super(message, category, code);
@Deprecated("GeneralSyncError constructor is deprecated and will be removed in the future")
GeneralSyncError(
String message,
SyncErrorCategory category,
int code, {
String? detailedMessage,
}) : super(message, category, code, detailedMessage: detailedMessage);

@override
String toString() {
Expand All @@ -792,3 +849,84 @@ enum GeneralSyncErrorCode {
final int code;
const GeneralSyncErrorCode(this.code);
}

/// Contains the details for a compensating write performed by the server.
/// {@category Sync}
class CompensatingWriteInfo {
desistefanova marked this conversation as resolved.
Show resolved Hide resolved
/// The type of the object which was affected by the compensating write.
final String objectType;

/// The reason for the server to perform a compensating write.
final String reason;

/// The primary key of the object which was affected by the compensating write.
final RealmValue primaryKey;

const CompensatingWriteInfo(this.objectType, this.reason, this.primaryKey);
blagoev marked this conversation as resolved.
Show resolved Hide resolved

@override
String toString() {
return "CompensatingWriteInfo: objectType: '$objectType' reason: '$reason' primaryKey: '$primaryKey'";
}
}

/// An error type that describes a compensating write error,
/// which indicates that one more object changes have been reverted
/// by the server.
/// {@category Sync}
class CompensatingWriteError extends SyncError {
/// The [CompensatingWriteError] has error code of [SyncSessionErrorCode.compensatingWrite]
SyncSessionErrorCode get code => SyncSessionErrorCode.compensatingWrite;

/// The list of the compensating writes performed by the server.
late final List<CompensatingWriteInfo>? compensatingWrites;

CompensatingWriteError._(
String message, {
String? detailedMessage,
this.compensatingWrites,
}) : super(message, SyncErrorCategory.session, SyncSessionErrorCode.compensatingWrite.code, detailedMessage: detailedMessage);

@override
String toString() {
return "CompensatingWriteError message: $message category: $category code: $code. ${compensatingWrites ?? ''}";
}
}

/// @nodoc
extension SyncErrorInternal on SyncError {
static SyncError createSyncError(SyncErrorDetails error, {App? app}) {
if (error.isClientResetRequested) {
//Client reset can be requested with isClientResetRequested disregarding the SyncClientErrorCode and SyncSessionErrorCode values
return ClientResetError(error.message,
app: app,
category: error.category,
errorCodeValue: error.code,
originalFilePath: error.originalFilePath,
backupFilePath: error.backupFilePath,
detailedMessage: error.detailedMessage);
}

switch (error.category) {
case SyncErrorCategory.client:
blagoev marked this conversation as resolved.
Show resolved Hide resolved
final errorCode = SyncClientErrorCode.fromInt(error.code);
return SyncClientError(error.message, error.category, errorCode, detailedMessage: error.detailedMessage, isFatal: error.isFatal);
case SyncErrorCategory.connection:
final errorCode = SyncConnectionErrorCode.fromInt(error.code);
return SyncConnectionError(error.message, error.category, errorCode, detailedMessage: error.detailedMessage, isFatal: error.isFatal);
case SyncErrorCategory.session:
final errorCode = SyncSessionErrorCode.fromInt(error.code);
if (errorCode == SyncSessionErrorCode.compensatingWrite) {
return CompensatingWriteError._(error.message, detailedMessage: error.detailedMessage, compensatingWrites: error.compensatingWrites);
}
return SyncSessionError(error.message, error.category, errorCode, detailedMessage: error.detailedMessage, isFatal: error.isFatal);
case SyncErrorCategory.webSocket:
final errorCode = SyncWebSocketErrorCode.fromInt(error.code);
return SyncWebSocketError(error.message, error.category, errorCode, detailedMessage: error.detailedMessage);
case SyncErrorCategory.system:
case SyncErrorCategory.unknown:
default:
return GeneralSyncError(error.message, error.category, error.code, detailedMessage: error.detailedMessage);
}
}
}
Loading