@op-engineering/op-sqlite 6.0.2-beta1 → 6.0.2-beta4

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 (38) hide show
  1. package/android/CMakeLists.txt +26 -15
  2. package/android/build.gradle +10 -1
  3. package/android/cpp-adapter.cpp +4 -0
  4. package/android/jniLibs/arm64-v8a/libsql_experimental.a +0 -0
  5. package/android/jniLibs/armeabi-v7a/libsql_experimental.a +0 -0
  6. package/android/jniLibs/x86/libsql_experimental.a +0 -0
  7. package/android/jniLibs/x86_64/libsql_experimental.a +0 -0
  8. package/cpp/DBHostObject.cpp +234 -87
  9. package/cpp/DBHostObject.h +19 -10
  10. package/cpp/PreparedStatementHostObject.cpp +28 -14
  11. package/cpp/PreparedStatementHostObject.h +18 -14
  12. package/cpp/bindings.cpp +49 -32
  13. package/cpp/bindings.h +4 -3
  14. package/cpp/bridge.cpp +45 -0
  15. package/cpp/bridge.h +3 -0
  16. package/cpp/libsql/bridge.cpp +660 -0
  17. package/cpp/libsql/bridge.h +76 -0
  18. package/cpp/libsql/libsql.h +133 -0
  19. package/cpp/sqlite3.h +0 -1
  20. package/cpp/types.h +5 -0
  21. package/cpp/utils.cpp +45 -3
  22. package/cpp/utils.h +2 -3
  23. package/ios/libsql.xcframework/Info.plist +48 -0
  24. package/ios/libsql.xcframework/ios-arm64/Headers/libsql.h +133 -0
  25. package/ios/libsql.xcframework/ios-arm64/libsql_experimental.a +0 -0
  26. package/ios/libsql.xcframework/ios-arm64_x86_64-simulator/Headers/libsql.h +133 -0
  27. package/ios/libsql.xcframework/ios-arm64_x86_64-simulator/libsql_experimental.a +0 -0
  28. package/lib/commonjs/index.js +167 -2
  29. package/lib/commonjs/index.js.map +1 -1
  30. package/lib/module/index.js +164 -1
  31. package/lib/module/index.js.map +1 -1
  32. package/lib/typescript/src/index.d.ts +14 -2
  33. package/lib/typescript/src/index.d.ts.map +1 -1
  34. package/op-sqlite.podspec +20 -3
  35. package/package.json +1 -1
  36. package/src/index.ts +209 -3
  37. package/cpp/sqlbatchexecutor.cpp +0 -93
  38. package/cpp/sqlbatchexecutor.h +0 -30
package/src/index.ts CHANGED
@@ -180,8 +180,10 @@ export type DB = {
180
180
  reactiveExecute: (params: {
181
181
  query: string;
182
182
  arguments: any[];
183
- tables: string[];
184
- rowIds?: number[];
183
+ fireOn: {
184
+ table: string;
185
+ ids?: number[];
186
+ }[];
185
187
  callback: (response: any) => void;
186
188
  }) => () => void;
187
189
  };
@@ -192,7 +194,9 @@ type OPSQLiteProxy = {
192
194
  location?: string;
193
195
  encryptionKey?: string;
194
196
  }) => DB;
197
+ openRemote: (options: { url: string; authToken: string }) => DB;
195
198
  isSQLCipher: () => boolean;
199
+ isLibsql: () => boolean;
196
200
  };
197
201
 
198
202
  const locks: Record<
@@ -216,6 +220,204 @@ function enhanceQueryResult(result: QueryResult): void {
216
220
  }
217
221
  }
218
222
 
