@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
package/src/index.ts ADDED
@@ -0,0 +1,722 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+ export { Storage } from './Storage';
3
+
4
+ export type Scalar =
5
+ | string
6
+ | number
7
+ | boolean
8
+ | null
9
+ | ArrayBuffer
10
+ | ArrayBufferView;
11
+
12
+ /**
13
+ * Object returned by SQL Query executions {
14
+ * insertId: Represent the auto-generated row id if applicable
15
+ * rowsAffected: Number of affected rows if result of a update query
16
+ * message: if status === 1, here you will find error description
17
+ * rows: if status is undefined or 0 this object will contain the query results
18
+ * }
19
+ *
20
+ * @interface QueryResult
21
+ */
22
+ export type QueryResult = {
23
+ insertId?: number;
24
+ rowsAffected: number;
25
+ res?: any[];
26
+ rows: Array<Record<string, Scalar>>;
27
+ // An array of intermediate results, just values without column names
28
+ rawRows?: Scalar[][];
29
+ columnNames?: string[];
30
+ /**
31
+ * Query metadata, available only for select query results
32
+ */
33
+ metadata?: ColumnMetadata[];
34
+ };
35
+
36
+ /**
37
+ * Column metadata
38
+ * Describes some information about columns fetched by the query
39
+ */
40
+ export type ColumnMetadata = {
41
+ /** The name used for this column for this result set */
42
+ name: string;
43
+ /** The declared column type for this column, when fetched directly from a table or a View resulting from a table column. "UNKNOWN" for dynamic values, like function returned ones. */
44
+ type: string;
45
+ /**
46
+ * The index for this column for this result set*/
47
+ index: number;
48
+ };
49
+
50
+ /**
51
+ * Allows the execution of bulk of sql commands
52
+ * inside a transaction
53
+ * If a single query must be executed many times with different arguments, its preferred
54
+ * to declare it a single time, and use an array of array parameters.
55
+ */
56
+ export type SQLBatchTuple =
57
+ | [string]
58
+ | [string, Array<Scalar> | Array<Array<Scalar>>];
59
+
60
+ export type UpdateHookOperation = 'INSERT' | 'DELETE' | 'UPDATE';
61
+
62
+ /**
63
+ * status: 0 or undefined for correct execution, 1 for error
64
+ * message: if status === 1, here you will find error description
65
+ * rowsAffected: Number of affected rows if status == 0
66
+ */
67
+ export type BatchQueryResult = {
68
+ rowsAffected?: number;
69
+ };
70
+
71
+ /**
72
+ * Result of loading a file and executing every line as a SQL command
73
+ * Similar to BatchQueryResult
74
+ */
75
+ export type FileLoadResult = BatchQueryResult & {
76
+ commands?: number;
77
+ };
78
+
79
+ export type Transaction = {
80
+ commit: () => Promise<QueryResult>;
81
+ execute: (query: string, params?: Scalar[]) => Promise<QueryResult>;
82
+ rollback: () => Promise<QueryResult>;
83
+ };
84
+
85
+ type PendingTransaction = {
86
+ /*
87
+ * The start function should not throw or return a promise because the
88
+ * queue just calls it and does not monitor for failures or completions.
89
+ *
90
+ * It should catch any errors and call the resolve or reject of the wrapping
91
+ * promise when complete.
92
+ *
93
+ * It should also automatically commit or rollback the transaction if needed
94
+ */
95
+ start: () => void;
96
+ };
97
+
98
+ export type PreparedStatement = {
99
+ bind: (params: any[]) => Promise<void>;
100
+ execute: () => Promise<QueryResult>;
101
+ };
102
+
103
+ type InternalDB = {
104
+ close: () => void;
105
+ delete: (location?: string) => void;
106
+ attach: (params: {
107
+ secondaryDbFileName: string;
108
+ alias: string;
109
+ location?: string;
110
+ }) => void;
111
+ detach: (alias: string) => void;
112
+ transaction: (fn: (tx: Transaction) => Promise<void>) => Promise<void>;
113
+ executeSync: (query: string, params?: Scalar[]) => QueryResult;
114
+ execute: (query: string, params?: Scalar[]) => Promise<QueryResult>;
115
+ executeWithHostObjects: (
116
+ query: string,
117
+ params?: Scalar[]
118
+ ) => Promise<QueryResult>;
119
+ executeBatch: (commands: SQLBatchTuple[]) => Promise<BatchQueryResult>;
120
+ loadFile: (location: string) => Promise<FileLoadResult>;
121
+ updateHook: (
122
+ callback?:
123
+ | ((params: {
124
+ table: string;
125
+ operation: UpdateHookOperation;
126
+ row?: any;
127
+ rowId: number;
128
+ }) => void)
129
+ | null
130
+ ) => void;
131
+ commitHook: (callback?: (() => void) | null) => void;
132
+ rollbackHook: (callback?: (() => void) | null) => void;
133
+ prepareStatement: (query: string) => PreparedStatement;
134
+ loadExtension: (path: string, entryPoint?: string) => void;
135
+ executeRaw: (query: string, params?: Scalar[]) => Promise<any[]>;
136
+ getDbPath: (location?: string) => string;
137
+ reactiveExecute: (params: {
138
+ query: string;
139
+ arguments: any[];
140
+ fireOn: {
141
+ table: string;
142
+ ids?: number[];
143
+ }[];
144
+ callback: (response: any) => void;
145
+ }) => () => void;
146
+ sync: () => void;
147
+ flushPendingReactiveQueries: () => Promise<void>;
148
+ };
149
+
150
+ export type DB = {
151
+ close: () => void;
152
+ delete: (location?: string) => void;
153
+ attach: (params: {
154
+ secondaryDbFileName: string;
155
+ alias: string;
156
+ location?: string;
157
+ }) => void;
158
+ detach: (alias: string) => void;
159
+ /**
160
+ * Wraps all the executions into a transaction. If an error is thrown it will rollback all of the changes
161
+ *
162
+ * You need to use this if you are using reactive queries for the queries to fire after the transaction is done
163
+ */
164
+ transaction: (fn: (tx: Transaction) => Promise<void>) => Promise<void>;
165
+ /**
166
+ * Sync version of the execute function
167
+ * It will block the JS thread and therefore your UI and should be used with caution
168
+ *
169
+ * When writing your queries, you can use the ? character as a placeholder for parameters
170
+ * The parameters will be automatically escaped and sanitized
171
+ *
172
+ * Example:
173
+ * db.executeSync('SELECT * FROM table WHERE id = ?', [1]);
174
+ *
175
+ * If you are writing a query that doesn't require parameters, you can omit the second argument
176
+ *
177
+ * If you are writing to the database YOU SHOULD BE USING TRANSACTIONS!
178
+ * Transactions protect you from partial writes and ensure that your data is always in a consistent state
179
+ *
180
+ * @param query
181
+ * @param params
182
+ * @returns QueryResult
183
+ */
184
+ executeSync: (query: string, params?: Scalar[]) => QueryResult;
185
+ /**
186
+ * Basic query execution function, it is async don't forget to await it
187
+ *
188
+ * When writing your queries, you can use the ? character as a placeholder for parameters
189
+ * The parameters will be automatically escaped and sanitized
190
+ *
191
+ * Example:
192
+ * await db.execute('SELECT * FROM table WHERE id = ?', [1]);
193
+ *
194
+ * If you are writing a query that doesn't require parameters, you can omit the second argument
195
+ *
196
+ * If you are writing to the database YOU SHOULD BE USING TRANSACTIONS!
197
+ * Transactions protect you from partial writes and ensure that your data is always in a consistent state
198
+ *
199
+ * If you need a large amount of queries ran as fast as possible you should be using `executeBatch`, `executeRaw`, `loadFile` or `executeWithHostObjects`
200
+ *
201
+ * @param query string of your SQL query
202
+ * @param params a list of parameters to bind to the query, if any
203
+ * @returns Promise<QueryResult> with the result of the query
204
+ */
205
+ execute: (query: string, params?: Scalar[]) => Promise<QueryResult>;
206
+ /**
207
+ * Similar to the execute function but returns the response in HostObjects
208
+ * Read more about HostObjects in the documentation and their pitfalls
209
+ *
210
+ * Will be a lot faster than the normal execute functions when returning data but you will pay when accessing the fields
211
+ * as the conversion is done the moment you access any field
212
+ * @param query
213
+ * @param params
214
+ * @returns
215
+ */
216
+ executeWithHostObjects: (
217
+ query: string,
218
+ params?: Scalar[]
219
+ ) => Promise<QueryResult>;
220
+ /**
221
+ * Executes all the queries in the params inside a single transaction
222
+ *
223
+ * It's faster than executing single queries as data is sent to the native side only once
224
+ * @param commands
225
+ * @returns Promise<BatchQueryResult>
226
+ */
227
+ executeBatch: (commands: SQLBatchTuple[]) => Promise<BatchQueryResult>;
228
+ /**
229
+ * Loads a SQLite Dump from disk. It will be the fastest way to execute a large set of queries as no JS is involved
230
+ */
231
+ loadFile: (location: string) => Promise<FileLoadResult>;
232
+ updateHook: (
233
+ callback?:
234
+ | ((params: {
235
+ table: string;
236
+ operation: UpdateHookOperation;
237
+ row?: any;
238
+ rowId: number;
239
+ }) => void)
240
+ | null
241
+ ) => void;
242
+ commitHook: (callback?: (() => void) | null) => void;
243
+ rollbackHook: (callback?: (() => void) | null) => void;
244
+ /**
245
+ * Constructs a prepared statement from the query string
246
+ * The statement can be re-bound with parameters and executed
247
+ * The performance gain is significant when the same query is executed multiple times, NOT when the query is executed (once)
248
+ * The cost lies in the preparation of the statement as it is compiled and optimized by the sqlite engine, the params can then rebound
249
+ * but the query itself is already optimized
250
+ *
251
+ * @param query string of your SQL query
252
+ * @returns Prepared statement object
253
+ */
254
+ prepareStatement: (query: string) => PreparedStatement;
255
+ /**
256
+ * Loads a runtime loadable sqlite extension. Libsql and iOS embedded version do not support loading extensions
257
+ */
258
+ loadExtension: (path: string, entryPoint?: string) => void;
259
+ /**
260
+ * Same as `execute` except the results are not returned in objects but rather in arrays with just the values and not the keys
261
+ * It will be faster since a lot of repeated work is skipped and only the values you care about are returned
262
+ */
263
+ executeRaw: (query: string, params?: Scalar[]) => Promise<any[]>;
264
+ /**
265
+ * Get's the absolute path to the db file. Useful for debugging on local builds and for attaching the DB from users devices
266
+ */
267
+ getDbPath: (location?: string) => string;
268
+ /**
269
+ * Reactive execution of queries when data is written to the database. Check the docs for how to use them.
270
+ */
271
+ reactiveExecute: (params: {
272
+ query: string;
273
+ arguments: any[];
274
+ fireOn: {
275
+ table: string;
276
+ ids?: number[];
277
+ }[];
278
+ callback: (response: any) => void;
279
+ }) => () => void;
280
+ /** This function is only available for libsql.
281
+ * Allows to trigger a sync the database with it's remote replica
282
+ * In order for this function to work you need to use openSync or openRemote functions
283
+ * with libsql: true in the package.json
284
+ *
285
+ * The database is hosted in turso
286
+ **/
287
+ sync: () => void;
288
+ };
289
+
290
+ export type DBParams = {
291
+ url?: string;
292
+ authToken?: string;
293
+ name?: string;
294
+ location?: string;
295
+ syncInterval?: number;
296
+ };
297
+
298
+ export type OPSQLiteProxy = {
299
+ open: (options: {
300
+ name: string;
301
+ location?: string;
302
+ encryptionKey?: string;
303
+ }) => InternalDB;
304
+ openRemote: (options: { url: string; authToken: string }) => InternalDB;
305
+ openSync: (options: DBParams) => InternalDB;
306
+ isSQLCipher: () => boolean;
307
+ isLibsql: () => boolean;
308
+ isIOSEmbedded: () => boolean;
309
+ };
310
+
311
+ declare global {
312
+ var __OPSQLiteProxy: object | undefined;
313
+ }
314
+
315
+ if (global.__OPSQLiteProxy == null) {
316
+ if (NativeModules.OPSQLite == null) {
317
+ throw new Error(
318
+ 'Base module not found. Did you do a pod install/clear the gradle cache?'
319
+ );
320
+ }
321
+
322
+ // Call the synchronous blocking install() function
323
+ const installed = NativeModules.OPSQLite.install();
324
+ if (!installed) {
325
+ throw new Error(
326
+ `Failed to install op-sqlite: The native OPSQLite Module could not be installed! Looks like something went wrong when installing JSI bindings, check the native logs for more info`
327
+ );
328
+ }
329
+
330
+ // Check again if the constructor now exists. If not, throw an error.
331
+ if (global.__OPSQLiteProxy == null) {
332
+ throw new Error(
333
+ 'OPSqlite native object is not available. Something is wrong. Check the native logs for more information.'
334
+ );
335
+ }
336
+ }
337
+
338
+ const proxy = global.__OPSQLiteProxy;
339
+ const OPSQLite = proxy as OPSQLiteProxy;
340
+
341
+ export const {
342
+ IOS_DOCUMENT_PATH,
343
+ IOS_LIBRARY_PATH,
344
+ ANDROID_DATABASE_PATH,
345
+ ANDROID_FILES_PATH,
346
+ ANDROID_EXTERNAL_FILES_PATH,
347
+ } = !!NativeModules.OPSQLite.getConstants
348
+ ? NativeModules.OPSQLite.getConstants()
349
+ : NativeModules.OPSQLite;
350
+
351
+ function enhanceDB(db: InternalDB, options: DBParams): DB {
352
+ const lock = {
353
+ queue: [] as PendingTransaction[],
354
+ inProgress: false,
355
+ };
356
+
357
+ const startNextTransaction = () => {
358
+ if (lock.inProgress) {
359
+ // Transaction is already in process bail out
360
+ return;
361
+ }
362
+
363
+ if (lock.queue.length) {
364
+ lock.inProgress = true;
365
+ const tx = lock.queue.shift();
366
+
367
+ if (!tx) {
368
+ throw new Error('Could not get a operation on database');
369
+ }
370
+
371
+ setImmediate(() => {
372
+ tx.start();
373
+ });
374
+ }
375
+ };
376
+
377
+ // spreading the object does not work with HostObjects (db)
378
+ // We need to manually assign the fields
379
+ let enhancedDb = {
380
+ delete: db.delete,
381
+ attach: db.attach,
382
+ detach: db.detach,
383
+ executeBatch: db.executeBatch,
384
+ loadFile: db.loadFile,
385
+ updateHook: db.updateHook,
386
+ commitHook: db.commitHook,
387
+ rollbackHook: db.rollbackHook,
388
+ loadExtension: db.loadExtension,
389
+ getDbPath: db.getDbPath,
390
+ reactiveExecute: db.reactiveExecute,
391
+ sync: db.sync,
392
+ close: db.close,
393
+ executeWithHostObjects: async (
394
+ query: string,
395
+ params?: Scalar[]
396
+ ): Promise<QueryResult> => {
397
+ const sanitizedParams = params?.map((p) => {
398
+ if (ArrayBuffer.isView(p)) {
399
+ return p.buffer;
400
+ }
401
+
402
+ return p;
403
+ });
404
+
405
+ return sanitizedParams
406
+ ? await db.executeWithHostObjects(query, sanitizedParams as Scalar[])
407
+ : await db.executeWithHostObjects(query);
408
+ },
409
+ executeRaw: async (query: string, params?: Scalar[]) => {
410
+ const sanitizedParams = params?.map((p) => {
411
+ if (ArrayBuffer.isView(p)) {
412
+ return p.buffer;
413
+ }
414
+
415
+ return p;
416
+ });
417
+
418
+ return db.executeRaw(query, sanitizedParams as Scalar[]);
419
+ },
420
+ // Wrapper for executeRaw, drizzleORM uses this function
421
+ // at some point I changed the API but they did not pin their dependency to a specific version
422
+ // so re-inserting this so it starts working again
423
+ executeRawAsync: async (query: string, params?: Scalar[]) => {
424
+ const sanitizedParams = params?.map((p) => {
425
+ if (ArrayBuffer.isView(p)) {
426
+ return p.buffer;
427
+ }
428
+
429
+ return p;
430
+ });
431
+
432
+ return db.executeRaw(query, sanitizedParams as Scalar[]);
433
+ },
434
+ executeSync: (query: string, params?: Scalar[]): QueryResult => {
435
+ const sanitizedParams = params?.map((p) => {
436
+ if (ArrayBuffer.isView(p)) {
437
+ return p.buffer;
438
+ }
439
+
440
+ return p;
441
+ });
442
+
443
+ let intermediateResult = sanitizedParams
444
+ ? db.executeSync(query, sanitizedParams as Scalar[])
445
+ : db.executeSync(query);
446
+
447
+ let rows: Record<string, Scalar>[] = [];
448
+ for (let i = 0; i < (intermediateResult.rawRows?.length ?? 0); i++) {
449
+ let row: Record<string, Scalar> = {};
450
+ let rawRow = intermediateResult.rawRows![i]!;
451
+ for (let j = 0; j < intermediateResult.columnNames!.length; j++) {
452
+ let columnName = intermediateResult.columnNames![j]!;
453
+ let value = rawRow[j]!;
454
+
455
+ row[columnName] = value;
456
+ }
457
+ rows.push(row);
458
+ }
459
+
460
+ let res = {
461
+ ...intermediateResult,
462
+ rows,
463
+ };
464
+
465
+ delete res.rawRows;
466
+
467
+ return res;
468
+ },
469
+ executeAsync: async (
470
+ query: string,
471
+ params?: Scalar[] | undefined
472
+ ): Promise<QueryResult> => {
473
+ return db.execute(query, params);
474
+ },
475
+ execute: async (
476
+ query: string,
477
+ params?: Scalar[] | undefined
478
+ ): Promise<QueryResult> => {
479
+ const sanitizedParams = params?.map((p) => {
480
+ if (ArrayBuffer.isView(p)) {
481
+ return p.buffer;
482
+ }
483
+
484
+ return p;
485
+ });
486
+
487
+ let intermediateResult = await db.execute(
488
+ query,
489
+ sanitizedParams as Scalar[]
490
+ );
491
+
492
+ let rows: Record<string, Scalar>[] = [];
493
+ for (let i = 0; i < (intermediateResult.rawRows?.length ?? 0); i++) {
494
+ let row: Record<string, Scalar> = {};
495
+ let rawRow = intermediateResult.rawRows![i]!;
496
+ for (let j = 0; j < intermediateResult.columnNames!.length; j++) {
497
+ let columnName = intermediateResult.columnNames![j]!;
498
+ let value = rawRow[j]!;
499
+
500
+ row[columnName] = value;
501
+ }
502
+ rows.push(row);
503
+ }
504
+
505
+ let res = {
506
+ ...intermediateResult,
507
+ rows,
508
+ };
509
+
510
+ delete res.rawRows;
511
+
512
+ return res;
513
+ },
514
+ prepareStatement: (query: string) => {
515
+ const stmt = db.prepareStatement(query);
516
+
517
+ return {
518
+ bind: async (params: Scalar[]) => {
519
+ const sanitizedParams = params.map((p) => {
520
+ if (ArrayBuffer.isView(p)) {
521
+ return p.buffer;
522
+ }
523
+
524
+ return p;
525
+ });
526
+
527
+ await stmt.bind(sanitizedParams);
528
+ },
529
+ execute: stmt.execute,
530
+ };
531
+ },
532
+ transaction: async (
533
+ fn: (tx: Transaction) => Promise<void>
534
+ ): Promise<void> => {
535
+ let isFinalized = false;
536
+
537
+ const execute = async (query: string, params?: Scalar[]) => {
538
+ if (isFinalized) {
539
+ throw Error(
540
+ `OP-Sqlite Error: Database: ${
541
+ options.name || options.url
542
+ }. Cannot execute query on finalized transaction`
543
+ );
544
+ }
545
+ return await enhancedDb.execute(query, params);
546
+ };
547
+
548
+ const commit = async (): Promise<QueryResult> => {
549
+ if (isFinalized) {
550
+ throw Error(
551
+ `OP-Sqlite Error: Database: ${
552
+ options.name || options.url
553
+ }. Cannot execute query on finalized transaction`
554
+ );
555
+ }
556
+ const result = await enhancedDb.execute('COMMIT;');
557
+
558
+ await db.flushPendingReactiveQueries();
559
+
560
+ isFinalized = true;
561
+ return result;
562
+ };
563
+
564
+ const rollback = async (): Promise<QueryResult> => {
565
+ if (isFinalized) {
566
+ throw Error(
567
+ `OP-Sqlite Error: Database: ${
568
+ options.name || options.url
569
+ }. Cannot execute query on finalized transaction`
570
+ );
571
+ }
572
+ const result = await enhancedDb.execute('ROLLBACK;');
573
+ isFinalized = true;
574
+ return result;
575
+ };
576
+
577
+ async function run() {
578
+ try {
579
+ await enhancedDb.execute('BEGIN TRANSACTION;');
580
+
581
+ await fn({
582
+ commit,
583
+ execute,
584
+ rollback,
585
+ });
586
+
587
+ if (!isFinalized) {
588
+ await commit();
589
+ }
590
+ } catch (executionError) {
591
+ if (!isFinalized) {
592
+ try {
593
+ await rollback();
594
+ } catch (rollbackError) {
595
+ throw rollbackError;
596
+ }
597
+ }
598
+
599
+ throw executionError;
600
+ } finally {
601
+ lock.inProgress = false;
602
+ isFinalized = false;
603
+ startNextTransaction();
604
+ }
605
+ }
606
+
607
+ return await new Promise((resolve, reject) => {
608
+ const tx: PendingTransaction = {
609
+ start: () => {
610
+ run().then(resolve).catch(reject);
611
+ },
612
+ };
613
+
614
+ lock.queue.push(tx);
615
+ startNextTransaction();
616
+ });
617
+ },
618
+ };
619
+
620
+ return enhancedDb;
621
+ }
622
+
623
+ /**
624
+ * Open a replicating connection via libsql to a turso db
625
+ * libsql needs to be enabled on your package.json
626
+ */
627
+ export const openSync = (params: {
628
+ url: string;
629
+ authToken: string;
630
+ name: string;
631
+ location?: string;
632
+ syncInterval?: number;
633
+ }): DB => {
634
+ if (!isLibsql()) {
635
+ throw new Error('This function is only available for libsql');
636
+ }
637
+
638
+ const db = OPSQLite.openSync(params);
639
+ const enhancedDb = enhanceDB(db, params);
640
+
641
+ return enhancedDb;
642
+ };
643
+
644
+ /**
645
+ * Open a remote connection via libsql to a turso db
646
+ * libsql needs to be enabled on your package.json
647
+ */
648
+ export const openRemote = (params: { url: string; authToken: string }): DB => {
649
+ if (!isLibsql()) {
650
+ throw new Error('This function is only available for libsql');
651
+ }
652
+
653
+ const db = OPSQLite.openRemote(params);
654
+ const enhancedDb = enhanceDB(db, params);
655
+
656
+ return enhancedDb;
657
+ };
658
+
659
+ /**
660
+ * Open a connection to a local sqlite or sqlcipher database
661
+ * If you want libsql remote or sync connections, use openSync or openRemote
662
+ */
663
+ export const open = (params: {
664
+ name: string;
665
+ location?: string;
666
+ encryptionKey?: string;
667
+ }): DB => {
668
+ if (params.location?.startsWith('file://')) {
669
+ console.warn(
670
+ "[op-sqlite] You are passing a path with 'file://' prefix, it's automatically removed"
671
+ );
672
+ params.location = params.location.substring(7);
673
+ }
674
+
675
+ const db = OPSQLite.open(params);
676
+ const enhancedDb = enhanceDB(db, params);
677
+
678
+ return enhancedDb;
679
+ };
680
+
681
+ /**
682
+ * Moves the database from the assets folder to the default path (check the docs) or to a custom path
683
+ * It DOES NOT OVERWRITE the database if it already exists in the destination path
684
+ * if you want to overwrite the database, you need to pass the overwrite flag as true
685
+ * @param args object with the parameters for the operaiton
686
+ * @returns promise, rejects if failed to move the database, resolves if the operation was successful
687
+ */
688
+ export const moveAssetsDatabase = async (args: {
689
+ filename: string;
690
+ path?: string;
691
+ overwrite?: boolean;
692
+ }): Promise<boolean> => {
693
+ return NativeModules.OPSQLite.moveAssetsDatabase(args);
694
+ };
695
+
696
+ /**
697
+ * Used to load a dylib file that contains a sqlite 3 extension/plugin
698
+ * It returns the raw path to the actual file which then needs to be passed to the loadExtension function
699
+ * Check the docs for more information
700
+ * @param bundle the iOS bundle identifier of the .framework
701
+ * @param name the file name of the dylib file
702
+ * @returns
703
+ */
704
+ export const getDylibPath = (bundle: string, name: string): string => {
705
+ return NativeModules.OPSQLite.getDylibPath(bundle, name);
706
+ };
707
+
708
+ export const isSQLCipher = (): boolean => {
709
+ return OPSQLite.isSQLCipher();
710
+ };
711
+
712
+ export const isLibsql = (): boolean => {
713
+ return OPSQLite.isLibsql();
714
+ };
715
+
716
+ export const isIOSEmbeeded = (): boolean => {
717
+ if (Platform.OS !== 'ios') {
718
+ return false;
719
+ }
720
+
721
+ return OPSQLite.isIOSEmbedded();
722
+ };