Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a sync execute function #194

Merged
merged 6 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 36 additions & 94 deletions cpp/DBHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<jsi::Value> resolve) {
invoker->invokeAsync(
[this, resolve]() { resolve->asObject(rt).asFunction(rt).call(rt, {}); });
void DBHostObject::flush_pending_reactive_queries(
std::shared_ptr<jsi::Value> resolve) {
invoker->invokeAsync(
[this, resolve]() { resolve->asObject(rt).asFunction(rt).call(rt, {}); });
}
#else
void DBHostObject::flush_pending_reactive_queries(std::shared_ptr<jsi::Value> resolve) {
void DBHostObject::flush_pending_reactive_queries(
std::shared_ptr<jsi::Value> resolve) {
for (const auto &query_ptr : pending_reactive_queries) {
auto query = query_ptr.get();

Expand Down Expand Up @@ -51,9 +53,9 @@ void DBHostObject::flush_pending_reactive_queries(std::shared_ptr<jsi::Value> re
});
}
}
pending_reactive_queries.clear();

pending_reactive_queries.clear();

invoker->invokeAsync(
[this, resolve]() { resolve->asObject(rt).asFunction(rt).call(rt, {}); });
}
Expand Down Expand Up @@ -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<JSVariant> params;

if (count == 2) {
params = to_variant_vec(rt, args[1]);
}
#ifdef OP_SQLITE_USE_LIBSQL
auto status = opsqlite_libsql_execute(db_name, query, &params);
#else
auto status = opsqlite_execute(db_name, query, &params);
#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<JSVariant> params;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -863,97 +886,16 @@ std::vector<jsi::PropNameID> 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,
Expand Down
14 changes: 12 additions & 2 deletions example/ios/OPSQLiteExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand All @@ -29,6 +30,7 @@
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = OPSQLiteExample/LaunchScreen.storyboard; sourceTree = "<group>"; };
9218E48CFB1F478CAC374D68 /* sample2.sqlite */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = sample2.sqlite; path = ../assets/sqlite/sample2.sqlite; sourceTree = "<group>"; };
96FD9FD0FC4F4540AC7A9CE6 /* sample.sqlite */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = sample.sqlite; path = ../assets/sample.sqlite; sourceTree = "<group>"; };
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 */

Expand All @@ -37,6 +39,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
55C40F8AA9DF83E899E3CDAC /* libPods-OPSQLiteExample.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -61,6 +64,7 @@
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
D9241EC58491DCDC9B61B00F /* libPods-OPSQLiteExample.a */,
);
name = Frameworks;
sourceTree = "<group>";
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -519,7 +526,10 @@
"\"$(inherited)\"",
);
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "$(inherited) ";
OTHER_CFLAGS = (
"$(inherited)",
" ",
);
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
Expand Down
12 changes: 6 additions & 6 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
19 changes: 19 additions & 0 deletions example/src/tests/queries.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
2 changes: 1 addition & 1 deletion scripts/test-ios.sh
Original file line number Diff line number Diff line change
@@ -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
49 changes: 44 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -59,9 +61,9 @@ export type QueryResult = {
insertId?: number;
rowsAffected: number;
res?: any[];
rows: Array<Record<string, string | number | boolean | ArrayBufferLike>>;
rows: Array<Record<string, Scalar>>;
// An array of intermediate results, just values without column names
rawRows?: any[];
rawRows?: Scalar[][];
columnNames?: string[];
/**
* Query metadata, available only for select query results
Expand Down Expand Up @@ -112,7 +114,7 @@ export interface FileLoadResult extends BatchQueryResult {

export interface Transaction {
commit: () => Promise<QueryResult>;
execute: (query: string, params?: any[]) => Promise<QueryResult>;
execute: (query: string, params?: Scalar[]) => Promise<QueryResult>;
rollback: () => Promise<QueryResult>;
}

Expand Down Expand Up @@ -145,6 +147,7 @@ export type DB = {
) => void;
detach: (mainDbName: string, alias: string) => void;
transaction: (fn: (tx: Transaction) => Promise<void>) => Promise<void>;
executeSync: (query: string, params?: any[]) => QueryResult;
execute: (query: string, params?: any[]) => Promise<QueryResult>;
executeWithHostObjects: (
query: string,
Expand Down Expand Up @@ -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<string, Scalar> = {};
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<QueryResult> => {
const sanitizedParams = params?.map((p) => {
if (ArrayBuffer.isView(p)) {
Expand All @@ -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;
}
Expand Down
Loading
Loading