@symbiote-native/sqlite 0.1.0

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 (128) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/build/angular/index.d.ts +2 -0
  4. package/build/angular/index.js +2 -0
  5. package/build/angular/sqlite.service.d.ts +41 -0
  6. package/build/angular/sqlite.service.js +127 -0
  7. package/build/core/index.d.ts +10 -0
  8. package/build/core/index.js +6 -0
  9. package/build/core/native-database.d.ts +65 -0
  10. package/build/core/native-database.js +13 -0
  11. package/build/core/native-module.d.ts +25 -0
  12. package/build/core/native-module.js +17 -0
  13. package/build/core/native-session.d.ts +20 -0
  14. package/build/core/native-session.js +1 -0
  15. package/build/core/native-statement.d.ts +45 -0
  16. package/build/core/native-statement.js +6 -0
  17. package/build/core/param-utils.d.ts +28 -0
  18. package/build/core/param-utils.js +126 -0
  19. package/build/core/path-utils.d.ts +6 -0
  20. package/build/core/path-utils.js +29 -0
  21. package/build/core/query-utils.d.ts +17 -0
  22. package/build/core/query-utils.js +37 -0
  23. package/build/core/sqlite-database.d.ts +246 -0
  24. package/build/core/sqlite-database.js +427 -0
  25. package/build/core/sqlite-session.d.ts +84 -0
  26. package/build/core/sqlite-session.js +121 -0
  27. package/build/core/sqlite-statement.d.ts +96 -0
  28. package/build/core/sqlite-statement.js +321 -0
  29. package/build/core/sqlite-tagged-query.d.ts +73 -0
  30. package/build/core/sqlite-tagged-query.js +119 -0
  31. package/build/core/storage.d.ts +107 -0
  32. package/build/core/storage.js +382 -0
  33. package/build/core/types.d.ts +30 -0
  34. package/build/core/types.js +1 -0
  35. package/build/react/index.d.ts +2 -0
  36. package/build/react/index.js +2 -0
  37. package/build/react/sqlite-context.d.ts +25 -0
  38. package/build/react/sqlite-context.js +129 -0
  39. package/build/solid/index.d.ts +2 -0
  40. package/build/solid/index.js +2 -0
  41. package/build/solid/sqlite-context.d.ts +23 -0
  42. package/build/solid/sqlite-context.js +106 -0
  43. package/build/svelte/SQLiteProvider.svelte +88 -0
  44. package/build/svelte/SQLiteProvider.svelte.d.ts +13 -0
  45. package/build/svelte/index.d.ts +3 -0
  46. package/build/svelte/index.js +5 -0
  47. package/build/svelte/sqlite-context.d.ts +11 -0
  48. package/build/svelte/sqlite-context.js +23 -0
  49. package/build/vue/index.d.ts +2 -0
  50. package/build/vue/index.js +2 -0
  51. package/build/vue/sqlite-context.d.ts +21 -0
  52. package/build/vue/sqlite-context.js +69 -0
  53. package/build-ngc/angular/index.d.ts +2 -0
  54. package/build-ngc/angular/index.js +3 -0
  55. package/build-ngc/angular/index.js.map +1 -0
  56. package/build-ngc/angular/sqlite.service.d.ts +44 -0
  57. package/build-ngc/angular/sqlite.service.js +85 -0
  58. package/build-ngc/angular/sqlite.service.js.map +1 -0
  59. package/build-ngc/core/index.d.ts +10 -0
  60. package/build-ngc/core/index.js +7 -0
  61. package/build-ngc/core/index.js.map +1 -0
  62. package/build-ngc/core/native-database.d.ts +65 -0
  63. package/build-ngc/core/native-database.js +14 -0
  64. package/build-ngc/core/native-database.js.map +1 -0
  65. package/build-ngc/core/native-module.d.ts +25 -0
  66. package/build-ngc/core/native-module.js +18 -0
  67. package/build-ngc/core/native-module.js.map +1 -0
  68. package/build-ngc/core/native-session.d.ts +20 -0
  69. package/build-ngc/core/native-session.js +2 -0
  70. package/build-ngc/core/native-session.js.map +1 -0
  71. package/build-ngc/core/native-statement.d.ts +45 -0
  72. package/build-ngc/core/native-statement.js +7 -0
  73. package/build-ngc/core/native-statement.js.map +1 -0
  74. package/build-ngc/core/param-utils.d.ts +28 -0
  75. package/build-ngc/core/param-utils.js +127 -0
  76. package/build-ngc/core/param-utils.js.map +1 -0
  77. package/build-ngc/core/path-utils.d.ts +6 -0
  78. package/build-ngc/core/path-utils.js +30 -0
  79. package/build-ngc/core/path-utils.js.map +1 -0
  80. package/build-ngc/core/query-utils.d.ts +17 -0
  81. package/build-ngc/core/query-utils.js +38 -0
  82. package/build-ngc/core/query-utils.js.map +1 -0
  83. package/build-ngc/core/sqlite-database.d.ts +246 -0
  84. package/build-ngc/core/sqlite-database.js +428 -0
  85. package/build-ngc/core/sqlite-database.js.map +1 -0
  86. package/build-ngc/core/sqlite-session.d.ts +84 -0
  87. package/build-ngc/core/sqlite-session.js +122 -0
  88. package/build-ngc/core/sqlite-session.js.map +1 -0
  89. package/build-ngc/core/sqlite-statement.d.ts +96 -0
  90. package/build-ngc/core/sqlite-statement.js +322 -0
  91. package/build-ngc/core/sqlite-statement.js.map +1 -0
  92. package/build-ngc/core/sqlite-tagged-query.d.ts +73 -0
  93. package/build-ngc/core/sqlite-tagged-query.js +120 -0
  94. package/build-ngc/core/sqlite-tagged-query.js.map +1 -0
  95. package/build-ngc/core/storage.d.ts +107 -0
  96. package/build-ngc/core/storage.js +383 -0
  97. package/build-ngc/core/storage.js.map +1 -0
  98. package/build-ngc/core/types.d.ts +30 -0
  99. package/build-ngc/core/types.js +2 -0
  100. package/build-ngc/core/types.js.map +1 -0
  101. package/native-link.json +12 -0
  102. package/package.json +141 -0
  103. package/src/angular/index.ts +2 -0
  104. package/src/angular/sqlite.service.ts +114 -0
  105. package/src/core/index.ts +40 -0
  106. package/src/core/native-database.ts +118 -0
  107. package/src/core/native-module.ts +57 -0
  108. package/src/core/native-session.ts +64 -0
  109. package/src/core/native-statement.ts +85 -0
  110. package/src/core/param-utils.ts +163 -0
  111. package/src/core/path-utils.ts +38 -0
  112. package/src/core/query-utils.ts +45 -0
  113. package/src/core/sqlite-database.ts +676 -0
  114. package/src/core/sqlite-session.ts +165 -0
  115. package/src/core/sqlite-statement.ts +578 -0
  116. package/src/core/sqlite-tagged-query.ts +160 -0
  117. package/src/core/storage.ts +492 -0
  118. package/src/core/types.ts +33 -0
  119. package/src/react/index.ts +2 -0
  120. package/src/react/sqlite-context.tsx +244 -0
  121. package/src/solid/index.ts +2 -0
  122. package/src/solid/sqlite-context.ts +156 -0
  123. package/src/svelte/SQLiteProvider.svelte +88 -0
  124. package/src/svelte/index.ts +6 -0
  125. package/src/svelte/sqlite-context.ts +32 -0
  126. package/src/svelte/svelte-compile.test-helper.ts +135 -0
  127. package/src/vue/index.ts +2 -0
  128. package/src/vue/sqlite-context.ts +105 -0
