@op-engineering/op-sqlite 0.0.0-resolution-test

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +31 -0
  3. package/android/.project +17 -0
  4. package/android/.settings/org.eclipse.buildship.core.prefs +13 -0
  5. package/android/CMakeLists.txt +141 -0
  6. package/android/build.gradle +266 -0
  7. package/android/c_sources/tokenizers.cpp +88 -0
  8. package/android/c_sources/tokenizers.h +15 -0
  9. package/android/cpp-adapter.cpp +46 -0
  10. package/android/gradle.properties +1 -0
  11. package/android/jniLibs/arm64-v8a/libsql_experimental.a +0 -0
  12. package/android/jniLibs/armeabi-v7a/libsql_experimental.a +0 -0
  13. package/android/jniLibs/x86/libsql_experimental.a +0 -0
  14. package/android/jniLibs/x86_64/libsql_experimental.a +0 -0
  15. package/android/src/main/AndroidManifest.xml +1 -0
  16. package/android/src/main/java/com/op/sqlite/OPSQLiteBridge.kt +37 -0
  17. package/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt +119 -0
  18. package/android/src/main/java/com/op/sqlite/OPSQLitePackage.kt +18 -0
  19. package/android/src/main/jniLibs/arm64-v8a/libcrsqlite.so +0 -0
  20. package/android/src/main/jniLibs/arm64-v8a/libsqlite_vec.so +0 -0
  21. package/android/src/main/jniLibs/armeabi-v7a/libcrsqlite.so +0 -0
  22. package/android/src/main/jniLibs/armeabi-v7a/libsqlite_vec.so +0 -0
  23. package/android/src/main/jniLibs/x86/libcrsqlite.so +0 -0
  24. package/android/src/main/jniLibs/x86/libsqlite_vec.so +0 -0
  25. package/android/src/main/jniLibs/x86_64/libcrsqlite.so +0 -0
  26. package/android/src/main/jniLibs/x86_64/libsqlite_vec.so +0 -0
  27. package/android/src/paper/java/com/op/sqlite/NativeOPSQLiteSpec.java +77 -0
  28. package/cpp/DBHostObject.cpp +852 -0
  29. package/cpp/DBHostObject.h +99 -0
  30. package/cpp/DumbHostObject.cpp +72 -0
  31. package/cpp/DumbHostObject.h +36 -0
  32. package/cpp/OPThreadPool.cpp +120 -0
  33. package/cpp/OPThreadPool.h +44 -0
  34. package/cpp/PreparedStatementHostObject.cpp +151 -0
  35. package/cpp/PreparedStatementHostObject.h +59 -0
  36. package/cpp/SmartHostObject.cpp +34 -0
  37. package/cpp/SmartHostObject.h +24 -0
  38. package/cpp/bindings.cpp +182 -0
  39. package/cpp/bindings.h +19 -0
  40. package/cpp/bridge.cpp +873 -0
  41. package/cpp/bridge.h +80 -0
  42. package/cpp/libsql/bridge.cpp +738 -0
  43. package/cpp/libsql/bridge.h +85 -0
  44. package/cpp/libsql/libsql.h +172 -0
  45. package/cpp/logs.h +40 -0
  46. package/cpp/macros.h +15 -0
  47. package/cpp/sqlcipher/sqlite3.c +262970 -0
  48. package/cpp/sqlcipher/sqlite3.h +13485 -0
  49. package/cpp/sqlite3.c +261454 -0
  50. package/cpp/sqlite3.h +13715 -0
  51. package/cpp/types.h +33 -0
  52. package/cpp/utils.cpp +327 -0
  53. package/cpp/utils.h +47 -0
  54. package/generate_tokenizers_header_file.rb +29 -0
  55. package/ios/OPSQLite.h +7 -0
  56. package/ios/OPSQLite.mm +157 -0
  57. package/ios/OPSQLite.xcodeproj/project.pbxproj +275 -0
  58. package/ios/crsqlite.xcframework/Info.plist +46 -0
  59. package/ios/crsqlite.xcframework/ios-arm64/crsqlite.framework/Info.plist +24 -0
  60. package/ios/crsqlite.xcframework/ios-arm64/crsqlite.framework/crsqlite +0 -0
  61. package/ios/crsqlite.xcframework/ios-arm64_x86_64-simulator/crsqlite.framework/Info.plist +24 -0
  62. package/ios/crsqlite.xcframework/ios-arm64_x86_64-simulator/crsqlite.framework/crsqlite +0 -0
  63. package/ios/libsql.xcframework/Info.plist +48 -0
  64. package/ios/libsql.xcframework/ios-arm64/Headers/libsql.h +172 -0
  65. package/ios/libsql.xcframework/ios-arm64/libsql_experimental.a +0 -0
  66. package/ios/libsql.xcframework/ios-arm64_x86_64-simulator/Headers/libsql.h +172 -0
  67. package/ios/libsql.xcframework/ios-arm64_x86_64-simulator/libsql_experimental.a +0 -0
  68. package/ios/sqlitevec.xcframework/Info.plist +71 -0
  69. package/ios/sqlitevec.xcframework/ios-arm64/sqlitevec.framework/Info.plist +24 -0
  70. package/ios/sqlitevec.xcframework/ios-arm64/sqlitevec.framework/sqlitevec +0 -0
  71. package/ios/sqlitevec.xcframework/ios-arm64_x86_64-simulator/sqlitevec.framework/Info.plist +24 -0
  72. package/ios/sqlitevec.xcframework/ios-arm64_x86_64-simulator/sqlitevec.framework/sqlitevec +0 -0
  73. package/ios/sqlitevec.xcframework/tvos-arm64/sqlitevec.framework/Info.plist +24 -0
  74. package/ios/sqlitevec.xcframework/tvos-arm64/sqlitevec.framework/sqlitevec +0 -0
  75. package/ios/sqlitevec.xcframework/tvos-arm64_x86_64-simulator/sqlitevec.framework/Info.plist +24 -0
  76. package/ios/sqlitevec.xcframework/tvos-arm64_x86_64-simulator/sqlitevec.framework/sqlitevec +0 -0
  77. package/lib/commonjs/NativeOPSQLite.js +9 -0
  78. package/lib/commonjs/NativeOPSQLite.js.map +1 -0
  79. package/lib/commonjs/Storage.js +60 -0
  80. package/lib/commonjs/Storage.js.map +1 -0
  81. package/lib/commonjs/index.js +365 -0
  82. package/lib/commonjs/index.js.map +1 -0
  83. package/lib/module/NativeOPSQLite.js +3 -0
  84. package/lib/module/NativeOPSQLite.js.map +1 -0
  85. package/lib/module/Storage.js +53 -0
  86. package/lib/module/Storage.js.map +1 -0
  87. package/lib/module/index.js +340 -0
  88. package/lib/module/index.js.map +1 -0
  89. package/lib/typescript/src/NativeOPSQLite.d.ts +15 -0
  90. package/lib/typescript/src/NativeOPSQLite.d.ts.map +1 -0
  91. package/lib/typescript/src/Storage.d.ts +23 -0
  92. package/lib/typescript/src/Storage.d.ts.map +1 -0
  93. package/lib/typescript/src/index.d.ts +319 -0
  94. package/lib/typescript/src/index.d.ts.map +1 -0
  95. package/op-sqlite.podspec +212 -0
  96. package/package.json +85 -0
  97. package/src/NativeOPSQLite.ts +17 -0
  98. package/src/Storage.ts +85 -0
  99. package/src/index.ts +722 -0
