diff --git a/lib/src/bindings/bindings.dart b/lib/src/bindings/bindings.dart index a748b287..c75d8206 100644 --- a/lib/src/bindings/bindings.dart +++ b/lib/src/bindings/bindings.dart @@ -54,6 +54,7 @@ class _ObjectBoxBindings { int Function(Pointer txn) obx_txn_close; int Function(Pointer txn) obx_txn_abort; int Function(Pointer txn) obx_txn_success; + int Function(Pointer txn, int was_successful) obx_txn_mark_success; // box management Pointer Function(Pointer store, int entity_id) obx_box; @@ -185,6 +186,7 @@ class _ObjectBoxBindings { obx_txn_close = _fn("obx_txn_close").asFunction(); obx_txn_abort = _fn("obx_txn_abort").asFunction(); obx_txn_success = _fn("obx_txn_success").asFunction(); + obx_txn_mark_success = _fn("obx_txn_mark_success").asFunction(); // box management obx_box = _fn("obx_box").asFunction(); diff --git a/lib/src/bindings/signatures.dart b/lib/src/bindings/signatures.dart index 5284b451..1a0b47aa 100644 --- a/lib/src/bindings/signatures.dart +++ b/lib/src/bindings/signatures.dart @@ -41,6 +41,7 @@ typedef obx_txn_read_native_t = Pointer Function(Pointer store); typedef obx_txn_close_native_t = Int32 Function(Pointer txn); typedef obx_txn_abort_native_t = Int32 Function(Pointer txn); typedef obx_txn_success_native_t = Int32 Function(Pointer txn); +typedef obx_txn_mark_success_native_t = Int32 Function(Pointer txn, Uint8 wasSuccessful); // box management typedef obx_box_native_t = Pointer Function(Pointer store, Uint32 entity_id); diff --git a/lib/src/store.dart b/lib/src/store.dart index 6c1aa842..ee579221 100644 --- a/lib/src/store.dart +++ b/lib/src/store.dart @@ -54,13 +54,22 @@ class Store { } /// Executes a given function inside a transaction + /// + /// Returns type of [fn] if [return] is called in [fn] R runInTransaction(TxMode mode, R Function() fn) { - assert(mode == TxMode.Read, "write transactions are currently not supported"); // TODO implement - - Pointer txn = bindings.obx_txn_read(_cStore); - checkObxPtr(txn, "failed to created transaction"); + bool wanna_write = mode == TxMode.Write; + Pointer txn = wanna_write ? bindings.obx_txn_write(_cStore) : bindings.obx_txn_read(_cStore); + checkObxPtr(txn, "failed to create transaction"); try { + if (wanna_write) { + checkObx(bindings.obx_txn_mark_success(txn, 1)); + } return fn(); + } catch (ex) { + if (wanna_write) { + checkObx(bindings.obx_txn_mark_success(txn, 0)); + } + rethrow; } finally { checkObx(bindings.obx_txn_close(txn)); } diff --git a/test/box_test.dart b/test/box_test.dart index 0b2be52b..ef809c9c 100644 --- a/test/box_test.dart +++ b/test/box_test.dart @@ -6,6 +6,7 @@ import 'test_env.dart'; void main() { TestEnv env; Box box; + Store store; final List simple_items = ["One", "Two", "Three", "Four", "Five", "Six"].map((s) => TestEntity.initText(s)).toList(); @@ -13,6 +14,7 @@ void main() { setUp(() { env = TestEnv("box"); box = env.box; + store = env.store; }); test(".put() returns a valid id", () { @@ -168,6 +170,73 @@ void main() { expect(removed, equals(3)); }); + test("simple write in txn works", () { + int count; + write_func() { + box.putMany(simple_items); + } + store.runInTransaction(TxMode.Write, write_func); + count = box.count(); + expect(count, equals(6)); + }); + + test("failing transactions", () { + try { + store.runInTransaction(TxMode.Write, () { + box.putMany(simple_items); + throw Exception("Test exception"); + }); + } on Exception { + ; //otherwise test fails due to not handling exceptions + } finally { + expect(box.count(), equals(0)); + } + }); + + test("recursive write in write transaction", () { + store.runInTransaction(TxMode.Write, () { + box.putMany(simple_items); + store.runInTransaction(TxMode.Write, () { + box.putMany(simple_items); + }); + }); + expect(box.count(), equals(12)); + }); + + test("recursive read in write transaction", () { + int count = store.runInTransaction(TxMode.Write, () { + box.putMany(simple_items); + return store.runInTransaction(TxMode.Read, () { + return box.count(); + }); + }); + expect(count, equals(6)); + }); + + test("recursive write in read -> fails during creation", () { + List ids; + try { + ids = store.runInTransaction(TxMode.Read, () { + box.count(); + return store.runInTransaction(TxMode.Write, () { + return box.putMany(simple_items); + }); + }); + } on ObjectBoxException catch (ex) { + expect(ex.toString(), equals("ObjectBoxException: failed to create transaction: ")); + } + }); + + test("failing in recursive txn", () { + store.runInTransaction(TxMode.Write, () { + //should throw code10001 -> valid until fix + List ids = store.runInTransaction(TxMode.Read, () { + return box.putMany(simple_items); + }); + expect(ids.length, equals(6)); + }); + }); + tearDown(() { env.close(); });