@@ -0,0 +1,676 @@
1
+ // Ported from expo-sqlite's SQLiteDatabase.ts (.vendors/expo @ origin/sdk-57,
2
+ // packages/expo-sqlite/src/SQLiteDatabase.ts), renamed with this repo's `I`-prefix convention.
3
+ //
4
+ // Not ported: `registerDatabaseForDevToolsAsync`/`unregisterDatabaseForDevToolsAsync`
5
+ // (SQLiteDevToolsClient.ts) — wiring for Expo's own DevTools browser extension, which this
6
+ // project has no equivalent of and does not otherwise depend on.
7
+ import { Platform } from 'expo-modules-core';
8
+ import type { EventSubscription } from 'expo-modules-core';
9
+
10
+ import { expoSQLite } from './native-module';
11
+ import { NativeDatabase, flattenOpenOptions } from './native-database';
12
+ import type { ISQLiteOpenOptions } from './native-database';
13
+ import { SQLiteSession } from './sqlite-session';
14
+ import { SQLiteStatement } from './sqlite-statement';
15
+ import type {
16
+ ISQLiteBindParams,
17
+ ISQLiteExecuteAsyncResult,
18
+ ISQLiteExecuteSyncResult,
19
+ ISQLiteRunResult,
20
+ ISQLiteVariadicBindParams,
21
+ } from './sqlite-statement';
22
+ import { SQLiteTaggedQuery } from './sqlite-tagged-query';
23
+ import { createDatabasePath } from './path-utils';
24
+ import type {
25
+ IDatabaseChangeEvent,
26
+ IOnInitCallback,
27
+ IOpenDatabaseOptions,
28
+ } from './types';
29
+
30
+ export type { ISQLiteOpenOptions } from './native-database';
31
+ export type {
32
+ IDatabaseChangeEvent,
33
+ IOnInitCallback,
34
+ IOpenDatabaseOptions,
35
+ } from './types';
36
+
37
+ /** A SQLite database. */
38
+ export class SQLiteDatabase {
39
+ constructor(
40
+ public readonly databasePath: string,
41
+ public readonly options: ISQLiteOpenOptions,
42
+ public readonly nativeDatabase: NativeDatabase,
43
+ ) {}
44
+
45
+ /** Whether the database is currently in a transaction. */
46
+ public isInTransactionAsync(): Promise<boolean> {
47
+ return this.nativeDatabase.isInTransactionAsync();
48
+ }
49
+
50
+ /** Closes the database. */
51
+ public closeAsync(): Promise<void> {
52
+ return this.nativeDatabase.closeAsync();
53
+ }
54
+
55
+ /**
56
+ * Executes all SQL queries in the supplied string.
57
+ * > **Note:** The queries are not escaped for you — be careful when constructing them.
58
+ */
59
+ public execAsync(source: string): Promise<void> {
60
+ return this.nativeDatabase.execAsync(source);
61
+ }
62
+
63
+ /**
64
+ * [Serializes the database](https://sqlite.org/c3ref/serialize.html) as a `Uint8Array`.
65
+ * @param databaseName The attached database name. Defaults to `main`.
66
+ */
67
+ public serializeAsync(databaseName: string = 'main'): Promise<Uint8Array> {
68
+ return this.nativeDatabase.serializeAsync(databaseName);
69
+ }
70
+
71
+ /**
72
+ * Creates a [prepared statement](https://www.sqlite.org/c3ref/prepare.html) from `source`.
73
+ */
74
+ public async prepareAsync(source: string): Promise<SQLiteStatement> {
75
+ const nativeStatement = new expoSQLite.NativeStatement();
76
+ await this.nativeDatabase.prepareAsync(nativeStatement, source);
77
+ return new SQLiteStatement(this.nativeDatabase, nativeStatement);
78
+ }
79
+
80
+ /**
81
+ * Creates a new session for the database.
82
+ * @see [`sqlite3session_create`](https://www.sqlite.org/session/sqlite3session_create.html)
83
+ * @param dbName The database name to create a session for. Defaults to `main`.
84
+ */
85
+ public async createSessionAsync(
86
+ dbName: string = 'main',
87
+ ): Promise<SQLiteSession> {
88
+ const nativeSession = new expoSQLite.NativeSession();
89
+ await this.nativeDatabase.createSessionAsync(nativeSession, dbName);
90
+ return new SQLiteSession(this.nativeDatabase, nativeSession);
91
+ }
92
+
93
+ /**
94
+ * Loads a SQLite extension.
95
+ * @param libPath The path to the extension library file.
96
+ * @param entryPoint The extension's entry point. Inferred by
97
+ * [`sqlite3_load_extension`](https://www.sqlite.org/c3ref/load_extension.html) when omitted.
98
+ */
99
+ public loadExtensionAsync(
100
+ libPath: string,
101
+ entryPoint?: string,
102
+ ): Promise<void> {
103
+ return this.nativeDatabase.loadExtensionAsync(libPath, entryPoint);
104
+ }
105
+
106
+ /**
107
+ * Executes a transaction, committing/rolling back automatically based on `task`'s result.
108
+ *
109
+ * > **Note:** Not exclusive — other async queries can interleave, so the order of execution
110
+ * > relative to a query issued outside the transaction is not guaranteed. Use
111
+ * > `withExclusiveTransactionAsync` when that matters.
112
+ */
113
+ public async withTransactionAsync(task: () => Promise<void>): Promise<void> {
114
+ try {
115
+ await this.execAsync('BEGIN');
116
+ await task();
117
+ await this.execAsync('COMMIT');
118
+ } catch (error) {
119
+ await this.execAsync('ROLLBACK');
120
+ throw error;
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Executes a transaction, committing/rolling back automatically based on `task`'s result.
126
+ * The transaction may be exclusive: once it becomes a write transaction, other async write
127
+ * queries abort with a `database is locked` error.
128
+ *
129
+ * > **Note:** Not supported on web.
130
+ *
131
+ * @param task Any queries inside it must run on the `txn` object it receives — a private
132
+ * `SQLiteDatabase` subclass bound to the exclusive connection, typed here as the base class
133
+ * since the subclass is an implementation detail, not a public export.
134
+ */
135
+ public async withExclusiveTransactionAsync(
136
+ task: (txn: SQLiteDatabase) => Promise<void>,
137
+ ): Promise<void> {
138
+ if (Platform.OS === 'web') {
139
+ throw new Error('withExclusiveTransactionAsync is not supported on web');
140
+ }
141
+ const transaction = await SQLiteTransaction.createAsync(this);
142
+ let error: unknown;
143
+ try {
144
+ await transaction.execAsync('BEGIN');
145
+ await task(transaction);
146
+ await transaction.execAsync('COMMIT');
147
+ } catch (thrown) {
148
+ await transaction.execAsync('ROLLBACK');
149
+ error = thrown;
150
+ } finally {
151
+ await transaction.closeAsync();
152
+ }
153
+ if (error !== undefined) {
154
+ throw error;
155
+ }
156
+ }
157
+
158
+ /** Whether the database is currently in a transaction. */
159
+ public isInTransactionSync(): boolean {
160
+ return this.nativeDatabase.isInTransactionSync();
161
+ }
162
+
163
+ /** Closes the database. */
164
+ public closeSync(): void {
165
+ return this.nativeDatabase.closeSync();
166
+ }
167
+
168
+ /**
169
+ * Executes all SQL queries in the supplied string.
170
+ * > **Note:** The queries are not escaped for you. Running heavy tasks with this function can
171
+ * > block the JavaScript thread.
172
+ */
173
+ public execSync(source: string): void {
174
+ return this.nativeDatabase.execSync(source);
175
+ }
176
+
177
+ /**
178
+ * [Serializes the database](https://sqlite.org/c3ref/serialize.html) as a `Uint8Array`.
179
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
180
+ */
181
+ public serializeSync(databaseName: string = 'main'): Uint8Array {
182
+ return this.nativeDatabase.serializeSync(databaseName);
183
+ }
184
+
185
+ /**
186
+ * Creates a [prepared statement](https://www.sqlite.org/c3ref/prepare.html) from `source`.
187
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
188
+ */
189
+ public prepareSync(source: string): SQLiteStatement {
190
+ const nativeStatement = new expoSQLite.NativeStatement();
191
+ this.nativeDatabase.prepareSync(nativeStatement, source);
192
+ return new SQLiteStatement(this.nativeDatabase, nativeStatement);
193
+ }
194
+
195
+ /**
196
+ * Creates a new session for the database.
197
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
198
+ * @see [`sqlite3session_create`](https://www.sqlite.org/session/sqlite3session_create.html)
199
+ */
200
+ public createSessionSync(dbName: string = 'main'): SQLiteSession {
201
+ const nativeSession = new expoSQLite.NativeSession();
202
+ this.nativeDatabase.createSessionSync(nativeSession, dbName);
203
+ return new SQLiteSession(this.nativeDatabase, nativeSession);
204
+ }
205
+
206
+ /**
207
+ * Loads a SQLite extension.
208
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
209
+ */
210
+ public loadExtensionSync(libPath: string, entryPoint?: string): void {
211
+ this.nativeDatabase.loadExtensionSync(libPath, entryPoint);
212
+ }
213
+
214
+ /**
215
+ * Executes a transaction, committing/rolling back automatically based on `task`'s result.
216
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
217
+ */
218
+ public withTransactionSync(task: () => void): void {
219
+ try {
220
+ this.execSync('BEGIN');
221
+ task();
222
+ this.execSync('COMMIT');
223
+ } catch (error) {
224
+ this.execSync('ROLLBACK');
225
+ throw error;
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Executes SQL queries using tagged template literals (Bun-style), automatically parameterized
231
+ * against SQL injection. Directly awaitable (returns rows/`ISQLiteRunResult`); use `.values()`,
232
+ * `.first()`, `.each()`, or the `*Sync` variants for other shapes.
233
+ *
234
+ * @example
235
+ * ```ts
236
+ * const users = await db.sql<User>`SELECT * FROM users WHERE age > ${21}`;
237
+ * const rows = await db.sql`SELECT name, age FROM users`.values();
238
+ * const user = await db.sql<User>`SELECT * FROM users WHERE id = ${userId}`.first();
239
+ * ```
240
+ */
241
+ public sql = <T = unknown>(
242
+ strings: TemplateStringsArray,
243
+ ...values: unknown[]
244
+ ) => new SQLiteTaggedQuery<T>(this, strings, values);
245
+
246
+ //#region Statement API shorthands
247
+
248
+ /**
249
+ * A convenience wrapper around `prepareAsync()`, `SQLiteStatement.executeAsync()`, and
250
+ * `SQLiteStatement.finalizeAsync()`.
251
+ */
252
+ public runAsync(
253
+ source: string,
254
+ params: ISQLiteBindParams,
255
+ ): Promise<ISQLiteRunResult>;
256
+ /** @hidden */
257
+ public runAsync(
258
+ source: string,
259
+ ...params: ISQLiteVariadicBindParams
260
+ ): Promise<ISQLiteRunResult>;
261
+ // `any[]`: the implementation signature of an overloaded function is not itself callable, so
262
+ // TS checks `statement.executeAsync(...params)` below against ITS overloads, not against
263
+ // whatever narrower type is written here — `unknown[]` fails that check for every one of
264
+ // these forwarding methods, matching upstream's own `any[]` for the identical reason.
265
+ public async runAsync(
266
+ source: string,
267
+ ...params: any[]
268
+ ): Promise<ISQLiteRunResult> {
269
+ const statement = await this.prepareAsync(source);
270
+ let result: ISQLiteExecuteAsyncResult<unknown>;
271
+ try {
272
+ result = await statement.executeAsync(...params);
273
+ } finally {
274
+ await statement.finalizeAsync();
275
+ }
276
+ return result;
277
+ }
278
+
279
+ /**
280
+ * A convenience wrapper around `prepareAsync()`, `SQLiteStatement.executeAsync()`,
281
+ * `ISQLiteExecuteAsyncResult.getFirstAsync()`, and `SQLiteStatement.finalizeAsync()`.
282
+ */
283
+ public getFirstAsync<T>(
284
+ source: string,
285
+ params: ISQLiteBindParams,
286
+ ): Promise<T | null>;
287
+ /** @hidden */
288
+ public getFirstAsync<T>(
289
+ source: string,
290
+ ...params: ISQLiteVariadicBindParams
291
+ ): Promise<T | null>;
292
+ public async getFirstAsync<T>(
293
+ source: string,
294
+ ...params: any[]
295
+ ): Promise<T | null> {
296
+ const statement = await this.prepareAsync(source);
297
+ let firstRow: T | null;
298
+ try {
299
+ const result = await statement.executeAsync<T>(...params);
300
+ firstRow = await result.getFirstAsync();
301
+ } finally {
302
+ await statement.finalizeAsync();
303
+ }
304
+ return firstRow;
305
+ }
306
+
307
+ /**
308
+ * A convenience wrapper around `prepareAsync()`, `SQLiteStatement.executeAsync()`, the
309
+ * `ISQLiteExecuteAsyncResult` async iterator, and `SQLiteStatement.finalizeAsync()`.
310
+ */
311
+ public getEachAsync<T>(
312
+ source: string,
313
+ params: ISQLiteBindParams,
314
+ ): AsyncIterableIterator<T>;
315
+ /** @hidden */
316
+ public getEachAsync<T>(
317
+ source: string,
318
+ ...params: ISQLiteVariadicBindParams
319
+ ): AsyncIterableIterator<T>;
320
+ public async *getEachAsync<T>(
321
+ source: string,
322
+ ...params: any[]
323
+ ): AsyncIterableIterator<T> {
324
+ const statement = await this.prepareAsync(source);
325
+ try {
326
+ const result = await statement.executeAsync<T>(...params);
327
+ for await (const row of result) {
328
+ yield row;
329
+ }
330
+ } finally {
331
+ await statement.finalizeAsync();
332
+ }
333
+ }
334
+
335
+ /**
336
+ * A convenience wrapper around `prepareAsync()`, `SQLiteStatement.executeAsync()`,
337
+ * `ISQLiteExecuteAsyncResult.getAllAsync()`, and `SQLiteStatement.finalizeAsync()`.
338
+ */
339
+ public getAllAsync<T>(
340
+ source: string,
341
+ params: ISQLiteBindParams,
342
+ ): Promise<T[]>;
343
+ /** @hidden */
344
+ public getAllAsync<T>(
345
+ source: string,
346
+ ...params: ISQLiteVariadicBindParams
347
+ ): Promise<T[]>;
348
+ public async getAllAsync<T>(source: string, ...params: any[]): Promise<T[]> {
349
+ const statement = await this.prepareAsync(source);
350
+ let allRows: T[];
351
+ try {
352
+ const result = await statement.executeAsync<T>(...params);
353
+ allRows = await result.getAllAsync();
354
+ } finally {
355
+ await statement.finalizeAsync();
356
+ }
357
+ return allRows;
358
+ }
359
+
360
+ /**
361
+ * A convenience wrapper around `prepareSync()`, `SQLiteStatement.executeSync()`, and
362
+ * `SQLiteStatement.finalizeSync()`.
363
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
364
+ */
365
+ public runSync(source: string, params: ISQLiteBindParams): ISQLiteRunResult;
366
+ /** @hidden */
367
+ public runSync(
368
+ source: string,
369
+ ...params: ISQLiteVariadicBindParams
370
+ ): ISQLiteRunResult;
371
+ public runSync(source: string, ...params: any[]): ISQLiteRunResult {
372
+ const statement = this.prepareSync(source);
373
+ let result: ISQLiteExecuteSyncResult<unknown>;
374
+ try {
375
+ result = statement.executeSync(...params);
376
+ } finally {
377
+ statement.finalizeSync();
378
+ }
379
+ return result;
380
+ }
381
+
382
+ /**
383
+ * A convenience wrapper around `prepareSync()`, `SQLiteStatement.executeSync()`,
384
+ * `ISQLiteExecuteSyncResult.getFirstSync()`, and `SQLiteStatement.finalizeSync()`.
385
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
386
+ */
387
+ public getFirstSync<T>(source: string, params: ISQLiteBindParams): T | null;
388
+ /** @hidden */
389
+ public getFirstSync<T>(
390
+ source: string,
391
+ ...params: ISQLiteVariadicBindParams
392
+ ): T | null;
393
+ public getFirstSync<T>(source: string, ...params: any[]): T | null {
394
+ const statement = this.prepareSync(source);
395
+ let firstRow: T | null;
396
+ try {
397
+ const result = statement.executeSync<T>(...params);
398
+ firstRow = result.getFirstSync();
399
+ } finally {
400
+ statement.finalizeSync();
401
+ }
402
+ return firstRow;
403
+ }
404
+
405
+ /**
406
+ * A convenience wrapper around `prepareSync()`, `SQLiteStatement.executeSync()`, the
407
+ * `ISQLiteExecuteSyncResult` iterator, and `SQLiteStatement.finalizeSync()`.
408
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
409
+ */
410
+ public getEachSync<T>(
411
+ source: string,
412
+ params: ISQLiteBindParams,
413
+ ): IterableIterator<T>;
414
+ /** @hidden */
415
+ public getEachSync<T>(
416
+ source: string,
417
+ ...params: ISQLiteVariadicBindParams
418
+ ): IterableIterator<T>;
419
+ public *getEachSync<T>(
420
+ source: string,
421
+ ...params: any[]
422
+ ): IterableIterator<T> {
423
+ const statement = this.prepareSync(source);
424
+ try {
425
+ const result = statement.executeSync<T>(...params);
426
+ for (const row of result) {
427
+ yield row;
428
+ }
429
+ } finally {
430
+ statement.finalizeSync();
431
+ }
432
+ }
433
+
434
+ /**
435
+ * A convenience wrapper around `prepareSync()`, `SQLiteStatement.executeSync()`,
436
+ * `ISQLiteExecuteSyncResult.getAllSync()`, and `SQLiteStatement.finalizeSync()`.
437
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
438
+ */
439
+ public getAllSync<T>(source: string, params: ISQLiteBindParams): T[];
440
+ /** @hidden */
441
+ public getAllSync<T>(
442
+ source: string,
443
+ ...params: ISQLiteVariadicBindParams
444
+ ): T[];
445
+ public getAllSync<T>(source: string, ...params: any[]): T[] {
446
+ const statement = this.prepareSync(source);
447
+ let allRows: T[];
448
+ try {
449
+ const result = statement.executeSync<T>(...params);
450
+ allRows = result.getAllSync();
451
+ } finally {
452
+ statement.finalizeSync();
453
+ }
454
+ return allRows;
455
+ }
456
+
457
+ /** Synchronizes the local database with the remote libSQL server (libSQL integration only). */
458
+ public syncLibSQL(): Promise<void> {
459
+ if (typeof this.nativeDatabase.syncLibSQL !== 'function') {
460
+ throw new Error('syncLibSQL is not supported in the current environment');
461
+ }
462
+ return this.nativeDatabase.syncLibSQL();
463
+ }
464
+
465
+ //#endregion
466
+ }
467
+
468
+ /** The default directory new databases are created in. */
469
+ export const defaultDatabaseDirectory = expoSQLite.defaultDatabaseDirectory;
470
+
471
+ /**
472
+ * Pre-bundled SQLite extensions. Bundling one (e.g. `sqlite-vec`) is a manual native-config
473
+ * step this package does not automate — see the README.
474
+ */
475
+ export const bundledExtensions = expoSQLite.bundledExtensions;
476
+
477
+ async function runOnInit(
478
+ db: SQLiteDatabase,
479
+ onInit: IOnInitCallback | undefined,
480
+ ): Promise<void> {
481
+ if (onInit) {
482
+ await onInit(db);
483
+ }
484
+ }
485
+
486
+ /**
487
+ * Opens a database.
488
+ * @param databaseName The database file name to open.
489
+ * @param options Open options — see `IOpenDatabaseOptions` for the `onInit` deviation from
490
+ * upstream (documented in the README).
491
+ * @param directory The directory the database file is located in. Defaults to
492
+ * `defaultDatabaseDirectory`.
493
+ */
494
+ export async function openDatabaseAsync(
495
+ databaseName: string,
496
+ options?: IOpenDatabaseOptions,
497
+ directory?: string,
498
+ ): Promise<SQLiteDatabase> {
499
+ const { onInit, ...openOptions } = options ?? {};
500
+ const databasePath = createDatabasePath(databaseName, directory);
501
+ await expoSQLite.ensureDatabasePathExistsAsync(databasePath);
502
+ const nativeDatabase = new expoSQLite.NativeDatabase(
503
+ databasePath,
504
+ flattenOpenOptions(openOptions),
505
+ );
506
+ await nativeDatabase.initAsync();
507
+ const database = new SQLiteDatabase(
508
+ databasePath,
509
+ openOptions,
510
+ nativeDatabase,
511
+ );
512
+ await runOnInit(database, onInit);
513
+ return database;
514
+ }
515
+
516
+ /**
517
+ * Opens a database.
518
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
519
+ */
520
+ export function openDatabaseSync(
521
+ databaseName: string,
522
+ options?: IOpenDatabaseOptions,
523
+ directory?: string,
524
+ ): SQLiteDatabase {
525
+ const { onInit, ...openOptions } = options ?? {};
526
+ const databasePath = createDatabasePath(databaseName, directory);
527
+ expoSQLite.ensureDatabasePathExistsSync(databasePath);
528
+ const nativeDatabase = new expoSQLite.NativeDatabase(
529
+ databasePath,
530
+ flattenOpenOptions(openOptions),
531
+ );
532
+ nativeDatabase.initSync();
533
+ const database = new SQLiteDatabase(
534
+ databasePath,
535
+ openOptions,
536
+ nativeDatabase,
537
+ );
538
+ if (onInit) {
539
+ const result = onInit(database);
540
+ if (result instanceof Promise) {
541
+ throw new Error(
542
+ 'openDatabaseSync: onInit returned a Promise — pass a synchronous callback, or use openDatabaseAsync.',
543
+ );
544
+ }
545
+ }
546
+ return database;
547
+ }
548
+
549
+ /**
550
+ * Given `Uint8Array` data, [deserializes it to an in-memory database](https://sqlite.org/c3ref/deserialize.html).
551
+ * @param serializedData The binary array from `SQLiteDatabase.serializeAsync()`.
552
+ */
553
+ export async function deserializeDatabaseAsync(
554
+ serializedData: Uint8Array,
555
+ options?: ISQLiteOpenOptions,
556
+ ): Promise<SQLiteDatabase> {
557
+ const openOptions = options ?? {};
558
+ const nativeDatabase = new expoSQLite.NativeDatabase(
559
+ ':memory:',
560
+ flattenOpenOptions(openOptions),
561
+ serializedData,
562
+ );
563
+ await nativeDatabase.initAsync();
564
+ return new SQLiteDatabase(':memory:', openOptions, nativeDatabase);
565
+ }
566
+
567
+ /**
568
+ * Given `Uint8Array` data, [deserializes it to an in-memory database](https://sqlite.org/c3ref/deserialize.html).
569
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
570
+ */
571
+ export function deserializeDatabaseSync(
572
+ serializedData: Uint8Array,
573
+ options?: ISQLiteOpenOptions,
574
+ ): SQLiteDatabase {
575
+ const openOptions = options ?? {};
576
+ const nativeDatabase = new expoSQLite.NativeDatabase(
577
+ ':memory:',
578
+ flattenOpenOptions(openOptions),
579
+ serializedData,
580
+ );
581
+ nativeDatabase.initSync();
582
+ return new SQLiteDatabase(':memory:', openOptions, nativeDatabase);
583
+ }
584
+
585
+ /** Deletes a database file. */
586
+ export async function deleteDatabaseAsync(
587
+ databaseName: string,
588
+ directory?: string,
589
+ ): Promise<void> {
590
+ const databasePath = createDatabasePath(databaseName, directory);
591
+ return await expoSQLite.deleteDatabaseAsync(databasePath);
592
+ }
593
+
594
+ /**
595
+ * Deletes a database file.
596
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
597
+ */
598
+ export function deleteDatabaseSync(
599
+ databaseName: string,
600
+ directory?: string,
601
+ ): void {
602
+ const databasePath = createDatabasePath(databaseName, directory);
603
+ return expoSQLite.deleteDatabaseSync(databasePath);
604
+ }
605
+
606
+ /**
607
+ * Backs up a database to another database.
608
+ * @see https://www.sqlite.org/c3ref/backup_finish.html
609
+ */
610
+ export function backupDatabaseAsync(options: {
611
+ sourceDatabase: SQLiteDatabase;
612
+ sourceDatabaseName?: string;
613
+ destDatabase: SQLiteDatabase;
614
+ destDatabaseName?: string;
615
+ }): Promise<void> {
616
+ const { sourceDatabase, sourceDatabaseName, destDatabase, destDatabaseName } =
617
+ options;
618
+ return expoSQLite.backupDatabaseAsync(
619
+ destDatabase.nativeDatabase,
620
+ destDatabaseName ?? 'main',
621
+ sourceDatabase.nativeDatabase,
622
+ sourceDatabaseName ?? 'main',
623
+ );
624
+ }
625
+
626
+ /**
627
+ * Backs up a database to another database.
628
+ * > **Note:** Running heavy tasks with this function can block the JavaScript thread.
629
+ * @see https://www.sqlite.org/c3ref/backup_finish.html
630
+ */
631
+ export function backupDatabaseSync(options: {
632
+ sourceDatabase: SQLiteDatabase;
633
+ sourceDatabaseName?: string;
634
+ destDatabase: SQLiteDatabase;
635
+ destDatabaseName?: string;
636
+ }): void {
637
+ const { sourceDatabase, sourceDatabaseName, destDatabase, destDatabaseName } =
638
+ options;
639
+ return expoSQLite.backupDatabaseSync(
640
+ destDatabase.nativeDatabase,
641
+ destDatabaseName ?? 'main',
642
+ sourceDatabase.nativeDatabase,
643
+ sourceDatabaseName ?? 'main',
644
+ );
645
+ }
646
+
647
+ /**
648
+ * Adds a listener for database changes.
649
+ * > **Note:** requires `enableChangeListener: true` in `ISQLiteOpenOptions` when opening.
650
+ */
651
+ export function addDatabaseChangeListener(
652
+ listener: (event: IDatabaseChangeEvent) => void,
653
+ ): EventSubscription {
654
+ return expoSQLite.addListener('onDatabaseChange', listener);
655
+ }
656
+
657
+ /**
658
+ * A new connection specifically used by `withExclusiveTransactionAsync`.
659
+ * @hidden not exposing all the database methods to the public API surface
660
+ */
661
+ class SQLiteTransaction extends SQLiteDatabase {
662
+ public static async createAsync(
663
+ db: SQLiteDatabase,
664
+ ): Promise<SQLiteTransaction> {
665
+ const options: ISQLiteOpenOptions = {
666
+ ...db.options,
667
+ useNewConnection: true,
668
+ };
669
+ const nativeDatabase = new expoSQLite.NativeDatabase(
670
+ db.databasePath,
671
+ flattenOpenOptions(options),
672
+ );
673
+ await nativeDatabase.initAsync();
674
+ return new SQLiteTransaction(db.databasePath, options, nativeDatabase);
675
+ }
676
+ }