transaction<R> method
Run body as a transaction. Mutations performed via the
supplied handle are buffered in memory and applied in body
order on successful completion; if the body throws, the
buffer is dropped and the exception propagates.
Hive impls provide best-effort atomicity; a future SQL impl will provide true atomicity.
Implementation
@override
Future<R> transaction<R>(
Future<R> Function(KeyStoreTxn<String, AtData, dynamic> txn) body) async {
final txn = _SqliteKeyStoreTxn(this);
final result = await body(txn);
// Apply buffered ops atomically, in body order.
final fired = <KeyStoreChange>[];
_db.runInTransaction(() {
for (final op in txn._ops) {
if (op.isRemove) {
if (_existsSync(op.key)) {
_db.raw.execute('DELETE FROM at_data WHERE atkey = ?;', [op.key]);
_commitOrNull(op.key, CommitOp.DELETE);
fired.add(KeyRemoved(op.key));
}
} else {
final existed = _existsSync(op.key);
final toStore = AtData()
..data = op.value!.data
..metaData = AtMetadataBuilder(
atSign: atSign,
newAtMetaData: op.metadata,
existingMetaData: existed ? _getSync(op.key)?.metaData : null,
).build();
_upsertAtData(op.key, toStore);
_commitOrNull(op.key, CommitOp.UPDATE_ALL);
fired.add(existed ? KeyUpdated(op.key) : KeyAdded(op.key));
}
}
});
for (final change in fired) {
_changes.add(change);
}
return result;
}