From d2dfdb221299b0ccf880071b249e039aa147bc3d Mon Sep 17 00:00:00 2001 From: Alex Gaetano Padula Date: Wed, 11 Feb 2026 10:30:52 -0500 Subject: [PATCH] extend api with column family clone method and transaction reset capabilities, update rockspec to bump minor --- src/tidesdb.lua | 23 +++- tests/test_tidesdb.lua | 107 ++++++++++++++++++ ...4.0-1.rockspec => tidesdb-0.5.0-1.rockspec | 4 +- 3 files changed, 131 insertions(+), 3 deletions(-) rename tidesdb-0.4.0-1.rockspec => tidesdb-0.5.0-1.rockspec (95%) diff --git a/src/tidesdb.lua b/src/tidesdb.lua index ed7c99f..f7450ea 100644 --- a/src/tidesdb.lua +++ b/src/tidesdb.lua @@ -117,6 +117,7 @@ ffi.cdef[[ int tidesdb_create_column_family(void* db, const char* name, tidesdb_column_family_config_t* config); int tidesdb_drop_column_family(void* db, const char* name); int tidesdb_rename_column_family(void* db, const char* old_name, const char* new_name); + int tidesdb_clone_column_family(void* db, const char* source_name, const char* dest_name); void* tidesdb_get_column_family(void* db, const char* name); int tidesdb_list_column_families(void* db, char*** names, int* count); @@ -129,6 +130,7 @@ ffi.cdef[[ int tidesdb_txn_commit(void* txn); int tidesdb_txn_rollback(void* txn); void tidesdb_txn_free(void* txn); + int tidesdb_txn_reset(void* txn, int isolation); int tidesdb_txn_savepoint(void* txn, const char* name); int tidesdb_txn_rollback_to_savepoint(void* txn, const char* name); int tidesdb_txn_release_savepoint(void* txn, const char* name); @@ -703,6 +705,16 @@ function Transaction:rollback() check_result(result, "failed to rollback transaction") end +function Transaction:reset(isolation) + if self._closed then + error(TidesDBError.new("Transaction is closed")) + end + + local result = lib.tidesdb_txn_reset(self._txn, isolation) + check_result(result, "failed to reset transaction") + self._committed = false +end + function Transaction:savepoint(name) if self._closed then error(TidesDBError.new("Transaction is closed")) @@ -855,6 +867,15 @@ function TidesDB:rename_column_family(old_name, new_name) check_result(result, "failed to rename column family") end +function TidesDB:clone_column_family(source_name, dest_name) + if self._closed then + error(TidesDBError.new("Database is closed")) + end + + local result = lib.tidesdb_clone_column_family(self._db, source_name, dest_name) + check_result(result, "failed to clone column family") +end + function TidesDB:get_column_family(name) if self._closed then error(TidesDBError.new("Database is closed")) @@ -1011,6 +1032,6 @@ function tidesdb.save_config_to_ini(ini_file, section_name, config) end -- Version -tidesdb._VERSION = "0.3.0" +tidesdb._VERSION = "0.5.0" return tidesdb diff --git a/tests/test_tidesdb.lua b/tests/test_tidesdb.lua index 954332d..abb8a15 100644 --- a/tests/test_tidesdb.lua +++ b/tests/test_tidesdb.lua @@ -482,6 +482,113 @@ function tests.test_btree_stats_extended() print("PASS: test_btree_stats_extended") end +function tests.test_clone_column_family() + local path = "./test_db_clone_cf" + cleanup_db(path) + + local db = tidesdb.TidesDB.open(path) + db:create_column_family("source_cf") + local cf = db:get_column_family("source_cf") + + -- Insert data into source + local txn = db:begin_txn() + txn:put(cf, "key1", "value1") + txn:put(cf, "key2", "value2") + txn:commit() + txn:free() + + -- Clone column family + db:clone_column_family("source_cf", "cloned_cf") + + -- Verify cloned column family exists + local cloned_cf = db:get_column_family("cloned_cf") + assert_true(cloned_cf ~= nil, "cloned column family should exist") + + -- Verify data is preserved in clone + local read_txn = db:begin_txn() + local v1 = read_txn:get(cloned_cf, "key1") + local v2 = read_txn:get(cloned_cf, "key2") + assert_eq(v1, "value1", "cloned key1 should have correct value") + assert_eq(v2, "value2", "cloned key2 should have correct value") + read_txn:free() + + -- Verify source still works independently + local src_txn = db:begin_txn() + local sv1 = src_txn:get(cf, "key1") + assert_eq(sv1, "value1", "source key1 should still exist") + src_txn:free() + + -- Verify modifications to clone don't affect source + local write_txn = db:begin_txn() + write_txn:put(cloned_cf, "key3", "value3") + write_txn:commit() + write_txn:free() + + local verify_txn = db:begin_txn() + local v3 = verify_txn:get(cloned_cf, "key3") + assert_eq(v3, "value3", "key3 should exist in clone") + local err = assert_error(function() + verify_txn:get(cf, "key3") + end, "key3 should not exist in source") + verify_txn:free() + + -- Verify cloning to existing name fails + local clone_err = assert_error(function() + db:clone_column_family("source_cf", "cloned_cf") + end, "cloning to existing name should fail") + + db:drop_column_family("source_cf") + db:drop_column_family("cloned_cf") + db:close() + cleanup_db(path) + print("PASS: test_clone_column_family") +end + +function tests.test_transaction_reset() + local path = "./test_db_txn_reset" + cleanup_db(path) + + local db = tidesdb.TidesDB.open(path) + db:create_column_family("test_cf") + local cf = db:get_column_family("test_cf") + + -- Begin transaction and do first batch of work + local txn = db:begin_txn() + txn:put(cf, "key1", "value1") + txn:commit() + + -- Reset transaction instead of free + begin + txn:reset(tidesdb.IsolationLevel.READ_COMMITTED) + + -- Second batch of work using the same transaction + txn:put(cf, "key2", "value2") + txn:commit() + + -- Reset again with different isolation level + txn:reset(tidesdb.IsolationLevel.SERIALIZABLE) + + -- Third batch + txn:put(cf, "key3", "value3") + txn:commit() + + txn:free() + + -- Verify all data was written + local read_txn = db:begin_txn() + local v1 = read_txn:get(cf, "key1") + local v2 = read_txn:get(cf, "key2") + local v3 = read_txn:get(cf, "key3") + assert_eq(v1, "value1", "key1 should exist after reset") + assert_eq(v2, "value2", "key2 should exist after reset") + assert_eq(v3, "value3", "key3 should exist after reset") + read_txn:free() + + db:drop_column_family("test_cf") + db:close() + cleanup_db(path) + print("PASS: test_transaction_reset") +end + -- Run all tests local function run_tests() print("Running TidesDB Lua tests...") diff --git a/tidesdb-0.4.0-1.rockspec b/tidesdb-0.5.0-1.rockspec similarity index 95% rename from tidesdb-0.4.0-1.rockspec rename to tidesdb-0.5.0-1.rockspec index 9e9ed0e..22fa743 100644 --- a/tidesdb-0.4.0-1.rockspec +++ b/tidesdb-0.5.0-1.rockspec @@ -1,8 +1,8 @@ package = "tidesdb" -version = "0.4.0-1" +version = "0.5.0-1" source = { url = "git://github.com/tidesdb/tidesdb-lua.git", - tag = "v0.4.0" + tag = "v0.5.0" } description = { summary = "Official Lua bindings for TidesDB - A high-performance embedded key-value storage engine",