save method
Saves a new value with an explicit context.
Returns a SaveResult so failures are observable and testable.
Implementation
Future<SaveResult> save(
T value, {
required SaveContext context,
}) async {
final nowMs = _clock.now().millisecondsSinceEpoch;
String? existingRaw;
SaveEnvelope? existingEnvelope;
try {
existingRaw = await _store.read();
} catch (error, stackTrace) {
return SaveFailure(
reason: SaveFailureReason.readFailed,
context: context,
error: error,
stackTrace: stackTrace,
);
}
if (existingRaw != null) {
try {
final decoded = _codec.decode(existingRaw);
existingEnvelope = SaveEnvelope.fromJson(decoded);
} catch (_) {
existingEnvelope = null;
}
}
final createdAtMs = existingEnvelope?.createdAtMs ?? nowMs;
Map<String, dynamic> payload;
try {
payload = _encoder(value);
} catch (error, stackTrace) {
return SaveFailure(
reason: SaveFailureReason.encodeFailed,
context: context,
error: error,
stackTrace: stackTrace,
);
}
if (_validatePayload) {
try {
JsonSafe.validate(payload);
} on FormatException catch (error, stackTrace) {
return SaveFailure(
reason: SaveFailureReason.invalidPayload,
context: context,
error: error,
stackTrace: stackTrace,
);
}
}
var envelope = SaveEnvelope(
schemaVersion: _migrator.latestVersion,
createdAtMs: createdAtMs,
updatedAtMs: nowMs,
payload: payload,
saveReason: context.reason.value,
changeSet: context.changeSet,
);
envelope = _applyChecksum(envelope);
String raw;
try {
raw = _codec.encode(envelope.toJson());
} catch (error, stackTrace) {
return SaveFailure(
reason: SaveFailureReason.encodeFailed,
context: context,
error: error,
stackTrace: stackTrace,
envelope: envelope,
);
}
var backupWritten = false;
if (_backupStore != null && existingRaw != null) {
try {
await _backupStore!.write(existingRaw);
backupWritten = true;
} catch (error, stackTrace) {
return SaveFailure(
reason: SaveFailureReason.backupWriteFailed,
context: context,
error: error,
stackTrace: stackTrace,
envelope: envelope,
raw: raw,
backupWritten: backupWritten,
);
}
}
try {
await _store.write(raw);
} catch (error, stackTrace) {
return SaveFailure(
reason: SaveFailureReason.writeFailed,
context: context,
error: error,
stackTrace: stackTrace,
envelope: envelope,
raw: raw,
backupWritten: backupWritten,
);
}
return SaveSuccess(
envelope: envelope,
raw: raw,
context: context,
backupWritten: backupWritten,
);
}