diff --git a/cpp/DBHostObject.cpp b/cpp/DBHostObject.cpp index 648dc89..ab33c7d 100644 --- a/cpp/DBHostObject.cpp +++ b/cpp/DBHostObject.cpp @@ -18,7 +18,7 @@ namespace react = facebook::react; #ifdef OP_SQLITE_USE_LIBSQL void DBHostObject::flush_pending_reactive_queries( - std::shared_ptr resolve) { + const std::shared_ptr &resolve) { invoker->invokeAsync( [this, resolve]() { resolve->asObject(rt).asFunction(rt).call(rt, {}); }); } @@ -135,33 +135,25 @@ void DBHostObject::auto_register_update_hook() { #ifdef OP_SQLITE_USE_LIBSQL DBHostObject::DBHostObject(jsi::Runtime &rt, std::string &url, std::string &auth_token, - std::shared_ptr invoker, - std::shared_ptr thread_pool) + std::shared_ptr invoker + ) : db_name(url), invoker(std::move(invoker)), - thread_pool(std::move(thread_pool)), rt(rt) { - BridgeResult result = opsqlite_libsql_open_remote(url, auth_token); - - if (result.type == SQLiteError) { - throw std::runtime_error(result.message); - } + rt(rt) { + db = opsqlite_libsql_open_remote(url, auth_token); create_jsi_functions(); } DBHostObject::DBHostObject(jsi::Runtime &rt, std::shared_ptr invoker, - std::shared_ptr thread_pool, std::string &db_name, std::string &path, std::string &url, std::string &auth_token, int sync_interval) : db_name(db_name), invoker(std::move(invoker)), - thread_pool(std::move(thread_pool)), rt(rt) { - BridgeResult result = + rt(rt) { + db = opsqlite_libsql_open_sync(db_name, path, url, auth_token, sync_interval); - if (result.type == SQLiteError) { - throw std::runtime_error(result.message); - } create_jsi_functions(); } @@ -179,10 +171,10 @@ DBHostObject::DBHostObject(jsi::Runtime &rt, std::string &base_path, _thread_pool = std::make_shared(); #ifdef OP_SQLITE_USE_SQLCIPHER - BridgeResult result = opsqlite_open(db_name, path, crsqlite_path, + db = opsqlite_open(db_name, path, crsqlite_path, sqlite_vec_path, encryption_key); #elif OP_SQLITE_USE_LIBSQL - BridgeResult result = opsqlite_libsql_open(db_name, path, crsqlite_path); + db = opsqlite_libsql_open(db_name, path, crsqlite_path); #else db = opsqlite_open(db_name, path, crsqlite_path, sqlite_vec_path); #endif @@ -214,8 +206,8 @@ void DBHostObject::create_jsi_functions() { std::string secondary_db_name = args[1].asString(rt).utf8(rt); std::string alias = args[2].asString(rt).utf8(rt); #ifdef OP_SQLITE_USE_LIBSQL - BridgeResult result = opsqlite_libsql_attach( - main_db_name, secondary_db_path, secondary_db_name, alias); + opsqlite_libsql_attach( + db, secondary_db_path, secondary_db_name, alias); #else opsqlite_attach(db, main_db_name, secondary_db_path, secondary_db_name, alias); @@ -237,7 +229,7 @@ void DBHostObject::create_jsi_functions() { std::string dbName = args[0].asString(rt).utf8(rt); std::string alias = args[1].asString(rt).utf8(rt); #ifdef OP_SQLITE_USE_LIBSQL - opsqlite_libsql_detach(dbName, alias); + opsqlite_libsql_detach(db, alias); #else opsqlite_detach(db, dbName, alias); #endif @@ -247,7 +239,7 @@ void DBHostObject::create_jsi_functions() { function_map["close"] = HOSTFN("close") { #ifdef OP_SQLITE_USE_LIBSQL - BridgeResult result = opsqlite_libsql_close(db_name); + opsqlite_libsql_close(db); #else opsqlite_close(db); #endif @@ -278,7 +270,7 @@ void DBHostObject::create_jsi_functions() { } #ifdef OP_SQLITE_USE_LIBSQL - BridgeResult result = opsqlite_libsql_remove(db_name, path); + opsqlite_libsql_remove(db, db_name, path); #else opsqlite_remove(db, db_name, path); #endif @@ -303,7 +295,7 @@ void DBHostObject::create_jsi_functions() { #ifdef OP_SQLITE_USE_LIBSQL auto status = - opsqlite_libsql_execute_raw(db_name, query, ¶ms, &results); + opsqlite_libsql_execute_raw(db, query, ¶ms, &results); #else auto status = opsqlite_execute_raw(db, query, ¶ms, &results); #endif @@ -352,7 +344,7 @@ void DBHostObject::create_jsi_functions() { params = to_variant_vec(rt, args[1]); } #ifdef OP_SQLITE_USE_LIBSQL - auto status = opsqlite_libsql_execute(db_name, query, ¶ms); + auto status = opsqlite_libsql_execute(db, query, ¶ms); #else auto status = opsqlite_execute(db, query, ¶ms); #endif @@ -374,7 +366,7 @@ void DBHostObject::create_jsi_functions() { reject = std::make_shared(rt, args[1])]() { try { #ifdef OP_SQLITE_USE_LIBSQL - auto status = opsqlite_libsql_execute(db_name, query, ¶ms); + auto status = opsqlite_libsql_execute(db, query, ¶ms); #else auto status = opsqlite_execute(db, query, ¶ms); #endif @@ -439,7 +431,7 @@ void DBHostObject::create_jsi_functions() { std::make_shared>(); #ifdef OP_SQLITE_USE_LIBSQL auto status = opsqlite_libsql_execute_with_host_objects( - db_name, query, ¶ms, &results, metadata); + db, query, ¶ms, &results, metadata); #else auto status = opsqlite_execute_host_objects(db, query, ¶ms, &results, metadata); @@ -518,7 +510,7 @@ void DBHostObject::create_jsi_functions() { try { #ifdef OP_SQLITE_USE_LIBSQL auto batchResult = - opsqlite_libsql_execute_batch(db_name, commands.get()); + opsqlite_libsql_execute_batch(db, commands.get()); #else auto batchResult = opsqlite_execute_batch(db, commands.get()); #endif @@ -562,10 +554,7 @@ void DBHostObject::create_jsi_functions() { #ifdef OP_SQLITE_USE_LIBSQL function_map["sync"] = HOSTFN("sync") { - BridgeResult result = opsqlite_libsql_sync(db_name); - if (result.type == SQLiteError) { - throw std::runtime_error(result.message); - } + opsqlite_libsql_sync(db); return {}; }); #else @@ -736,7 +725,7 @@ void DBHostObject::create_jsi_functions() { function_map["prepareStatement"] = HOSTFN("prepareStatement") { auto query = args[0].asString(rt).utf8(rt); #ifdef OP_SQLITE_USE_LIBSQL - libsql_stmt_t statement = opsqlite_libsql_prepare_statement(db_name, query); + libsql_stmt_t statement = opsqlite_libsql_prepare_statement(db, query); #else sqlite3_stmt *statement = opsqlite_prepare_statement(db, query); #endif @@ -818,10 +807,14 @@ void DBHostObject::set(jsi::Runtime &_rt, const jsi::PropNameID &name, void DBHostObject::invalidate() { invalidated = true; _thread_pool->restartPool(); +#ifdef OP_SQLITE_USE_LIBSQL + opsqlite_libsql_close(db); +#else if (db != nullptr) { opsqlite_close(db); db = nullptr; } +#endif } DBHostObject::~DBHostObject() { invalidate(); } diff --git a/cpp/DBHostObject.h b/cpp/DBHostObject.h index b2f8d73..8567a2e 100644 --- a/cpp/DBHostObject.h +++ b/cpp/DBHostObject.h @@ -5,7 +5,11 @@ #include #include #include +#ifdef OP_SQLITE_USE_LIBSQL +#include "libsql/bridge.h" +#else #include +#endif #include #include @@ -26,7 +30,9 @@ struct TableRowDiscriminator { }; struct ReactiveQuery { +#ifndef OP_SQLITE_USE_LIBSQL sqlite3_stmt *stmt; +#endif std::vector discriminators; std::shared_ptr callback; }; @@ -43,8 +49,7 @@ class JSI_EXPORT DBHostObject : public jsi::HostObject { #ifdef OP_SQLITE_USE_LIBSQL // Constructor for remoteOpen, purely for remote databases DBHostObject(jsi::Runtime &rt, std::string &url, std::string &auth_token, - std::shared_ptr invoker, - std::shared_ptr thread_pool); + std::shared_ptr invoker); // Constructor for a local database with remote sync DBHostObject(jsi::Runtime &rt, std::shared_ptr invoker, @@ -84,8 +89,7 @@ class JSI_EXPORT DBHostObject : public jsi::HostObject { bool is_update_hook_registered = false; bool invalidated = false; #ifdef OP_SQLITE_USE_LIBSQL - libsql_database_t db; - libsql_connection_t c; + DB db; #else sqlite3 *db; #endif diff --git a/cpp/PreparedStatementHostObject.cpp b/cpp/PreparedStatementHostObject.cpp index 43696af..6dba885 100644 --- a/cpp/PreparedStatementHostObject.cpp +++ b/cpp/PreparedStatementHostObject.cpp @@ -91,7 +91,7 @@ jsi::Value PreparedStatementHostObject::get(jsi::Runtime &rt, try { #ifdef OP_SQLITE_USE_LIBSQL auto status = opsqlite_libsql_execute_prepared_statement( - _name, _stmt, &results, metadata); + _db, _stmt, &results, metadata); #else auto status = opsqlite_execute_prepared_statement( _db, _stmt, &results, metadata); diff --git a/cpp/PreparedStatementHostObject.h b/cpp/PreparedStatementHostObject.h index ba4bb72..71895f6 100644 --- a/cpp/PreparedStatementHostObject.h +++ b/cpp/PreparedStatementHostObject.h @@ -4,6 +4,7 @@ #include #include #ifdef OP_SQLITE_USE_LIBSQL +#include "libsql/bridge.h" #include "libsql.h" #else #include @@ -20,10 +21,10 @@ class PreparedStatementHostObject : public jsi::HostObject { public: #ifdef OP_SQLITE_USE_LIBSQL PreparedStatementHostObject( - std::string name, libsql_stmt_t stmt, + DB const &db, std::string name, libsql_stmt_t stmt, std::shared_ptr js_call_invoker, std::shared_ptr thread_pool) - : _name(name), _stmt(stmt), _js_call_invoker(js_call_invoker), + : _db(db), _name(std::move(name)), _stmt(stmt), _js_call_invoker(js_call_invoker), _thread_pool(thread_pool) {}; #else PreparedStatementHostObject( @@ -40,11 +41,12 @@ class PreparedStatementHostObject : public jsi::HostObject { jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propNameID) override; private: - sqlite3 *_db; std::string _name; #ifdef OP_SQLITE_USE_LIBSQL + DB _db; libsql_stmt_t _stmt; #else + sqlite3 *_db; // This shouldn't be de-allocated until sqlite3_finalize is called on it sqlite3_stmt *_stmt; #endif diff --git a/cpp/bindings.cpp b/cpp/bindings.cpp index e289088..273fc60 100644 --- a/cpp/bindings.cpp +++ b/cpp/bindings.cpp @@ -108,7 +108,7 @@ void install(jsi::Runtime &rt, options.getProperty(rt, "authToken").asString(rt).utf8(rt); std::shared_ptr db = std::make_shared( - rt, url, auth_token, invoker, thread_pool); + rt, url, auth_token, invoker); return jsi::Object::createFromHostObject(rt, db); }); diff --git a/cpp/bridge.cpp b/cpp/bridge.cpp index c6f265d..a34b3fd 100644 --- a/cpp/bridge.cpp +++ b/cpp/bridge.cpp @@ -72,7 +72,7 @@ std::string opsqlite_get_db_path(std::string const &db_name, } #ifdef OP_SQLITE_USE_SQLCIPHER -BridgeResult opsqlite_open(std::string const &name, std::string const &path, +sqlite3 *opsqlite_open(std::string const &name, std::string const &path, std::string const &crsqlite_path, std::string const &sqlite_vec_path, std::string const &encryption_key) { diff --git a/cpp/bridge.h b/cpp/bridge.h index f5ec490..10414e5 100644 --- a/cpp/bridge.h +++ b/cpp/bridge.h @@ -22,7 +22,7 @@ std::string opsqlite_get_db_path(std::string const &db_name, std::string const &location); #ifdef OP_SQLITE_USE_SQLCIPHER -BridgeResult opsqlite_open(std::string const &dbName, std::string const &path, +sqlite3 *opsqlite_open(std::string const &dbName, std::string const &path, std::string const &crsqlite_path, std::string const &sqlite_vec_path, std::string const &encryption_key); diff --git a/cpp/libsql/bridge.cpp b/cpp/libsql/bridge.cpp index 5014307..e895f10 100644 --- a/cpp/libsql/bridge.cpp +++ b/cpp/libsql/bridge.cpp @@ -9,19 +9,6 @@ namespace opsqlite { -struct DB { - libsql_database_t db; - libsql_connection_t c; -}; - -std::unordered_map db_map = - std::unordered_map(); - -inline void check_db_open(std::string const &db_name) { - if (db_map.count(db_name) == 0) { - throw std::runtime_error("[OP-SQLite] DB is not open"); - } -} // _____ _____ // /\ | __ \_ _| // / \ | |__) || | @@ -42,7 +29,7 @@ std::string opsqlite_get_db_path(std::string const &db_name, return location + "/" + db_name; } -BridgeResult opsqlite_libsql_open_sync(std::string const &name, +DB opsqlite_libsql_open_sync(std::string const &name, std::string const &base_path, std::string const &url, std::string const &auth_token, @@ -63,21 +50,19 @@ BridgeResult opsqlite_libsql_open_sync(std::string const &name, .with_webpki = '1'}; status = libsql_open_sync_with_config(config, &db, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } status = libsql_connect(db, &c, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } - db_map[name] = {.db = db, .c = c}; - - return {.type = SQLiteOk, .affectedRows = 0}; + return {.db= db, .c= c }; } -BridgeResult opsqlite_libsql_open(std::string const &name, +DB opsqlite_libsql_open(std::string const &name, std::string const &last_path, std::string const &crsqlitePath) { std::string path = opsqlite_get_db_path(name, last_path); @@ -90,13 +75,13 @@ BridgeResult opsqlite_libsql_open(std::string const &name, status = libsql_open_file(path.c_str(), &db, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } status = libsql_connect(db, &c, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } #ifdef OP_SQLITE_USE_CRSQLITE @@ -113,12 +98,10 @@ BridgeResult opsqlite_libsql_open(std::string const &name, } #endif - db_map[name] = {.db = db, .c = c}; - - return {.type = SQLiteOk, .affectedRows = 0}; + return {.db = db, .c = c}; } -BridgeResult opsqlite_libsql_open_remote(std::string const &url, +DB opsqlite_libsql_open_remote(std::string const &url, std::string const &auth_token) { int status; libsql_database_t db; @@ -129,109 +112,68 @@ BridgeResult opsqlite_libsql_open_remote(std::string const &url, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } status = libsql_connect(db, &c, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } - db_map[url] = {.db = db, .c = c}; - - return {.type = SQLiteOk, .affectedRows = 0}; + return {.db = db, .c = c}; } -BridgeResult opsqlite_libsql_close(std::string const &name) { - - check_db_open(name); - - DB db = db_map[name]; - - libsql_disconnect(db.c); - libsql_close(db.db); - - db_map.erase(name); - - return BridgeResult{ - .type = SQLiteOk, - }; +void opsqlite_libsql_close(DB &db) { + if (db.c != nullptr) { + libsql_disconnect(db.c); + db.c = nullptr; + } + if (db.db != nullptr) { + libsql_close(db.db); + db.db = nullptr; + } } -BridgeResult opsqlite_libsql_attach(std::string const &mainDBName, +void opsqlite_libsql_attach(DB const &db, std::string const &docPath, std::string const &databaseToAttach, std::string const &alias) { std::string dbPath = opsqlite_get_db_path(databaseToAttach, docPath); std::string statement = "ATTACH DATABASE '" + dbPath + "' AS " + alias; - BridgeResult result = opsqlite_libsql_execute(mainDBName, statement, nullptr); + opsqlite_libsql_execute(db, statement, nullptr); - if (result.type == SQLiteError) { - return { - .type = SQLiteError, - .message = mainDBName + " was unable to attach another database: " + - std::string(result.message), - }; - } - return { - .type = SQLiteOk, - }; } -BridgeResult opsqlite_libsql_detach(std::string const &mainDBName, +void opsqlite_libsql_detach(DB const &db, std::string const &alias) { std::string statement = "DETACH DATABASE " + alias; - BridgeResult result = opsqlite_libsql_execute(mainDBName, statement, nullptr); - if (result.type == SQLiteError) { - return BridgeResult{ - .type = SQLiteError, - .message = mainDBName + "was unable to detach database: " + - std::string(result.message), - }; - } - return BridgeResult{ - .type = SQLiteOk, - }; + opsqlite_libsql_execute(db, statement, nullptr); } -BridgeResult opsqlite_libsql_sync(std::string const &name) { - check_db_open(name); - - auto db = db_map[name].db; +void opsqlite_libsql_sync(DB const &db) { const char *err = nullptr; - int status = libsql_sync(db, &err); + int status = libsql_sync(db.db, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } - return {.type = SQLiteOk}; } -BridgeResult opsqlite_libsql_remove(std::string const &name, +void opsqlite_libsql_remove(DB &db, std::string const &name, std::string const &path) { - if (db_map.count(name) == 1) { - BridgeResult closeResult = opsqlite_libsql_close(name); - if (closeResult.type == SQLiteError) { - return closeResult; - } - } + opsqlite_libsql_close(db); std::string full_path = opsqlite_get_db_path(name, path); if (!file_exists(full_path)) { - return {.type = SQLiteError, - .message = "[op-sqlite]: Database file not found" + full_path}; + throw std::runtime_error("[op-sqlite]: Database file not found" + full_path); } remove(full_path.c_str()); - - return { - .type = SQLiteOk, - }; } void opsqlite_libsql_bind_statement(libsql_stmt_t statement, @@ -273,13 +215,11 @@ void opsqlite_libsql_bind_statement(libsql_stmt_t statement, } BridgeResult opsqlite_libsql_execute_prepared_statement( - std::string const &name, libsql_stmt_t stmt, + DB const &db, + libsql_stmt_t stmt, std::vector *results, const std::shared_ptr> &metadatas) { - check_db_open(name); - - libsql_connection_t c = db_map[name].c; libsql_rows_t rows; libsql_row_t row; @@ -289,7 +229,7 @@ BridgeResult opsqlite_libsql_execute_prepared_statement( status = libsql_query_stmt(stmt, &rows, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } bool metadata_set = false; @@ -384,22 +324,17 @@ BridgeResult opsqlite_libsql_execute_prepared_statement( libsql_free_rows(rows); - unsigned long long changes = libsql_changes(c); - long long insert_row_id = libsql_last_insert_rowid(c); + unsigned long long changes = libsql_changes(db.c); + long long insert_row_id = libsql_last_insert_rowid(db.c); libsql_reset_stmt(stmt, &err); - return {.type = SQLiteOk, - .affectedRows = static_cast(changes), + return {.affectedRows = static_cast(changes), .insertId = static_cast(insert_row_id)}; } -libsql_stmt_t opsqlite_libsql_prepare_statement(std::string const &name, +libsql_stmt_t opsqlite_libsql_prepare_statement(DB const &db, std::string const &query) { - check_db_open(name); - - DB db = db_map[name]; - libsql_stmt_t stmt; const char *err; @@ -413,26 +348,23 @@ libsql_stmt_t opsqlite_libsql_prepare_statement(std::string const &name, return stmt; } -BridgeResult opsqlite_libsql_execute(std::string const &name, +BridgeResult opsqlite_libsql_execute(DB const &db, std::string const &query, const std::vector *params) { - check_db_open(name); - std::vector column_names; std::vector> out_rows; std::vector out_row; - libsql_connection_t c = db_map[name].c; libsql_rows_t rows; libsql_row_t row; libsql_stmt_t stmt; int status; const char *err = nullptr; - status = libsql_prepare(c, query.c_str(), &stmt, &err); + status = libsql_prepare(db.c, query.c_str(), &stmt, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } if (params != nullptr && !params->empty()) { @@ -442,7 +374,7 @@ BridgeResult opsqlite_libsql_execute(std::string const &name, status = libsql_query_stmt(stmt, &rows, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } // Get the column names on the first pass @@ -524,34 +456,30 @@ BridgeResult opsqlite_libsql_execute(std::string const &name, libsql_free_rows(rows); libsql_free_stmt(stmt); - unsigned long long changes = libsql_changes(c); - long long insert_row_id = libsql_last_insert_rowid(c); + unsigned long long changes = libsql_changes(db.c); + long long insert_row_id = libsql_last_insert_rowid(db.c); - return {.type = SQLiteOk, - .affectedRows = static_cast(changes), + return {.affectedRows = static_cast(changes), .insertId = static_cast(insert_row_id), .rows = std::move(out_rows), .column_names = std::move(column_names)}; } BridgeResult opsqlite_libsql_execute_with_host_objects( - std::string const &name, std::string const &query, + DB const &db, std::string const &query, const std::vector *params, std::vector *results, const std::shared_ptr> &metadatas) { - check_db_open(name); - - libsql_connection_t c = db_map[name].c; libsql_rows_t rows; libsql_row_t row; libsql_stmt_t stmt; int status; const char *err = nullptr; - status = libsql_prepare(c, query.c_str(), &stmt, &err); + status = libsql_prepare(db.c, query.c_str(), &stmt, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } if (params != nullptr && !params->empty()) { @@ -561,7 +489,7 @@ BridgeResult opsqlite_libsql_execute_with_host_objects( status = libsql_query_stmt(stmt, &rows, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } bool metadata_set = false; @@ -657,34 +585,30 @@ BridgeResult opsqlite_libsql_execute_with_host_objects( libsql_free_rows(rows); libsql_free_stmt(stmt); - unsigned long long changes = libsql_changes(c); - long long insert_row_id = libsql_last_insert_rowid(c); + unsigned long long changes = libsql_changes(db.c); + long long insert_row_id = libsql_last_insert_rowid(db.c); - return {.type = SQLiteOk, - .affectedRows = static_cast(changes), + return {.affectedRows = static_cast(changes), .insertId = static_cast(insert_row_id)}; } /// Executes returning data in raw arrays, a small performance optimization /// for certain use cases BridgeResult -opsqlite_libsql_execute_raw(std::string const &name, std::string const &query, +opsqlite_libsql_execute_raw(DB const &db, std::string const &query, const std::vector *params, std::vector> *results) { - check_db_open(name); - - libsql_connection_t c = db_map[name].c; libsql_rows_t rows; libsql_row_t row; libsql_stmt_t stmt; int status; const char *err = nullptr; - status = libsql_prepare(c, query.c_str(), &stmt, &err); + status = libsql_prepare(db.c, query.c_str(), &stmt, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } if (params != nullptr && !params->empty()) { @@ -694,7 +618,7 @@ opsqlite_libsql_execute_raw(std::string const &name, std::string const &query, status = libsql_query_stmt(stmt, &rows, &err); if (status != 0) { - return {.type = SQLiteError, .message = err}; + throw std::runtime_error(err); } int num_cols = libsql_column_count(rows); @@ -771,54 +695,40 @@ opsqlite_libsql_execute_raw(std::string const &name, std::string const &query, libsql_free_rows(rows); libsql_free_stmt(stmt); - unsigned long long changes = libsql_changes(c); - long long insert_row_id = libsql_last_insert_rowid(c); + unsigned long long changes = libsql_changes(db.c); + long long insert_row_id = libsql_last_insert_rowid(db.c); - return {.type = SQLiteOk, - .affectedRows = static_cast(changes), + return {.affectedRows = static_cast(changes), .insertId = static_cast(insert_row_id)}; } BatchResult -opsqlite_libsql_execute_batch(std::string const &name, +opsqlite_libsql_execute_batch(DB const &db, std::vector *commands) { size_t commandCount = commands->size(); if (commandCount <= 0) { - return BatchResult{ - .type = SQLiteError, - .message = "No SQL commands provided", - }; + throw std::runtime_error("No SQL commands provided"); } try { int affectedRows = 0; - opsqlite_libsql_execute(name, "BEGIN EXCLUSIVE TRANSACTION", nullptr); + opsqlite_libsql_execute(db, "BEGIN EXCLUSIVE TRANSACTION", nullptr); for (int i = 0; i < commandCount; i++) { auto command = commands->at(i); // We do not provide a datastructure to receive query data because we // don't need/want to handle this results in a batch execution auto result = - opsqlite_libsql_execute(name, command.sql, command.params.get()); - if (result.type == SQLiteError) { - opsqlite_libsql_execute(name, "ROLLBACK", nullptr); - return BatchResult{ - .type = SQLiteError, - .message = result.message, - }; - } else { + opsqlite_libsql_execute(db, command.sql, command.params.get()); affectedRows += result.affectedRows; - } } - opsqlite_libsql_execute(name, "COMMIT", nullptr); + opsqlite_libsql_execute(db, "COMMIT", nullptr); return BatchResult{ - .type = SQLiteOk, .affectedRows = affectedRows, .commands = static_cast(commandCount), }; } catch (std::exception &exc) { - opsqlite_libsql_execute(name, "ROLLBACK", nullptr); + opsqlite_libsql_execute(db, "ROLLBACK", nullptr); return BatchResult{ - .type = SQLiteError, .message = exc.what(), }; } diff --git a/cpp/libsql/bridge.h b/cpp/libsql/bridge.h index 5847ee5..6708612 100644 --- a/cpp/libsql/bridge.h +++ b/cpp/libsql/bridge.h @@ -24,63 +24,68 @@ typedef std::function CommitCallback; typedef std::function RollbackCallback; +struct DB { + libsql_database_t db; + libsql_connection_t c; +}; + std::string opsqlite_get_db_path(std::string const &name, std::string const &location); -BridgeResult opsqlite_libsql_open(std::string const &name, +DB opsqlite_libsql_open(std::string const &name, std::string const &path, std::string const &crsqlitePath); -BridgeResult opsqlite_libsql_open_remote(std::string const &url, +DB opsqlite_libsql_open_remote(std::string const &url, std::string const &auth_token); -BridgeResult opsqlite_libsql_open_sync(std::string const &name, +DB opsqlite_libsql_open_sync(std::string const &name, std::string const &path, std::string const &url, std::string const &auth_token, int sync_interval); -BridgeResult opsqlite_libsql_close(std::string const &name); +void opsqlite_libsql_close(DB &db); -BridgeResult opsqlite_libsql_remove(std::string const &name, +void opsqlite_libsql_remove(DB &db, std::string const &name, std::string const &path); -BridgeResult opsqlite_libsql_attach(std::string const &mainDBName, +void opsqlite_libsql_attach(DB const &db, std::string const &docPath, std::string const &databaseToAttach, std::string const &alias); -BridgeResult opsqlite_libsql_detach(std::string const &mainDBName, +void opsqlite_libsql_detach(DB const &db, std::string const &alias); -BridgeResult opsqlite_libsql_sync(std::string const &name); +void opsqlite_libsql_sync(DB const &db); -BridgeResult opsqlite_libsql_execute(std::string const &name, +BridgeResult opsqlite_libsql_execute(DB const &db, std::string const &query, const std::vector *params); BridgeResult opsqlite_libsql_execute_with_host_objects( - std::string const &name, std::string const &query, + DB const &db, std::string const &query, const std::vector *params, std::vector *results, const std::shared_ptr> &metadatas); BridgeResult -opsqlite_libsql_execute_raw(std::string const &dbName, std::string const &query, +opsqlite_libsql_execute_raw(DB const &db, std::string const &query, const std::vector *params, std::vector> *results); BatchResult -opsqlite_libsql_execute_batch(std::string const &name, +opsqlite_libsql_execute_batch(DB const &db, std::vector *commands); -libsql_stmt_t opsqlite_libsql_prepare_statement(std::string const &name, +libsql_stmt_t opsqlite_libsql_prepare_statement(DB const &db, std::string const &query); void opsqlite_libsql_bind_statement(libsql_stmt_t stmt, const std::vector *params); BridgeResult opsqlite_libsql_execute_prepared_statement( - std::string const &name, libsql_stmt_t stmt, + DB const &db, libsql_stmt_t stmt, std::vector *results, const std::shared_ptr> &metadatas);