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

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.
package/src/index.ts CHANGED
@@ -34,7 +34,7 @@ if (global.__OPSQLiteProxy == null) {
34
34
  }
35
35
 
36
36
  const proxy = global.__OPSQLiteProxy;
37
- export const OPSQLite = proxy as ISQLite;
37
+ export const OPSQLite = proxy as OPSQLiteProxy;
38
38
 
39
39
  export const {
40
40
  IOS_DOCUMENT_PATH,
@@ -145,14 +145,9 @@ export type PreparedStatementObj = {
145
145
  execute: () => QueryResult;
146
146
  };
147
147
 
148
- interface ISQLite {
149
- open: (options: {
150
- name: string;
151
- location?: string;
152
- encryptionKey?: string;
153
- }) => void;
154
- close: (dbName: string) => void;
155
- delete: (dbName: string, location?: string) => void;
148
+ export type DB = {
149
+ close: () => void;
150
+ delete: (location?: string) => void;
156
151
  attach: (
157
152
  mainDbName: string,
158
153
  dbNameToAttach: string,
@@ -160,24 +155,13 @@ interface ISQLite {
160
155
  location?: string
161
156
  ) => void;
162
157
  detach: (mainDbName: string, alias: string) => void;
163
- transaction: (
164
- dbName: string,
165
- fn: (tx: Transaction) => Promise<void>
166
- ) => Promise<void>;
167
- execute: (dbName: string, query: string, params?: any[]) => QueryResult;
168
- executeAsync: (
169
- dbName: string,
170
- query: string,
171
- params?: any[]
172
- ) => Promise<QueryResult>;
173
- executeBatch: (dbName: string, commands: SQLBatchTuple[]) => BatchQueryResult;
174
- executeBatchAsync: (
175
- dbName: string,
176
- commands: SQLBatchTuple[]
177
- ) => Promise<BatchQueryResult>;
178
- loadFile: (dbName: string, location: string) => Promise<FileLoadResult>;
158
+ transaction: (fn: (tx: Transaction) => Promise<void>) => Promise<void>;
159
+ execute: (query: string, params?: any[]) => QueryResult;
160
+ executeAsync: (query: string, params?: any[]) => Promise<QueryResult>;
161
+ executeBatch: (commands: SQLBatchTuple[]) => BatchQueryResult;
162
+ executeBatchAsync: (commands: SQLBatchTuple[]) => Promise<BatchQueryResult>;
163
+ loadFile: (location: string) => Promise<FileLoadResult>;
179
164
  updateHook: (
180
- dbName: string,
181
165
  callback?:
182
166
  | ((params: {
183
167
  table: string;
@@ -187,18 +171,29 @@ interface ISQLite {
187
171
  }) => void)
188
172
  | null
189
173
  ) => void;
190
- commitHook: (dbName: string, callback?: (() => void) | null) => void;
191
- rollbackHook: (dbName: string, callback?: (() => void) | null) => void;
192
- prepareStatement: (dbName: string, query: string) => PreparedStatementObj;
193
- loadExtension: (dbName: string, path: string, entryPoint?: string) => void;
194
- executeRawAsync: (
195
- dbName: string,
196
- query: string,
197
- params?: any[]
198
- ) => Promise<any[]>;
199
- getDbPath: (dbName: string, location?: string) => string;
174
+ commitHook: (callback?: (() => void) | null) => void;
175
+ rollbackHook: (callback?: (() => void) | null) => void;
176
+ prepareStatement: (query: string) => PreparedStatementObj;
177
+ loadExtension: (path: string, entryPoint?: string) => void;
178
+ executeRawAsync: (query: string, params?: any[]) => Promise<any[]>;
179
+ getDbPath: (location?: string) => string;
180
+ reactiveExecute: (params: {
181
+ query: string;
182
+ arguments: any[];
183
+ tables: string[];
184
+ rowIds?: number[];
185
+ callback: (response: any) => void;
186
+ }) => () => void;
187
+ };
188
+
189
+ type OPSQLiteProxy = {
190
+ open: (options: {
191
+ name: string;
192
+ location?: string;
193
+ encryptionKey?: string;
194
+ }) => DB;
200
195
  isSQLCipher: () => boolean;
201
- }
196
+ };
202
197
 
203
198
  const locks: Record<
204
199
  string,
@@ -221,71 +216,76 @@ function enhanceQueryResult(result: QueryResult): void {
221
216
  }
222
217
  }
223
218
 
224
- const _open = OPSQLite.open;
225
- OPSQLite.open = (options: {
219
+ export const open = (options: {
226
220
  name: string;
227
221
  location?: string;
228
222
  encryptionKey?: string;
229
- }) => {
230
- _open(options);
223
+ }): DB => {
224
+ const db = OPSQLite.open(options);
231
225
 
232
- locks[options.name] = {
233
- queue: [],
226
+ const lock = {
227
+ queue: [] as PendingTransaction[],
234
228
  inProgress: false,
235
229
  };
236
- };
237
-
238
- const _close = OPSQLite.close;
239
- OPSQLite.close = (dbName: string) => {
240
- _close(dbName);
241
- delete locks[dbName];
242
- };
243
230
 
244
- const _execute = OPSQLite.execute;
245
- OPSQLite.execute = (
246
- dbName: string,
247
- query: string,
248
- params?: any[] | undefined
249
- ): QueryResult => {
250
- const sanitizedParams = params?.map((p) => {
251
- if (ArrayBuffer.isView(p)) {
252
- return p.buffer;
231
+ const startNextTransaction = () => {
232
+ if (lock.inProgress) {
233
+ // Transaction is already in process bail out
234
+ return;
253
235
  }
254
236
 
255
- return p;
256
- });
237
+ if (lock.queue.length) {
238
+ lock.inProgress = true;
239
+ const tx = lock.queue.shift();
257
240
 
258
- const result = _execute(dbName, query, sanitizedParams);
259
- enhanceQueryResult(result);
260
- return result;
261
- };
241
+ if (!tx) {
242
+ throw new Error('Could not get a operation on database');
243
+ }
262
244
 
263
- const _executeAsync = OPSQLite.executeAsync;
264
- OPSQLite.executeAsync = async (
265
- dbName: string,
266
- query: string,
267
- params?: any[] | undefined
268
- ): Promise<QueryResult> => {
269
- const sanitizedParams = params?.map((p) => {
270
- if (ArrayBuffer.isView(p)) {
271
- return p.buffer;
245
+ setImmediate(() => {
246
+ tx.start();
247
+ });
272
248
  }
249
+ };
273
250
 
274
- return p;
275
- });
276
-
277
- const res = await _executeAsync(dbName, query, sanitizedParams);
278
- enhanceQueryResult(res);
279
- return res;
280
- };
251
+ // spreading the object is not working, so we need to do it manually
252
+ let enhancedDb = {
253
+ delete: db.delete,
254
+ attach: db.attach,
255
+ detach: db.detach,
256
+ executeBatch: db.executeBatch,
257
+ executeBatchAsync: db.executeBatchAsync,
258
+
259
+ loadFile: db.loadFile,
260
+ updateHook: db.updateHook,
261
+ commitHook: db.commitHook,
262
+ rollbackHook: db.rollbackHook,
263
+ loadExtension: db.loadExtension,
264
+ executeRawAsync: db.executeRawAsync,
265
+ getDbPath: db.getDbPath,
266
+ reactiveExecute: db.reactiveExecute,
267
+ close: () => {
268
+ db.close();
269
+ delete locks[options.name];
270
+ },
271
+ execute: (query: string, params?: any[] | undefined): QueryResult => {
272
+ const sanitizedParams = params?.map((p) => {
273
+ if (ArrayBuffer.isView(p)) {
274
+ return p.buffer;
275
+ }
281
276
 
282
- const _prepareStatement = OPSQLite.prepareStatement;
283
- OPSQLite.prepareStatement = (dbName: string, query: string) => {
284
- const stmt = _prepareStatement(dbName, query);
277
+ return p;
278
+ });
285
279
 
286
- return {
287
- bind: (params: any[]) => {
288
- const sanitizedParams = params.map((p) => {
280
+ const result = db.execute(query, sanitizedParams);
281
+ enhanceQueryResult(result);
282
+ return result;
283
+ },
284
+ executeAsync: async (
285
+ query: string,
286
+ params?: any[] | undefined
287
+ ): Promise<QueryResult> => {
288
+ const sanitizedParams = params?.map((p) => {
289
289
  if (ArrayBuffer.isView(p)) {
290
290
  return p.buffer;
291
291
  }
@@ -293,207 +293,131 @@ OPSQLite.prepareStatement = (dbName: string, query: string) => {
293
293
  return p;
294
294
  });
295
295
 
296
- stmt.bind(sanitizedParams);
296
+ const result = await db.executeAsync(query, sanitizedParams);
297
+ enhanceQueryResult(result);
298
+ return result;
297
299
  },
298
- execute: () => {
299
- const res = stmt.execute();
300
- enhanceQueryResult(res);
301
- return res;
300
+ prepareStatement: (query: string) => {
301
+ const stmt = db.prepareStatement(query);
302
+
303
+ return {
304
+ bind: (params: any[]) => {
305
+ const sanitizedParams = params.map((p) => {
306
+ if (ArrayBuffer.isView(p)) {
307
+ return p.buffer;
308
+ }
309
+
310
+ return p;
311
+ });
312
+
313
+ stmt.bind(sanitizedParams);
314
+ },
315
+ execute: () => {
316
+ const res = stmt.execute();
317
+ enhanceQueryResult(res);
318
+ return res;
319
+ },
320
+ };
302
321
  },
303
- };
304
- };
305
-
306
- OPSQLite.transaction = async (
307
- dbName: string,
308
- fn: (tx: Transaction) => Promise<void>
309
- ): Promise<void> => {
310
- if (!locks[dbName]) {
311
- throw Error(`SQLite Error: No lock found on db: ${dbName}`);
312
- }
313
-
314
- let isFinalized = false;
315
-
316
- // Local transaction context object implementation
317
- const execute = (query: string, params?: any[]): QueryResult => {
318
- if (isFinalized) {
319
- throw Error(
320
- `SQLite Error: Cannot execute query on finalized transaction: ${dbName}`
321
- );
322
- }
323
- return OPSQLite.execute(dbName, query, params);
324
- };
325
-
326
- const executeAsync = (query: string, params?: any[] | undefined) => {
327
- if (isFinalized) {
328
- throw Error(
329
- `SQLite Error: Cannot execute query on finalized transaction: ${dbName}`
330
- );
331
- }
332
- return OPSQLite.executeAsync(dbName, query, params);
333
- };
334
-
335
- const commit = () => {
336
- if (isFinalized) {
337
- throw Error(
338
- `SQLite Error: Cannot execute commit on finalized transaction: ${dbName}`
339
- );
340
- }
341
- const result = OPSQLite.execute(dbName, 'COMMIT');
342
- isFinalized = true;
343
- return result;
344
- };
345
-
346
- const rollback = () => {
347
- if (isFinalized) {
348
- throw Error(
349
- `SQLite Error: Cannot execute rollback on finalized transaction: ${dbName}`
350
- );
351
- }
352
- const result = OPSQLite.execute(dbName, 'ROLLBACK');
353
- isFinalized = true;
354
- return result;
355
- };
356
-
357
- async function run() {
358
- try {
359
- await OPSQLite.executeAsync(dbName, 'BEGIN TRANSACTION');
360
-
361
- await fn({
362
- commit,
363
- execute,
364
- executeAsync,
365
- rollback,
366
- });
322
+ transaction: async (
323
+ fn: (tx: Transaction) => Promise<void>
324
+ ): Promise<void> => {
325
+ let isFinalized = false;
326
+
327
+ // Local transaction context object implementation
328
+ const execute = (query: string, params?: any[]): QueryResult => {
329
+ if (isFinalized) {
330
+ throw Error(
331
+ `OP-Sqlite Error: Database: ${options.name}. Cannot execute query on finalized transaction`
332
+ );
333
+ }
334
+ return enhancedDb.execute(query, params);
335
+ };
336
+
337
+ const executeAsync = (query: string, params?: any[] | undefined) => {
338
+ if (isFinalized) {
339
+ throw Error(
340
+ `OP-Sqlite Error: Database: ${options.name}. Cannot execute query on finalized transaction`
341
+ );
342
+ }
343
+ return enhancedDb.executeAsync(query, params);
344
+ };
345
+
346
+ const commit = () => {
347
+ if (isFinalized) {
348
+ throw Error(
349
+ `OP-Sqlite Error: Database: ${options.name}. Cannot execute query on finalized transaction`
350
+ );
351
+ }
352
+ const result = enhancedDb.execute('COMMIT;');
353
+ isFinalized = true;
354
+ return result;
355
+ };
356
+
357
+ const rollback = () => {
358
+ if (isFinalized) {
359
+ throw Error(
360
+ `OP-Sqlite Error: Database: ${options.name}. Cannot execute query on finalized transaction`
361
+ );
362
+ }
363
+ const result = enhancedDb.execute('ROLLBACK;');
364
+ isFinalized = true;
365
+ return result;
366
+ };
367
367
 
368
- if (!isFinalized) {
369
- commit();
370
- }
371
- } catch (executionError) {
372
- if (!isFinalized) {
368
+ async function run() {
373
369
  try {
374
- rollback();
375
- } catch (rollbackError) {
376
- throw rollbackError;
370
+ await enhancedDb.executeAsync('BEGIN TRANSACTION;');
371
+
372
+ await fn({
373
+ commit,
374
+ execute,
375
+ executeAsync,
376
+ rollback,
377
+ });
378
+ console.warn('finished executing user function for transaction');
379
+ if (!isFinalized) {
380
+ commit();
381
+ }
382
+ } catch (executionError) {
383
+ console.warn('transaction error', executionError);
384
+ if (!isFinalized) {
385
+ try {
386
+ rollback();
387
+ } catch (rollbackError) {
388
+ throw rollbackError;
389
+ }
390
+ }
391
+
392
+ throw executionError;
393
+ } finally {
394
+ lock.inProgress = false;
395
+ isFinalized = false;
396
+ startNextTransaction();
377
397
  }
378
398
  }
379
399
 
380
- throw executionError;
381
- } finally {
382
- locks[dbName]!.inProgress = false;
383
- isFinalized = false;
384
- startNextTransaction(dbName);
385
- }
386
- }
387
-
388
- return await new Promise((resolve, reject) => {
389
- const tx: PendingTransaction = {
390
- start: () => {
391
- run().then(resolve).catch(reject);
392
- },
393
- };
394
-
395
- locks[dbName]!.queue.push(tx);
396
- startNextTransaction(dbName);
397
- });
398
- };
399
-
400
- const startNextTransaction = (dbName: string) => {
401
- if (!locks[dbName]) {
402
- throw Error(`Lock not found for db: ${dbName}`);
403
- }
404
-
405
- if (locks[dbName]!.inProgress) {
406
- // Transaction is already in process bail out
407
- return;
408
- }
409
-
410
- if (locks[dbName]!.queue.length) {
411
- locks[dbName]!.inProgress = true;
412
- const tx = locks[dbName]!.queue.shift();
413
-
414
- if (!tx) {
415
- throw new Error('Could not get a operation on datebase');
416
- }
417
-
418
- setImmediate(() => {
419
- tx.start();
420
- });
421
- }
422
- };
423
-
424
- export type OPSQLiteConnection = {
425
- close: () => void;
426
- delete: () => void;
427
- attach: (dbNameToAttach: string, alias: string, location?: string) => void;
428
- detach: (alias: string) => void;
429
- transaction: (fn: (tx: Transaction) => Promise<void>) => Promise<void>;
430
- execute: (query: string, params?: any[]) => QueryResult;
431
- executeAsync: (query: string, params?: any[]) => Promise<QueryResult>;
432
- executeBatch: (commands: SQLBatchTuple[]) => BatchQueryResult;
433
- executeBatchAsync: (commands: SQLBatchTuple[]) => Promise<BatchQueryResult>;
434
- loadFile: (location: string) => Promise<FileLoadResult>;
435
- updateHook: (
436
- callback:
437
- | ((params: {
438
- table: string;
439
- operation: UpdateHookOperation;
440
- row?: any;
441
- rowId: number;
442
- }) => void)
443
- | null
444
- ) => void;
445
- commitHook: (callback: (() => void) | null) => void;
446
- rollbackHook: (callback: (() => void) | null) => void;
447
- prepareStatement: (query: string) => PreparedStatementObj;
448
- loadExtension: (path: string, entryPoint?: string) => void;
449
- executeRawAsync: (query: string, params?: any[]) => Promise<any[]>;
450
- getDbPath: () => string;
451
- };
400
+ return await new Promise((resolve, reject) => {
401
+ const tx: PendingTransaction = {
402
+ start: () => {
403
+ run().then(resolve).catch(reject);
404
+ },
405
+ };
452
406
 
453
- export const open = (options: {
454
- name: string;
455
- location?: string;
456
- encryptionKey?: string;
457
- }): OPSQLiteConnection => {
458
- OPSQLite.open(options);
459
-
460
- return {
461
- close: () => OPSQLite.close(options.name),
462
- delete: () => OPSQLite.delete(options.name, options.location),
463
- attach: (dbNameToAttach: string, alias: string, location?: string) =>
464
- OPSQLite.attach(options.name, dbNameToAttach, alias, location),
465
- detach: (alias: string) => OPSQLite.detach(options.name, alias),
466
- transaction: (fn: (tx: Transaction) => Promise<void>) =>
467
- OPSQLite.transaction(options.name, fn),
468
- execute: (query: string, params?: any[] | undefined): QueryResult =>
469
- OPSQLite.execute(options.name, query, params),
470
- executeAsync: (
471
- query: string,
472
- params?: any[] | undefined
473
- ): Promise<QueryResult> =>
474
- OPSQLite.executeAsync(options.name, query, params),
475
- executeBatch: (commands: SQLBatchTuple[]) =>
476
- OPSQLite.executeBatch(options.name, commands),
477
- executeBatchAsync: (commands: SQLBatchTuple[]) =>
478
- OPSQLite.executeBatchAsync(options.name, commands),
479
- loadFile: (location: string) => OPSQLite.loadFile(options.name, location),
480
- updateHook: (callback) => OPSQLite.updateHook(options.name, callback),
481
- commitHook: (callback) => OPSQLite.commitHook(options.name, callback),
482
- rollbackHook: (callback) => OPSQLite.rollbackHook(options.name, callback),
483
- prepareStatement: (query) => OPSQLite.prepareStatement(options.name, query),
484
- loadExtension: (path, entryPoint) =>
485
- OPSQLite.loadExtension(options.name, path, entryPoint),
486
- executeRawAsync: (query, params) =>
487
- OPSQLite.executeRawAsync(options.name, query, params),
488
- getDbPath: () => OPSQLite.getDbPath(options.name, options.location),
407
+ lock.queue.push(tx);
408
+ startNextTransaction();
409
+ });
410
+ },
489
411
  };
412
+
413
+ return enhancedDb;
490
414
  };
491
415
 
492
- export const moveAssetsDatabase = (args: {
416
+ export const moveAssetsDatabase = async (args: {
493
417
  filename: string;
494
418
  path?: string;
495
419
  overwrite?: boolean;
496
- }): boolean => {
420
+ }): Promise<boolean> => {
497
421
  return NativeModules.OPSQLite.moveAssetsDatabase(args);
498
422
  };
499
423