@@ -0,0 +1,852 @@
1
+ #include "DBHostObject.h"
2
+ #include "PreparedStatementHostObject.h"
3
+ #if OP_SQLITE_USE_LIBSQL
4
+ #include "libsql/bridge.h"
5
+ #else
6
+ #include "bridge.h"
7
+ #endif
8
+ #include "logs.h"
9
+ #include "macros.h"
10
+ #include "utils.h"
11
+ #include <iostream>
12
+ #include <utility>
13
+
14
+ namespace opsqlite {
15
+
16
+ namespace jsi = facebook::jsi;
17
+ namespace react = facebook::react;
18
+
19
+ #ifdef OP_SQLITE_USE_LIBSQL
20
+ void DBHostObject::flush_pending_reactive_queries(
21
+ const std::shared_ptr<jsi::Value> &resolve) {
22
+ invoker->invokeAsync([this, resolve]() {
23
+ resolve->asObject(rt).asFunction(rt).call(rt, {});
24
+ });
25
+ }
26
+ #else
27
+ void DBHostObject::flush_pending_reactive_queries(
28
+ const std::shared_ptr<jsi::Value> &resolve) {
29
+ for (const auto &query_ptr : pending_reactive_queries) {
30
+ auto query = query_ptr.get();
31
+
32
+ std::vector<DumbHostObject> results;
33
+ std::shared_ptr<std::vector<SmartHostObject>> metadata =
34
+ std::make_shared<std::vector<SmartHostObject>>();
35
+
36
+ auto status = opsqlite_execute_prepared_statement(db, query->stmt,
37
+ &results, metadata);
38
+
39
+ invoker->invokeAsync(
40
+ [this,
41
+ results = std::make_shared<std::vector<DumbHostObject>>(results),
42
+ callback = query->callback, metadata, status = std::move(status)] {
43
+ auto jsiResult =
44
+ create_result(rt, status, results.get(), metadata);
45
+ callback->asObject(rt).asFunction(rt).call(rt, jsiResult);
46
+ });
47
+ }
48
+
49
+ pending_reactive_queries.clear();
50
+
51
+ invoker->invokeAsync([this, resolve]() {
52
+ resolve->asObject(rt).asFunction(rt).call(rt, {});
53
+ });
54
+ }
55
+
56
+ void DBHostObject::on_commit() {
57
+ invoker->invokeAsync(
58
+ [this] { commit_hook_callback->asObject(rt).asFunction(rt).call(rt); });
59
+ }
60
+
61
+ void DBHostObject::on_rollback() {
62
+ invoker->invokeAsync([this] {
63
+ rollback_hook_callback->asObject(rt).asFunction(rt).call(rt);
64
+ });
65
+ }
66
+
67
+ void DBHostObject::on_update(const std::string &table,
68
+ const std::string &operation, long long row_id) {
69
+ if (update_hook_callback != nullptr) {
70
+ invoker->invokeAsync(
71
+ [this, callback = update_hook_callback, table, operation, row_id] {
72
+ auto res = jsi::Object(rt);
73
+ res.setProperty(rt, "table",
74
+ jsi::String::createFromUtf8(rt, table));
75
+ res.setProperty(rt, "operation",
76
+ jsi::String::createFromUtf8(rt, operation));
77
+ res.setProperty(rt, "rowId",
78
+ jsi::Value(static_cast<double>(row_id)));
79
+
80
+ callback->asObject(rt).asFunction(rt).call(rt, res);
81
+ });
82
+ }
83
+
84
+ for (const auto &query_ptr : reactive_queries) {
85
+ auto query = query_ptr.get();
86
+ if (query->discriminators.empty()) {
87
+ continue;
88
+ }
89
+
90
+ bool shouldFire = false;
91
+
92
+ for (const auto &discriminator : query->discriminators) {
93
+ // Tables don't match then skip
94
+ if (discriminator.table != table) {
95
+ continue;
96
+ }
97
+
98
+ // If no ids are specified, then we should fire
99
+ if (discriminator.ids.empty()) {
100
+ shouldFire = true;
101
+ break;
102
+ }
103
+
104
+ // If ids are specified, then we should check if the rowId matches
105
+ for (const auto &discrimator_id : discriminator.ids) {
106
+ if (row_id == discrimator_id) {
107
+ shouldFire = true;
108
+ break;
109
+ }
110
+ }
111
+ }
112
+
113
+ if (shouldFire) {
114
+ pending_reactive_queries.insert(query_ptr);
115
+ }
116
+ }
117
+ }
118
+
119
+ void DBHostObject::auto_register_update_hook() {
120
+ if (update_hook_callback == nullptr && reactive_queries.empty() &&
121
+ is_update_hook_registered) {
122
+ opsqlite_deregister_update_hook(db);
123
+ is_update_hook_registered = false;
124
+ return;
125
+ }
126
+
127
+ if (is_update_hook_registered) {
128
+ return;
129
+ }
130
+
131
+ opsqlite_register_update_hook(db, this);
132
+ is_update_hook_registered = true;
133
+ }
134
+ #endif
135
+
136
+ // _____ _ _
137
+ // / ____| | | | |
138
+ // | | ___ _ __ ___| |_ _ __ _ _ ___| |_ ___ _ __
139
+ // | | / _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__|
140
+ // | |___| (_) | | | \__ \ |_| | | |_| | (__| || (_) | |
141
+ // \_____\___/|_| |_|___/\__|_| \__,_|\___|\__\___/|_|
142
+ #ifdef OP_SQLITE_USE_LIBSQL
143
+ DBHostObject::DBHostObject(jsi::Runtime &rt, std::string &url,
144
+ std::string &auth_token,
145
+ std::shared_ptr<react::CallInvoker> invoker)
146
+ : db_name(url), invoker(std::move(invoker)), rt(rt) {
147
+ _thread_pool = std::make_shared<ThreadPool>();
148
+ db = opsqlite_libsql_open_remote(url, auth_token);
149
+
150
+ create_jsi_functions();
151
+ }
152
+
153
+ DBHostObject::DBHostObject(jsi::Runtime &rt,
154
+ std::shared_ptr<react::CallInvoker> invoker,
155
+ std::string &db_name, std::string &path,
156
+ std::string &url, std::string &auth_token,
157
+ int sync_interval)
158
+ : db_name(db_name), invoker(std::move(invoker)), rt(rt) {
159
+ _thread_pool = std::make_shared<ThreadPool>();
160
+ db = opsqlite_libsql_open_sync(db_name, path, url, auth_token,
161
+ sync_interval);
162
+
163
+ create_jsi_functions();
164
+ }
165
+
166
+ #endif
167
+
168
+ DBHostObject::DBHostObject(jsi::Runtime &rt, std::string &base_path,
169
+ std::shared_ptr<react::CallInvoker> invoker,
170
+ std::string &db_name, std::string &path,
171
+ std::string &crsqlite_path,
172
+ std::string &sqlite_vec_path,
173
+ std::string &encryption_key)
174
+ : base_path(base_path), invoker(std::move(invoker)), db_name(db_name),
175
+ rt(rt) {
176
+ _thread_pool = std::make_shared<ThreadPool>();
177
+
178
+ #ifdef OP_SQLITE_USE_SQLCIPHER
179
+ db = opsqlite_open(db_name, path, crsqlite_path, sqlite_vec_path,
180
+ encryption_key);
181
+ #elif OP_SQLITE_USE_LIBSQL
182
+ db = opsqlite_libsql_open(db_name, path, crsqlite_path);
183
+ #else
184
+ db = opsqlite_open(db_name, path, crsqlite_path, sqlite_vec_path);
185
+ #endif
186
+ create_jsi_functions();
187
+ };
188
+
189
+ void DBHostObject::create_jsi_functions() {
190
+ function_map["attach"] = HOSTFN("attach") {
191
+ std::string secondary_db_path = std::string(base_path);
192
+
193
+ auto obj_params = args[0].asObject(rt);
194
+
195
+ std::string secondary_db_name =
196
+ obj_params.getProperty(rt, "secondaryDbFileName")
197
+ .asString(rt)
198
+ .utf8(rt);
199
+ std::string alias =
200
+ obj_params.getProperty(rt, "alias").asString(rt).utf8(rt);
201
+
202
+ if (obj_params.hasProperty(rt, "location")) {
203
+ std::string location =
204
+ obj_params.getProperty(rt, "location").asString(rt).utf8(rt);
205
+ secondary_db_path = secondary_db_path + location;
206
+ }
207
+
208
+ #ifdef OP_SQLITE_USE_LIBSQL
209
+ opsqlite_libsql_attach(db, secondary_db_path, secondary_db_name, alias);
210
+ #else
211
+ opsqlite_attach(db, secondary_db_path, secondary_db_name, alias);
212
+ #endif
213
+
214
+ return {};
215
+ });
216
+
217
+ function_map["detach"] = HOSTFN("detach") {
218
+
219
+ if (!args[0].isString()) {
220
+ throw std::runtime_error("[op-sqlite] alias must be a strings");
221
+ }
222
+
223
+ std::string alias = args[0].asString(rt).utf8(rt);
224
+ #ifdef OP_SQLITE_USE_LIBSQL
225
+ opsqlite_libsql_detach(db, alias);
226
+ #else
227
+ opsqlite_detach(db, alias);
228
+ #endif
229
+
230
+ return {};
231
+ });
232
+
233
+ function_map["close"] = HOSTFN("close") {
234
+ invalidated = true;
235
+
236
+ #ifdef OP_SQLITE_USE_LIBSQL
237
+ opsqlite_libsql_close(db);
238
+ #else
239
+ opsqlite_close(db);
240
+ #endif
241
+
242
+ return {};
243
+ });
244
+
245
+ function_map["delete"] = HOSTFN("delete") {
246
+ invalidated = true;
247
+
248
+ std::string path = std::string(base_path);
249
+
250
+ if (count == 1) {
251
+ if (!args[1].isString()) {
252
+ throw std::runtime_error(
253
+ "[op-sqlite][open] database location must be a string");
254
+ }
255
+
256
+ std::string location = args[1].asString(rt).utf8(rt);
257
+
258
+ if (!location.empty()) {
259
+ if (location == ":memory:") {
260
+ path = ":memory:";
261
+ } else if (location.rfind('/', 0) == 0) {
262
+ path = location;
263
+ } else {
264
+ path = path + "/" + location;
265
+ }
266
+ }
267
+ }
268
+
269
+ #ifdef OP_SQLITE_USE_LIBSQL
270
+ opsqlite_libsql_remove(db, db_name, path);
271
+ #else
272
+ opsqlite_remove(db, db_name, path);
273
+ #endif
274
+
275
+ return {};
276
+ });
277
+
278
+ function_map["executeRaw"] = HOSTFN("executeRaw") {
279
+ const std::string query = args[0].asString(rt).utf8(rt);
280
+ std::vector<JSVariant> params = count == 2 && args[1].isObject()
281
+ ? to_variant_vec(rt, args[1])
282
+ : std::vector<JSVariant>();
283
+
284
+ auto promiseCtr = rt.global().getPropertyAsFunction(rt, "Promise");
285
+ auto promise = promiseCtr.callAsConstructor(rt, HOSTFN("executor") {
286
+ auto resolve = std::make_shared<jsi::Value>(rt, args[0]);
287
+ auto reject = std::make_shared<jsi::Value>(rt, args[1]);
288
+
289
+ auto task = [this, &rt, query, params, resolve, reject]() {
290
+ try {
291
+ std::vector<std::vector<JSVariant>> results;
292
+
293
+ #ifdef OP_SQLITE_USE_LIBSQL
294
+ auto status = opsqlite_libsql_execute_raw(
295
+ db, query, &params, &results);
296
+ #else
297
+ auto status =
298
+ opsqlite_execute_raw(db, query, &params, &results);
299
+ #endif
300
+
301
+ if (invalidated) {
302
+ return;
303
+ }
304
+
305
+ invoker->invokeAsync([&rt, results = std::move(results),
306
+ status = std::move(status), resolve,
307
+ reject] {
308
+ auto jsiResult =
309
+ create_raw_result(rt, status, &results);
310
+ resolve->asObject(rt).asFunction(rt).call(
311
+ rt, std::move(jsiResult));
312
+ });
313
+ } catch (std::runtime_error &e) {
314
+ auto what = e.what();
315
+ invoker->invokeAsync([&rt, what, reject] {
316
+ auto errorCtr =
317
+ rt.global().getPropertyAsFunction(rt, "Error");
318
+ auto error = errorCtr.callAsConstructor(
319
+ rt, jsi::String::createFromAscii(rt, what));
320
+ reject->asObject(rt).asFunction(rt).call(rt, error);
321
+ });
322
+ } catch (std::exception &exc) {
323
+ auto what = exc.what();
324
+ invoker->invokeAsync([&rt, what, reject] {
325
+ auto errorCtr =
326
+ rt.global().getPropertyAsFunction(rt, "Error");
327
+ auto error = errorCtr.callAsConstructor(
328
+ rt, jsi::String::createFromAscii(rt, what));
329
+ reject->asObject(rt).asFunction(rt).call(rt, error);
330
+ });
331
+ }
332
+ };
333
+
334
+ _thread_pool->queueWork(task);
335
+
336
+ return {};
337
+ }));
338
+
339
+ return promise;
340
+ });
341
+
342
+ function_map["executeSync"] = HOSTFN("executeSync") {
343
+ std::string query = args[0].asString(rt).utf8(rt);
344
+ std::vector<JSVariant> params;
345
+
346
+ if (count == 2) {
347
+ params = to_variant_vec(rt, args[1]);
348
+ }
349
+ #ifdef OP_SQLITE_USE_LIBSQL
350
+ auto status = opsqlite_libsql_execute(db, query, &params);
351
+ #else
352
+ auto status = opsqlite_execute(db, query, &params);
353
+ #endif
354
+
355
+ return create_js_rows(rt, status);
356
+ });
357
+
358
+ function_map["execute"] = HOSTFN("execute") {
359
+ const std::string query = args[0].asString(rt).utf8(rt);
360
+ std::vector<JSVariant> params = count == 2 && args[1].isObject()
361
+ ? to_variant_vec(rt, args[1])
362
+ : std::vector<JSVariant>();
363
+
364
+ auto promiseCtr = rt.global().getPropertyAsFunction(rt, "Promise");
365
+ auto promise = promiseCtr.callAsConstructor(rt,
366
+ HOSTFN("executor") {
367
+ auto task = [this, &rt, query, params,
368
+ resolve = std::make_shared<jsi::Value>(rt, args[0]),
369
+ reject = std::make_shared<jsi::Value>(rt, args[1])]() {
370
+ try {
371
+ #ifdef OP_SQLITE_USE_LIBSQL
372
+ auto status = opsqlite_libsql_execute(db, query, &params);
373
+ #else
374
+ auto status = opsqlite_execute(db, query, &params);
375
+ #endif
376
+
377
+ if (invalidated) {
378
+ return;
379
+ }
380
+
381
+ invoker->invokeAsync(
382
+ [&rt, status = std::move(status), resolve, reject] {
383
+ auto jsiResult = create_js_rows(rt, status);
384
+ resolve->asObject(rt).asFunction(rt).call(
385
+ rt, std::move(jsiResult));
386
+ });
387
+ // On Android RN is broken and does not correctly match
388
+ // runtime_error to the generic exception We have to
389
+ // explicitly catch it
390
+ // https://github.com/facebook/react-native/issues/48027
391
+ } catch (std::runtime_error &e) {
392
+ auto what = e.what();
393
+ invoker->invokeAsync(
394
+ [&rt, what = std::string(what), reject] {
395
+ auto errorCtr =
396
+ rt.global().getPropertyAsFunction(rt, "Error");
397
+ auto error = errorCtr.callAsConstructor(
398
+ rt, jsi::String::createFromAscii(rt, what));
399
+ reject->asObject(rt).asFunction(rt).call(rt, error);
400
+ });
401
+ } catch (std::exception &exc) {
402
+ auto what = exc.what();
403
+ invoker->invokeAsync(
404
+ [&rt, what = std::string(what), reject] {
405
+ auto errorCtr =
406
+ rt.global().getPropertyAsFunction(rt, "Error");
407
+ auto error = errorCtr.callAsConstructor(
408
+ rt, jsi::String::createFromAscii(rt, what));
409
+ reject->asObject(rt).asFunction(rt).call(rt, error);
410
+ });
411
+ }
412
+ };
413
+
414
+ _thread_pool->queueWork(task);
415
+
416
+ return {};
417
+ }));
418
+
419
+ return promise;
420
+ });
421
+
422
+ function_map["executeWithHostObjects"] = HOSTFN("executeWithHostObjects") {
423
+ const std::string query = args[0].asString(rt).utf8(rt);
424
+ std::vector<JSVariant> params;
425
+
426
+ if (count == 2) {
427
+ const jsi::Value &originalParams = args[1];
428
+ params = to_variant_vec(rt, originalParams);
429
+ }
430
+
431
+ auto promiseCtr = rt.global().getPropertyAsFunction(rt, "Promise");
432
+ auto promise = promiseCtr.callAsConstructor(rt, HOSTFN("executor") {
433
+ auto resolve = std::make_shared<jsi::Value>(rt, args[0]);
434
+ auto reject = std::make_shared<jsi::Value>(rt, args[1]);
435
+
436
+ auto task = [&rt, this, query, params, resolve, reject]() {
437
+ try {
438
+ std::vector<DumbHostObject> results;
439
+ std::shared_ptr<std::vector<SmartHostObject>> metadata =
440
+ std::make_shared<std::vector<SmartHostObject>>();
441
+ #ifdef OP_SQLITE_USE_LIBSQL
442
+ auto status = opsqlite_libsql_execute_with_host_objects(
443
+ db, query, &params, &results, metadata);
444
+ #else
445
+ auto status = opsqlite_execute_host_objects(
446
+ db, query, &params, &results, metadata);
447
+ #endif
448
+
449
+ if (invalidated) {
450
+ return;
451
+ }
452
+
453
+ invoker->invokeAsync(
454
+ [&rt,
455
+ results =
456
+ std::make_shared<std::vector<DumbHostObject>>(
457
+ results),
458
+ metadata, status = std::move(status), resolve,
459
+ reject] {
460
+ auto jsiResult = create_result(
461
+ rt, status, results.get(), metadata);
462
+ resolve->asObject(rt).asFunction(rt).call(
463
+ rt, std::move(jsiResult));
464
+ });
465
+ } catch (std::runtime_error &e) {
466
+ auto what = e.what();
467
+ invoker->invokeAsync(
468
+ [&rt, what = std::string(what), reject] {
469
+ auto errorCtr =
470
+ rt.global().getPropertyAsFunction(rt, "Error");
471
+ auto error = errorCtr.callAsConstructor(
472
+ rt, jsi::String::createFromAscii(rt, what));
473
+ reject->asObject(rt).asFunction(rt).call(rt, error);
474
+ });
475
+ } catch (std::exception &exc) {
476
+ auto what = exc.what();
477
+ invoker->invokeAsync([&rt, what, reject] {
478
+ auto errorCtr =
479
+ rt.global().getPropertyAsFunction(rt, "Error");
480
+ auto error = errorCtr.callAsConstructor(
481
+ rt, jsi::String::createFromAscii(rt, what));
482
+ reject->asObject(rt).asFunction(rt).call(rt, error);
483
+ });
484
+ }
485
+ };
486
+
487
+ _thread_pool->queueWork(task);
488
+
489
+ return {};
490
+ }));
491
+
492
+ return promise;
493
+ });
494
+
495
+ function_map["executeBatch"] = HOSTFN("executeBatch") {
496
+ if (count < 1) {
497
+ throw std::runtime_error(
498
+ "[op-sqlite][executeAsyncBatch] Incorrect parameter count");
499
+ }
500
+
501
+ const jsi::Value &params = args[0];
502
+
503
+ if (params.isNull() || params.isUndefined()) {
504
+ throw std::runtime_error(
505
+ "[op-sqlite][executeAsyncBatch] - An array of SQL "
506
+ "commands or parameters is needed");
507
+ }
508
+
509
+ const jsi::Array &batchParams = params.asObject(rt).asArray(rt);
510
+
511
+ std::vector<BatchArguments> commands;
512
+ to_batch_arguments(rt, batchParams, &commands);
513
+
514
+ auto promiseCtr = rt.global().getPropertyAsFunction(rt, "Promise");
515
+ auto promise = promiseCtr.callAsConstructor(rt, HOSTFN("executor") {
516
+ auto resolve = std::make_shared<jsi::Value>(rt, args[0]);
517
+ auto reject = std::make_shared<jsi::Value>(rt, args[1]);
518
+
519
+ auto task = [this, &rt, commands, resolve, reject]() {
520
+ try {
521
+ #ifdef OP_SQLITE_USE_LIBSQL
522
+ auto batchResult =
523
+ opsqlite_libsql_execute_batch(db, &commands);
524
+ #else
525
+ auto batchResult = opsqlite_execute_batch(db, &commands);
526
+ #endif
527
+
528
+ if (invalidated) {
529
+ return;
530
+ }
531
+
532
+ invoker->invokeAsync([&rt,
533
+ batchResult = std::move(batchResult),
534
+ resolve] {
535
+ auto res = jsi::Object(rt);
536
+ res.setProperty(rt, "rowsAffected",
537
+ jsi::Value(batchResult.affectedRows));
538
+ resolve->asObject(rt).asFunction(rt).call(
539
+ rt, std::move(res));
540
+ });
541
+ } catch (std::runtime_error &e) {
542
+ auto what = e.what();
543
+ invoker->invokeAsync([&rt, what, reject] {
544
+ auto errorCtr =
545
+ rt.global().getPropertyAsFunction(rt, "Error");
546
+ auto error = errorCtr.callAsConstructor(
547
+ rt, jsi::String::createFromAscii(rt, what));
548
+ reject->asObject(rt).asFunction(rt).call(rt, error);
549
+ });
550
+ } catch (std::exception &exc) {
551
+ auto what = exc.what();
552
+ invoker->invokeAsync([&rt, what, reject] {
553
+ auto errorCtr =
554
+ rt.global().getPropertyAsFunction(rt, "Error");
555
+ auto error = errorCtr.callAsConstructor(
556
+ rt, jsi::String::createFromAscii(rt, what));
557
+ reject->asObject(rt).asFunction(rt).call(rt, error);
558
+ });
559
+ }
560
+ };
561
+ _thread_pool->queueWork(task);
562
+
563
+ return {};
564
+ }));
565
+
566
+ return promise;
567
+ });
568
+
569
+ #ifdef OP_SQLITE_USE_LIBSQL
570
+ function_map["sync"] = HOSTFN("sync") {
571
+ opsqlite_libsql_sync(db);
572
+ return {};
573
+ });
574
+ #else
575
+ function_map["loadFile"] = HOSTFN("loadFile") {
576
+ if (count < 1) {
577
+ throw std::runtime_error(
578
+ "[op-sqlite][loadFile] Incorrect parameter count");
579
+ return {};
580
+ }
581
+
582
+ const std::string sqlFileName = args[0].asString(rt).utf8(rt);
583
+
584
+ auto promiseCtr = rt.global().getPropertyAsFunction(rt, "Promise");
585
+ auto promise = promiseCtr.callAsConstructor(rt, HOSTFN("executor") {
586
+ auto resolve = std::make_shared<jsi::Value>(rt, args[0]);
587
+ auto reject = std::make_shared<jsi::Value>(rt, args[1]);
588
+
589
+ auto task = [&rt, this, sqlFileName, resolve, reject]() {
590
+ try {
591
+ const auto result = import_sql_file(db, sqlFileName);
592
+
593
+ invoker->invokeAsync([&rt, result, resolve] {
594
+ auto res = jsi::Object(rt);
595
+ res.setProperty(rt, "rowsAffected",
596
+ jsi::Value(result.affectedRows));
597
+ res.setProperty(rt, "commands",
598
+ jsi::Value(result.commands));
599
+ resolve->asObject(rt).asFunction(rt).call(
600
+ rt, std::move(res));
601
+ });
602
+ } catch (std::runtime_error &e) {
603
+ auto what = e.what();
604
+ invoker->invokeAsync(
605
+ [&rt, what = std::string(what), reject] {
606
+ auto errorCtr =
607
+ rt.global().getPropertyAsFunction(rt, "Error");
608
+ auto error = errorCtr.callAsConstructor(
609
+ rt, jsi::String::createFromAscii(rt, what));
610
+ reject->asObject(rt).asFunction(rt).call(rt, error);
611
+ });
612
+ } catch (std::exception &exc) {
613
+ auto what = exc.what();
614
+ invoker->invokeAsync(
615
+ [&rt, what = std::string(what), reject] {
616
+ auto errorCtr =
617
+ rt.global().getPropertyAsFunction(rt, "Error");
618
+ auto error = errorCtr.callAsConstructor(
619
+ rt, jsi::String::createFromAscii(rt, what));
620
+ reject->asObject(rt).asFunction(rt).call(rt, error);
621
+ });
622
+ }
623
+ };
624
+ _thread_pool->queueWork(task);
625
+ return {};
626
+ }));
627
+
628
+ return promise;
629
+ });
630
+
631
+ function_map["updateHook"] = HOSTFN("updateHook") {
632
+ auto callback = std::make_shared<jsi::Value>(rt, args[0]);
633
+
634
+ if (callback->isUndefined() || callback->isNull()) {
635
+ update_hook_callback = nullptr;
636
+ } else {
637
+ update_hook_callback = callback;
638
+ }
639
+
640
+ auto_register_update_hook();
641
+ return {};
642
+ });
643
+
644
+ function_map["commitHook"] = HOSTFN("commitHook") {
645
+ if (count < 1) {
646
+ throw std::runtime_error("[op-sqlite][commitHook] callback needed");
647
+ }
648
+
649
+ auto callback = std::make_shared<jsi::Value>(rt, args[0]);
650
+ if (callback->isUndefined() || callback->isNull()) {
651
+ opsqlite_deregister_commit_hook(db);
652
+ return {};
653
+ }
654
+ commit_hook_callback = callback;
655
+ opsqlite_register_commit_hook(db, this);
656
+
657
+ return {};
658
+ });
659
+
660
+ function_map["rollbackHook"] = HOSTFN("rollbackHook") {
661
+ if (count < 1) {
662
+ throw std::runtime_error(
663
+ "[op-sqlite][rollbackHook] callback needed");
664
+ }
665
+
666
+ auto callback = std::make_shared<jsi::Value>(rt, args[0]);
667
+
668
+ if (callback->isUndefined() || callback->isNull()) {
669
+ opsqlite_deregister_rollback_hook(db);
670
+ return {};
671
+ }
672
+ rollback_hook_callback = callback;
673
+
674
+ opsqlite_register_rollback_hook(db, this);
675
+ return {};
676
+ });
677
+
678
+ function_map["loadExtension"] = HOSTFN("loadExtension") {
679
+ auto path = args[0].asString(rt).utf8(rt);
680
+ std::string entry_point;
681
+ if (count > 1 && args[1].isString()) {
682
+ entry_point = args[1].asString(rt).utf8(rt);
683
+ }
684
+
685
+ opsqlite_load_extension(db, path, entry_point);
686
+ return {};
687
+ });
688
+
689
+ function_map["reactiveExecute"] = HOSTFN("reactiveExecute") {
690
+ auto query = args[0].asObject(rt);
691
+
692
+ const std::string query_str =
693
+ query.getProperty(rt, "query").asString(rt).utf8(rt);
694
+ auto js_args = query.getProperty(rt, "arguments");
695
+ auto js_discriminators =
696
+ query.getProperty(rt, "fireOn").asObject(rt).asArray(rt);
697
+ auto variant_args = to_variant_vec(rt, js_args);
698
+
699
+ sqlite3_stmt *stmt = opsqlite_prepare_statement(db, query_str);
700
+ opsqlite_bind_statement(stmt, &variant_args);
701
+
702
+ auto callback =
703
+ std::make_shared<jsi::Value>(query.getProperty(rt, "callback"));
704
+
705
+ std::vector<TableRowDiscriminator> discriminators;
706
+
707
+ for (size_t i = 0; i < js_discriminators.length(rt); i++) {
708
+ auto js_discriminator =
709
+ js_discriminators.getValueAtIndex(rt, i).asObject(rt);
710
+ std::string table =
711
+ js_discriminator.getProperty(rt, "table").asString(rt).utf8(rt);
712
+ std::vector<int> ids;
713
+ if (js_discriminator.hasProperty(rt, "ids")) {
714
+ auto js_ids = js_discriminator.getProperty(rt, "ids")
715
+ .asObject(rt)
716
+ .asArray(rt);
717
+ for (size_t j = 0; j < js_ids.length(rt); j++) {
718
+ ids.push_back(static_cast<int>(
719
+ js_ids.getValueAtIndex(rt, j).asNumber()));
720
+ }
721
+ }
722
+ discriminators.push_back({table, ids});
723
+ }
724
+
725
+ std::shared_ptr<ReactiveQuery> reactiveQuery =
726
+ std::make_shared<ReactiveQuery>(
727
+ ReactiveQuery{stmt, discriminators, callback});
728
+
729
+ reactive_queries.push_back(reactiveQuery);
730
+
731
+ auto_register_update_hook();
732
+
733
+ auto unsubscribe = HOSTFN("unsubscribe") {
734
+ auto it = std::find(reactive_queries.begin(),
735
+ reactive_queries.end(), reactiveQuery);
736
+ if (it != reactive_queries.end()) {
737
+ reactive_queries.erase(it);
738
+ }
739
+ auto_register_update_hook();
740
+ return {};
741
+ });
742
+
743
+ return unsubscribe;
744
+ });
745
+ #endif
746
+
747
+ function_map["prepareStatement"] = HOSTFN("prepareStatement") {
748
+ auto query = args[0].asString(rt).utf8(rt);
749
+ #ifdef OP_SQLITE_USE_LIBSQL
750
+ libsql_stmt_t statement = opsqlite_libsql_prepare_statement(db, query);
751
+ #else
752
+ sqlite3_stmt *statement = opsqlite_prepare_statement(db, query);
753
+ #endif
754
+ auto preparedStatementHostObject =
755
+ std::make_shared<PreparedStatementHostObject>(
756
+ db, db_name, statement, invoker, _thread_pool);
757
+
758
+ return jsi::Object::createFromHostObject(rt,
759
+ preparedStatementHostObject);
760
+ });
761
+
762
+ function_map["getDbPath"] = HOSTFN("getDbPath") {
763
+ std::string path = std::string(base_path);
764
+
765
+ if (count == 1) {
766
+ if (!args[0].isString()) {
767
+ throw std::runtime_error(
768
+ "[op-sqlite][open] database location must be a string");
769
+ }
770
+
771
+ std::string last_path = args[0].asString(rt).utf8(rt);
772
+
773
+ if (last_path == ":memory:") {
774
+ path = ":memory:";
775
+ } else if (last_path.rfind('/', 0) == 0) {
776
+ path = last_path;
777
+ } else {
778
+ path = path + "/" + last_path;
779
+ }
780
+ }
781
+
782
+ auto result = opsqlite_get_db_path(db_name, path);
783
+ return jsi::String::createFromUtf8(rt, result);
784
+ });
785
+
786
+ function_map["flushPendingReactiveQueries"] =
787
+ HOSTFN("flushPendingReactiveQueries") {
788
+ auto promiseCtr = rt.global().getPropertyAsFunction(rt, "Promise");
789
+ auto promise = promiseCtr.callAsConstructor(rt, HOSTFN("executor") {
790
+ auto resolve = std::make_shared<jsi::Value>(rt, args[0]);
791
+
792
+ auto task = [&rt, this, resolve]() {
793
+ flush_pending_reactive_queries(resolve);
794
+ };
795
+
796
+ _thread_pool->queueWork(task);
797
+
798
+ return {};
799
+ }));
800
+
801
+ return promise;
802
+ });
803
+ }
804
+
805
+ std::vector<jsi::PropNameID> DBHostObject::getPropertyNames(jsi::Runtime &_rt) {
806
+ std::vector<jsi::PropNameID> keys;
807
+ keys.reserve(function_map.size());
808
+ for (const auto &pair : function_map) {
809
+ keys.emplace_back(jsi::PropNameID::forUtf8(_rt, pair.first));
810
+ }
811
+ return keys;
812
+ }
813
+
814
+ jsi::Value DBHostObject::get(jsi::Runtime &_rt,
815
+ const jsi::PropNameID &propNameID) {
816
+ auto name = propNameID.utf8(rt);
817
+ if (function_map.count(name) != 1) {
818
+ return HOST_STATIC_FN(name.c_str()) {
819
+ throw std::runtime_error(
820
+ "[op-sqlite] Function " + name +
821
+ " not implemented for current backend (libsql or sqlcipher)");
822
+ });
823
+ }
824
+
825
+ return {rt, function_map[name]};
826
+ }
827
+
828
+ void DBHostObject::set(jsi::Runtime &_rt, const jsi::PropNameID &name,
829
+ const jsi::Value &value) {
830
+ throw std::runtime_error("You cannot write to this object!");
831
+ }
832
+
833
+ void DBHostObject::invalidate() {
834
+ if (invalidated) {
835
+ return;
836
+ }
837
+
838
+ invalidated = true;
839
+ _thread_pool->restartPool();
840
+ #ifdef OP_SQLITE_USE_LIBSQL
841
+ opsqlite_libsql_close(db);
842
+ #else
843
+ if (db != nullptr) {
844
+ opsqlite_close(db);
845
+ db = nullptr;
846
+ }
847
+ #endif
848
+ }
849
+
850
+ DBHostObject::~DBHostObject() { invalidate(); }
851
+
852
+ } // namespace opsqlite