diff --git a/cpp/DBHostObject.cpp b/cpp/DBHostObject.cpp index c6bda2ac..66b5b0b2 100644 --- a/cpp/DBHostObject.cpp +++ b/cpp/DBHostObject.cpp @@ -17,12 +17,14 @@ namespace jsi = facebook::jsi; namespace react = facebook::react; #ifdef OP_SQLITE_USE_LIBSQL -void DBHostObject::flush_pending_reactive_queries(std::shared_ptr resolve) { - invoker->invokeAsync( - [this, resolve]() { resolve->asObject(rt).asFunction(rt).call(rt, {}); }); +void DBHostObject::flush_pending_reactive_queries( + std::shared_ptr resolve) { + invoker->invokeAsync( + [this, resolve]() { resolve->asObject(rt).asFunction(rt).call(rt, {}); }); } #else -void DBHostObject::flush_pending_reactive_queries(std::shared_ptr resolve) { +void DBHostObject::flush_pending_reactive_queries( + std::shared_ptr resolve) { for (const auto &query_ptr : pending_reactive_queries) { auto query = query_ptr.get(); @@ -51,9 +53,9 @@ void DBHostObject::flush_pending_reactive_queries(std::shared_ptr re }); } } - - pending_reactive_queries.clear(); - + + pending_reactive_queries.clear(); + invoker->invokeAsync( [this, resolve]() { resolve->asObject(rt).asFunction(rt).call(rt, {}); }); } @@ -365,6 +367,26 @@ void DBHostObject::create_jsi_functions() { return promise; }); + auto execute_sync = HOSTFN("executeSync") { + + std::string query = args[0].asString(rt).utf8(rt); + std::vector params; + + if (count == 2) { + params = to_variant_vec(rt, args[1]); + } +#ifdef OP_SQLITE_USE_LIBSQL + auto status = opsqlite_libsql_execute(db_name, query, ¶ms); +#else + auto status = opsqlite_execute(db_name, query, ¶ms); +#endif + + if (status.type != SQLiteOk) { + throw std::runtime_error(status.message); + } + return create_js_rows(rt, status); + }); + auto execute = HOSTFN("execute") { std::string query = args[0].asString(rt).utf8(rt); std::vector params; @@ -835,6 +857,7 @@ void DBHostObject::create_jsi_functions() { function_map["detach"] = std::move(detach); function_map["close"] = std::move(close); function_map["execute"] = std::move(execute); + function_map["executeSync"] = std::move(execute_sync); function_map["executeRaw"] = std::move(execute_raw); function_map["executeWithHostObjects"] = std::move(execute_with_host_objects); function_map["delete"] = std::move(remove); @@ -863,97 +886,16 @@ std::vector DBHostObject::getPropertyNames(jsi::Runtime &rt) { jsi::Value DBHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &propNameID) { - auto name = propNameID.utf8(rt); - if (name == "execute") { - return jsi::Value(rt, function_map["execute"]); - } - if (name == "flushPendingReactiveQueries") { - return jsi::Value(rt, function_map["flushPendingReactiveQueries"]); - } - if (name == "attach") { - return jsi::Value(rt, function_map["attach"]); - } - if (name == "detach") { - return jsi::Value(rt, function_map["detach"]); - } - if (name == "close") { - return jsi::Value(rt, function_map["close"]); - } - if (name == "executeRaw") { - return jsi::Value(rt, function_map["executeRaw"]); - } - if (name == "executeWithHostObjects") { - return jsi::Value(rt, function_map["executeWithHostObjects"]); - } - if (name == "delete") { - return jsi::Value(rt, function_map["delete"]); - } - if (name == "executeBatch") { - return jsi::Value(rt, function_map["executeBatch"]); - } - if (name == "prepareStatement") { - return jsi::Value(rt, function_map["prepareStatement"]); - } - if (name == "getDbPath") { - return jsi::Value(rt, function_map["getDbPath"]); - } - if (name == "sync") { - return jsi::Value(rt, function_map["sync"]); - } -#ifdef OP_SQLITE_USE_LIBSQL - if (name == "loadFile") { - return HOSTFN("loadFile") { - throw std::runtime_error("[op-sqlite] Load file not implemented"); - }); - } - if (name == "updateHook") { - return HOSTFN("updateHook") { - throw std::runtime_error("[op-sqlite] Hooks not supported in libsql"); - }); - } - if (name == "commitHook") { - return HOSTFN("commitHook") { - throw std::runtime_error("[op-sqlite] Hooks not supported in libsql"); - }); - } - if (name == "rollbackHook") { - return HOSTFN("rollbackHook") { - throw std::runtime_error("[op-sqlite] Hooks not supported in libsql"); - }); - } - if (name == "loadExtension") { - return HOSTFN("loadExtension") { - throw std::runtime_error("[op-sqlite] Hooks not supported in libsql"); - }); - } - if (name == "reactiveExecute") { - return HOSTFN("reactiveExecute") { - throw std::runtime_error("[op-sqlite] Hooks not supported in libsql"); + if (function_map.count(name) != 1) { + return HOSTFN(name.c_str()) { + throw std::runtime_error( + "[op-sqlite] Function " + name + + " not implemented for current backend (libsql or sqlcipher)"); }); } -#else - if (name == "loadFile") { - return jsi::Value(rt, function_map["loadFile"]); - } - if (name == "updateHook") { - return jsi::Value(rt, function_map["updateHook"]); - } - if (name == "commitHook") { - return jsi::Value(rt, function_map["commitHook"]); - } - if (name == "rollbackHook") { - return jsi::Value(rt, function_map["rollbackHook"]); - } - if (name == "loadExtension") { - return jsi::Value(rt, function_map["loadExtension"]); - } - if (name == "reactiveExecute") { - return jsi::Value(rt, function_map["reactiveExecute"]); - } -#endif - return {}; + return jsi::Value(rt, function_map[name]); } void DBHostObject::set(jsi::Runtime &rt, const jsi::PropNameID &name, diff --git a/example/ios/OPSQLiteExample.xcodeproj/project.pbxproj b/example/ios/OPSQLiteExample.xcodeproj/project.pbxproj index 5f37d426..6ccb4fdf 100644 --- a/example/ios/OPSQLiteExample.xcodeproj/project.pbxproj +++ b/example/ios/OPSQLiteExample.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 55C40F8AA9DF83E899E3CDAC /* libPods-OPSQLiteExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D9241EC58491DCDC9B61B00F /* libPods-OPSQLiteExample.a */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; 92B54B8E74B0B43081C567EF /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 2C08DBE2BF8FD676ED5D600B /* PrivacyInfo.xcprivacy */; }; AC1DF06E9759460CAA51B7B1 /* sample2.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = 9218E48CFB1F478CAC374D68 /* sample2.sqlite */; }; @@ -29,6 +30,7 @@ 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = OPSQLiteExample/LaunchScreen.storyboard; sourceTree = ""; }; 9218E48CFB1F478CAC374D68 /* sample2.sqlite */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = sample2.sqlite; path = ../assets/sqlite/sample2.sqlite; sourceTree = ""; }; 96FD9FD0FC4F4540AC7A9CE6 /* sample.sqlite */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = sample.sqlite; path = ../assets/sample.sqlite; sourceTree = ""; }; + D9241EC58491DCDC9B61B00F /* libPods-OPSQLiteExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-OPSQLiteExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ @@ -37,6 +39,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 55C40F8AA9DF83E899E3CDAC /* libPods-OPSQLiteExample.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -61,6 +64,7 @@ isa = PBXGroup; children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + D9241EC58491DCDC9B61B00F /* libPods-OPSQLiteExample.a */, ); name = Frameworks; sourceTree = ""; @@ -432,7 +436,10 @@ ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = "$(inherited) "; + OTHER_CFLAGS = ( + "$(inherited)", + " ", + ); OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", @@ -519,7 +526,10 @@ "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = NO; - OTHER_CFLAGS = "$(inherited) "; + OTHER_CFLAGS = ( + "$(inherited)", + " ", + ); OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index e97522e7..94a0cee1 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -10,7 +10,7 @@ PODS: - hermes-engine (0.76.1): - hermes-engine/Pre-built (= 0.76.1) - hermes-engine/Pre-built (0.76.1) - - op-sqlite (10.1.0): + - op-sqlite (0.0.0): - DoubleConversion - glog - hermes-engine @@ -1779,14 +1779,14 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: 1dca942403ed9342f98334bf4c3621f011aa7946 - DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5 + DoubleConversion: f16ae600a246532c4020132d54af21d0ddb2a385 FBLazyVector: 7075bb12898bc3998fd60f4b7ca422496cc2cdf7 - fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120 + fmt: 10c6e61f4be25dc963c36bd73fc7b1705fe975be GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 - glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 + glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a hermes-engine: 46f1ffbf0297f4298862068dd4c274d4ac17a1fd - op-sqlite: 09176c1312198acd6da5847bc0003ce641b4c8f0 - RCT-Folly: 045d6ecaa59d826c5736dfba0b2f4083ff8d79df + op-sqlite: 9917e5a5747fc813e42487c0cbdd2d35eaa687bb + RCT-Folly: bf5c0376ffe4dd2cf438dcf86db385df9fdce648 RCTDeprecation: fde92935b3caa6cb65cbff9fbb7d3a9867ffb259 RCTRequired: 75c6cee42d21c1530a6f204ba32ff57335d19007 RCTTypeSafety: 7e6fe47bfb693c50d4669db1a480ca5331795f5b diff --git a/example/src/tests/queries.spec.ts b/example/src/tests/queries.spec.ts index e27660e2..845ed2b1 100644 --- a/example/src/tests/queries.spec.ts +++ b/example/src/tests/queries.spec.ts @@ -67,6 +67,25 @@ export function queriesTests() { // }); // } + it('executeSync', () => { + const res = db.executeSync('SELECT 1'); + expect(res.rowsAffected).to.equal(0); + + const id = chance.integer(); + const name = chance.name(); + const age = chance.integer(); + const networth = chance.floating(); + const res2 = db.executeSync( + 'INSERT INTO "User" (id, name, age, networth) VALUES(?, ?, ?, ?)', + [id, name, age, networth], + ); + + expect(res2.rowsAffected).to.equal(1); + expect(res2.insertId).to.equal(1); + expect(res2.rows).to.eql([]); + expect(res2.rows?.length).to.equal(0); + }); + it('Insert', async () => { const id = chance.integer(); const name = chance.name(); diff --git a/package.json b/package.json index 2bf1b86d..e3f67cab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@op-engineering/op-sqlite", - "version": "11.0.2", + "version": "0.0.0", "description": "Next generation SQLite for React Native", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/scripts/test-ios.sh b/scripts/test-ios.sh index 7d1b2933..f7ba46f0 100755 --- a/scripts/test-ios.sh +++ b/scripts/test-ios.sh @@ -1,5 +1,5 @@ #!/bin/bash -yarn turbo run run:ios --cache-dir=.turbo/ios +yarn run run:ios echo "Polling in-app server..." node ./scripts/poll-in-app-server.js \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 3477d3fd..42be8dfd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -45,6 +45,8 @@ export const { ? NativeModules.OPSQLite.getConstants() : NativeModules.OPSQLite; +type Scalar = string | number | boolean | null | ArrayBuffer | ArrayBufferView; + /** * Object returned by SQL Query executions { * insertId: Represent the auto-generated row id if applicable @@ -59,9 +61,9 @@ export type QueryResult = { insertId?: number; rowsAffected: number; res?: any[]; - rows: Array>; + rows: Array>; // An array of intermediate results, just values without column names - rawRows?: any[]; + rawRows?: Scalar[][]; columnNames?: string[]; /** * Query metadata, available only for select query results @@ -112,7 +114,7 @@ export interface FileLoadResult extends BatchQueryResult { export interface Transaction { commit: () => Promise; - execute: (query: string, params?: any[]) => Promise; + execute: (query: string, params?: Scalar[]) => Promise; rollback: () => Promise; } @@ -145,6 +147,7 @@ export type DB = { ) => void; detach: (mainDbName: string, alias: string) => void; transaction: (fn: (tx: Transaction) => Promise) => Promise; + executeSync: (query: string, params?: any[]) => QueryResult; execute: (query: string, params?: any[]) => Promise; executeWithHostObjects: ( query: string, @@ -273,9 +276,44 @@ function enhanceDB(db: DB, options: any): DB { return result; }, + executeSync: ( + query: string, + params?: Scalar[] | undefined + ): QueryResult => { + const sanitizedParams = params?.map((p) => { + if (ArrayBuffer.isView(p)) { + return p.buffer; + } + + return p; + }); + + let intermediateResult = db.executeSync(query, sanitizedParams); + let rows: any[] = []; + for (let i = 0; i < (intermediateResult.rawRows?.length ?? 0); i++) { + let row: Record = {}; + let rawRow = intermediateResult.rawRows![i]!; + for (let j = 0; j < intermediateResult.columnNames!.length; j++) { + let columnName = intermediateResult.columnNames![j]!; + let value = rawRow[j]!; + + row[columnName] = value; + } + rows.push(row); + } + + let res = { + ...intermediateResult, + rows, + }; + + delete res.rawRows; + + return res; + }, execute: async ( query: string, - params?: any[] | undefined + params?: Scalar[] | undefined ): Promise => { const sanitizedParams = params?.map((p) => { if (ArrayBuffer.isView(p)) { @@ -290,9 +328,10 @@ function enhanceDB(db: DB, options: any): DB { let rows: any[] = []; for (let i = 0; i < (intermediateResult.rawRows?.length ?? 0); i++) { let row: any = {}; + let rawRow = intermediateResult.rawRows![i]!; for (let j = 0; j < intermediateResult.columnNames!.length; j++) { let columnName = intermediateResult.columnNames![j]!; - let value = intermediateResult.rawRows![i][j]; + let value = rawRow[j]!; row[columnName] = value; } diff --git a/turbo.json b/turbo.json index e5c3058c..b1c666aa 100644 --- a/turbo.json +++ b/turbo.json @@ -7,10 +7,12 @@ "android", "!android/build", "src/*.ts", - "src/tests/*.ts", + "example/src/tests/**.ts", "example/package.json", "example/android", - "cpp", + "cpp/**.cpp", + "cpp/**/*.c", + "cpp/*.h", "!example/android/.gradle", "!example/android/build", "!example/android/app/build" @@ -22,9 +24,11 @@ "package.json", "*.podspec", "ios", - "cpp", + "cpp/**/*.cpp", + "cpp/**/*.c", + "cpp/*.h", "src/*.ts", - "src/tests/*.ts", + "example/src/tests/**.ts", "example/package.json", "example/ios", "!example/ios/build",