223
+ // TODO de-dupe this function with open
224
+ export const openRemote = (options: { url: string; authToken: string }): DB => {
225
+ if (!isLibsql()) {
226
+ throw new Error('This function is only available for libsql');
227
+ }
228
+
229
+ const db = OPSQLite.openRemote(options);
230
+
231
+ const lock = {
232
+ queue: [] as PendingTransaction[],
233
+ inProgress: false,
234
+ };
235
+
236
+ const startNextTransaction = () => {
237
+ if (lock.inProgress) {
238
+ // Transaction is already in process bail out
239
+ return;
240
+ }
241
+
242
+ if (lock.queue.length) {
243
+ lock.inProgress = true;
244
+ const tx = lock.queue.shift();
245
+
246
+ if (!tx) {
247
+ throw new Error('Could not get a operation on database');
248
+ }
249
+
250
+ setImmediate(() => {
251
+ tx.start();
252
+ });
253
+ }
254
+ };
255
+
256
+ // spreading the object is not working, so we need to do it manually
257
+ let enhancedDb = {
258
+ delete: db.delete,
259
+ attach: db.attach,
260
+ detach: db.detach,
261
+ executeBatch: db.executeBatch,
262
+ executeBatchAsync: db.executeBatchAsync,
263
+
264
+ loadFile: db.loadFile,
265
+ updateHook: db.updateHook,
266
+ commitHook: db.commitHook,
267
+ rollbackHook: db.rollbackHook,
268
+ loadExtension: db.loadExtension,
269
+ executeRawAsync: db.executeRawAsync,
270
+ getDbPath: db.getDbPath,
271
+ reactiveExecute: db.reactiveExecute,
272
+ close: () => {
273
+ db.close();
274
+ delete locks[options.url];
275
+ },
276
+ execute: (query: string, params?: any[] | undefined): QueryResult => {
277
+ const sanitizedParams = params?.map((p) => {
278
+ if (ArrayBuffer.isView(p)) {
279
+ return p.buffer;
280
+ }
281
+
282
+ return p;
283
+ });
284
+
285
+ const result = db.execute(query, sanitizedParams);
286
+ enhanceQueryResult(result);
287
+ return result;
288
+ },
289
+ executeAsync: async (
290
+ query: string,
291
+ params?: any[] | undefined
292
+ ): Promise<QueryResult> => {
293
+ const sanitizedParams = params?.map((p) => {
294
+ if (ArrayBuffer.isView(p)) {
295
+ return p.buffer;
296
+ }
297
+
298
+ return p;
299
+ });
300
+
301
+ const result = await db.executeAsync(query, sanitizedParams);
302
+ enhanceQueryResult(result);
303
+ return result;
304
+ },
305
+ prepareStatement: (query: string) => {
306
+ const stmt = db.prepareStatement(query);
307
+
308
+ return {
309
+ bind: (params: any[]) => {
310
+ const sanitizedParams = params.map((p) => {
311
+ if (ArrayBuffer.isView(p)) {
312
+ return p.buffer;
313
+ }
314
+
315
+ return p;
316
+ });
317
+
318
+ stmt.bind(sanitizedParams);
319
+ },
320
+ execute: () => {
321
+ const res = stmt.execute();
322
+ enhanceQueryResult(res);
323
+ return res;
324
+ },
325
+ };
326
+ },
327
+ transaction: async (
328
+ fn: (tx: Transaction) => Promise<void>
329
+ ): Promise<void> => {
330
+ let isFinalized = false;
331
+
332
+ // Local transaction context object implementation
333
+ const execute = (query: string, params?: any[]): QueryResult => {
334
+ if (isFinalized) {
335
+ throw Error(
336
+ `OP-Sqlite Error: Database: ${options.url}. Cannot execute query on finalized transaction`
337
+ );
338
+ }
339
+ return enhancedDb.execute(query, params);
340
+ };
341
+
342
+ const executeAsync = (query: string, params?: any[] | undefined) => {
343
+ if (isFinalized) {
344
+ throw Error(
345
+ `OP-Sqlite Error: Database: ${options.url}. Cannot execute query on finalized transaction`
346
+ );
347
+ }
348
+ return enhancedDb.executeAsync(query, params);
349
+ };
350
+
351
+ const commit = () => {
352
+ if (isFinalized) {
353
+ throw Error(
354
+ `OP-Sqlite Error: Database: ${options.url}. Cannot execute query on finalized transaction`
355
+ );
356
+ }
357
+ const result = enhancedDb.execute('COMMIT;');
358
+ isFinalized = true;
359
+ return result;
360
+ };
361
+
362
+ const rollback = () => {
363
+ if (isFinalized) {
364
+ throw Error(
365
+ `OP-Sqlite Error: Database: ${options.url}. Cannot execute query on finalized transaction`
366
+ );
367
+ }
368
+ const result = enhancedDb.execute('ROLLBACK;');
369
+ isFinalized = true;
370
+ return result;
371
+ };
372
+
373
+ async function run() {
374
+ try {
375
+ await enhancedDb.executeAsync('BEGIN TRANSACTION;');
376
+
377
+ await fn({
378
+ commit,
379
+ execute,
380
+ executeAsync,
381
+ rollback,
382
+ });
383
+
384
+ if (!isFinalized) {
385
+ commit();
386
+ }
387
+ } catch (executionError) {
388
+ console.warn('transaction error', executionError);
389
+ if (!isFinalized) {
390
+ try {
391
+ rollback();
392
+ } catch (rollbackError) {
393
+ throw rollbackError;
394
+ }
395
+ }
396
+
397
+ throw executionError;
398
+ } finally {
399
+ lock.inProgress = false;
400
+ isFinalized = false;
401
+ startNextTransaction();
402
+ }
403
+ }
404
+
405
+ return await new Promise((resolve, reject) => {
406
+ const tx: PendingTransaction = {
407
+ start: () => {
408
+ run().then(resolve).catch(reject);
409
+ },
410
+ };
411
+
412
+ lock.queue.push(tx);
413
+ startNextTransaction();
414
+ });
415
+ },
416
+ };
417
+
418
+ return enhancedDb;
419
+ };
420
+
219
421
  export const open = (options: {
220
422
  name: string;
221
423
  location?: string;
@@ -375,7 +577,7 @@ export const open = (options: {
375
577
  executeAsync,
376
578
  rollback,
377
579
  });
378
- console.warn('finished executing user function for transaction');
580
+
379
581
  if (!isFinalized) {
380
582
  commit();
381
583
  }
@@ -424,3 +626,7 @@ export const moveAssetsDatabase = async (args: {
424
626
  export const isSQLCipher = (): boolean => {
425
627
  return OPSQLite.isSQLCipher();
426
628
  };
629
+
630
+ export const isLibsql = (): boolean => {
631
+ return OPSQLite.isLibsql();
632
+ };
@@ -1,93 +0,0 @@
1
- #include "sqlbatchexecutor.h"
2
-
3
- namespace opsqlite {
4
-
5
- /**
6
- * Batch execution implementation
7
- */
8
-
9
- void toBatchArguments(jsi::Runtime &rt, jsi::Array const &batchParams,
10
- std::vector<BatchArguments> *commands) {
11
- for (int i = 0; i < batchParams.length(rt); i++) {
12
- const jsi::Array &command =
13
- batchParams.getValueAtIndex(rt, i).asObject(rt).asArray(rt);
14
- if (command.length(rt) == 0) {
15
- continue;
16
- }
17
-
18
- const std::string query =
19
- command.getValueAtIndex(rt, 0).asString(rt).utf8(rt);
20
- const jsi::Value &commandParams = command.length(rt) > 1
21
- ? command.getValueAtIndex(rt, 1)
22
- : jsi::Value::undefined();
23
- if (!commandParams.isUndefined() &&
24
- commandParams.asObject(rt).isArray(rt) &&
25
- commandParams.asObject(rt).asArray(rt).length(rt) > 0 &&
26
- commandParams.asObject(rt)
27
- .asArray(rt)
28
- .getValueAtIndex(rt, 0)
29
- .isObject()) {
30
- // This arguments is an array of arrays, like a batch update of a single
31
- // sql command.
32
- const jsi::Array &batchUpdateParams =
33
- commandParams.asObject(rt).asArray(rt);
34
- for (int x = 0; x < batchUpdateParams.length(rt); x++) {
35
- const jsi::Value &p = batchUpdateParams.getValueAtIndex(rt, x);
36
- auto params =
37
- std::make_shared<std::vector<JSVariant>>(to_variant_vec(rt, p));
38
- commands->push_back({query, params});
39
- }
40
- } else {
41
- auto params = std::make_shared<std::vector<JSVariant>>(
42
- to_variant_vec(rt, commandParams));
43
- commands->push_back({query, params});
44
- }
45
- }
46
- }
47
-
48
- BatchResult sqliteExecuteBatch(std::string dbName,
49
- std::vector<BatchArguments> *commands) {
50
- size_t commandCount = commands->size();
51
- if (commandCount <= 0) {
52
- return BatchResult{
53
- .type = SQLiteError,
54
- .message = "No SQL commands provided",
55
- };
56
- }
57
-
58
- try {
59
- int affectedRows = 0;
60
- opsqlite_execute(dbName, "BEGIN EXCLUSIVE TRANSACTION", nullptr, nullptr,
61
- nullptr);
62
- for (int i = 0; i < commandCount; i++) {
63
- auto command = commands->at(i);
64
- // We do not provide a datastructure to receive query data because we
65
- // don't need/want to handle this results in a batch execution
66
- auto result = opsqlite_execute(dbName, command.sql, command.params.get(),
67
- nullptr, nullptr);
68
- if (result.type == SQLiteError) {
69
- opsqlite_execute(dbName, "ROLLBACK", nullptr, nullptr, nullptr);
70
- return BatchResult{
71
- .type = SQLiteError,
72
- .message = result.message,
73
- };
74
- } else {
75
- affectedRows += result.affectedRows;
76
- }
77
- }
78
- opsqlite_execute(dbName, "COMMIT", nullptr, nullptr, nullptr);
79
- return BatchResult{
80
- .type = SQLiteOk,
81
- .affectedRows = affectedRows,
82
- .commands = static_cast<int>(commandCount),
83
- };
84
- } catch (std::exception &exc) {
85
- opsqlite_execute(dbName, "ROLLBACK", nullptr, nullptr, nullptr);
86
- return BatchResult{
87
- .type = SQLiteError,
88
- .message = exc.what(),
89
- };
90
- }
91
- }
92
-
93
- } // namespace opsqlite
@@ -1,30 +0,0 @@
1
- /**
2
- * SQL Batch execution implementation using default sqliteBridge implementation
3
- */
4
- #include "bridge.h"
5
- #include "types.h"
6
- #include "utils.h"
7
-
8
- namespace opsqlite {
9
-
10
- namespace jsi = facebook::jsi;
11
-
12
- struct BatchArguments {
13
- std::string sql;
14
- std::shared_ptr<std::vector<JSVariant>> params;
15
- };
16
-
17
- /**
18
- * Local Helper method to translate JSI objects BatchArguments data structure
19
- * MUST be called in the JavaScript Thread
20
- */
21
- void toBatchArguments(jsi::Runtime &rt, jsi::Array const &batchParams,
22
- std::vector<BatchArguments> *commands);
23
-
24
- /**
25
- * Execute a batch of commands in a exclusive transaction
26
- */
27
- BatchResult sqliteExecuteBatch(std::string dbName,
28
- std::vector<BatchArguments> *commands);
29
-
30
- } // namespace opsqlite