expo-sqlite 15.2.8 → 15.2.10

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/CHANGELOG.md +15 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/sqlite/SQLiteModule.kt +39 -34
  4. package/build/Storage.d.ts +4 -4
  5. package/build/Storage.d.ts.map +1 -1
  6. package/build/Storage.js +70 -37
  7. package/build/Storage.js.map +1 -1
  8. package/expo-module.config.json +1 -7
  9. package/ios/NativeStatement.swift +1 -0
  10. package/ios/SQLiteModule.swift +7 -0
  11. package/package.json +6 -4
  12. package/src/Storage.ts +77 -43
  13. package/web/WorkerChannel.ts +16 -6
  14. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8-sources.jar +0 -0
  15. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8-sources.jar.md5 +0 -1
  16. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8-sources.jar.sha1 +0 -1
  17. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8-sources.jar.sha256 +0 -1
  18. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8-sources.jar.sha512 +0 -1
  19. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.aar +0 -0
  20. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.aar.md5 +0 -1
  21. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.aar.sha1 +0 -1
  22. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.aar.sha256 +0 -1
  23. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.aar.sha512 +0 -1
  24. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.module +0 -87
  25. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.module.md5 +0 -1
  26. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.module.sha1 +0 -1
  27. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.module.sha256 +0 -1
  28. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.module.sha512 +0 -1
  29. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.pom +0 -35
  30. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.pom.md5 +0 -1
  31. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.pom.sha1 +0 -1
  32. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.pom.sha256 +0 -1
  33. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/15.2.8/expo.modules.sqlite-15.2.8.pom.sha512 +0 -1
  34. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml +0 -13
  35. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml.md5 +0 -1
  36. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml.sha1 +0 -1
  37. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml.sha256 +0 -1
  38. package/local-maven-repo/host/exp/exponent/expo.modules.sqlite/maven-metadata.xml.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,21 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 15.2.10 — 2025-05-08
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - Fixed parallel issue for `Statement.executeAsync`. ([#36674](https://github.com/expo/expo/pull/36674) by [@kudo](https://github.com/kudo))
18
+
19
+ ### 💡 Others
20
+
21
+ - Avoided synchronous API calls for `kv-store`. ([#36669](https://github.com/expo/expo/pull/36669) by [@kudo](https://github.com/kudo))
22
+ - Improved synchronous APIs on web. ([#36670](https://github.com/expo/expo/pull/36670) by [@kudo](https://github.com/kudo))
23
+
24
+ ## 15.2.9 — 2025-04-30
25
+
26
+ _This version does not introduce any user-facing changes._
27
+
13
28
  ## 15.2.8 — 2025-04-30
14
29
 
15
30
  ### 📚 3rd party library updates
@@ -45,13 +45,13 @@ def reactNativeArchitectures() {
45
45
  }
46
46
 
47
47
  group = 'host.exp.exponent'
48
- version = '15.2.8'
48
+ version = '15.2.10'
49
49
 
50
50
  android {
51
51
  namespace "expo.modules.sqlite"
52
52
  defaultConfig {
53
53
  versionCode 18
54
- versionName "15.2.8"
54
+ versionName "15.2.10"
55
55
  buildConfigField "boolean", "USE_LIBSQL", project.ext.USE_LIBSQL.toString()
56
56
 
57
57
  externalNativeBuild {
@@ -367,44 +367,49 @@ class SQLiteModule : Module() {
367
367
  private fun run(statement: NativeStatement, database: NativeDatabase, bindParams: Map<String, Any>, bindBlobParams: Map<String, ByteArray>, shouldPassAsArray: Boolean): Map<String, Any> {
368
368
  maybeThrowForClosedDatabase(database)
369
369
  maybeThrowForFinalizedStatement(statement)
370
- statement.ref.sqlite3_reset()
371
- statement.ref.sqlite3_clear_bindings()
372
- for ((key, param) in bindParams) {
373
- val index = getBindParamIndex(statement, key, shouldPassAsArray)
374
- if (index > 0) {
375
- // expo-modules-core AnyTypeConverter casts JavaScript Number to Kotlin Double,
376
- // here to cast as Long if the value is an integer.
377
- val normalizedParam =
378
- if (param is Double && param.toDouble() % 1.0 == 0.0) {
379
- param.toLong()
380
- } else {
381
- param
382
- }
383
- statement.ref.bindStatementParam(index, normalizedParam)
370
+
371
+ // The statement with parameter bindings is stateful,
372
+ // we have to guard with a critical section for thread safety.
373
+ synchronized(statement) {
374
+ statement.ref.sqlite3_reset()
375
+ statement.ref.sqlite3_clear_bindings()
376
+ for ((key, param) in bindParams) {
377
+ val index = getBindParamIndex(statement, key, shouldPassAsArray)
378
+ if (index > 0) {
379
+ // expo-modules-core AnyTypeConverter casts JavaScript Number to Kotlin Double,
380
+ // here to cast as Long if the value is an integer.
381
+ val normalizedParam =
382
+ if (param is Double && param.toDouble() % 1.0 == 0.0) {
383
+ param.toLong()
384
+ } else {
385
+ param
386
+ }
387
+ statement.ref.bindStatementParam(index, normalizedParam)
388
+ }
384
389
  }
385
- }
386
- for ((key, param) in bindBlobParams) {
387
- val index = getBindParamIndex(statement, key, shouldPassAsArray)
388
- if (index > 0) {
389
- statement.ref.bindStatementParam(index, param)
390
+ for ((key, param) in bindBlobParams) {
391
+ val index = getBindParamIndex(statement, key, shouldPassAsArray)
392
+ if (index > 0) {
393
+ statement.ref.bindStatementParam(index, param)
394
+ }
390
395
  }
391
- }
392
396
 
393
- val ret = statement.ref.sqlite3_step()
394
- if (ret != NativeDatabaseBinding.SQLITE_ROW && ret != NativeDatabaseBinding.SQLITE_DONE) {
395
- throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
396
- }
397
- val firstRowValues: SQLiteColumnValues =
398
- if (ret == NativeDatabaseBinding.SQLITE_ROW) {
399
- statement.ref.getColumnValues()
400
- } else {
401
- arrayListOf()
397
+ val ret = statement.ref.sqlite3_step()
398
+ if (ret != NativeDatabaseBinding.SQLITE_ROW && ret != NativeDatabaseBinding.SQLITE_DONE) {
399
+ throw SQLiteErrorException(database.ref.convertSqlLiteErrorToString())
402
400
  }
403
- return mapOf(
404
- "lastInsertRowId" to database.ref.sqlite3_last_insert_rowid().toInt(),
405
- "changes" to database.ref.sqlite3_changes(),
406
- "firstRowValues" to firstRowValues
407
- )
401
+ val firstRowValues: SQLiteColumnValues =
402
+ if (ret == NativeDatabaseBinding.SQLITE_ROW) {
403
+ statement.ref.getColumnValues()
404
+ } else {
405
+ arrayListOf()
406
+ }
407
+ return mapOf(
408
+ "lastInsertRowId" to database.ref.sqlite3_last_insert_rowid().toInt(),
409
+ "changes" to database.ref.sqlite3_changes(),
410
+ "firstRowValues" to firstRowValues
411
+ )
412
+ }
408
413
  }
409
414
 
410
415
  @Throws(AccessClosedResourceException::class, InvalidConvertibleException::class, SQLiteErrorException::class)
@@ -1,7 +1,3 @@
1
- /**
2
- * @hidden
3
- */
4
- export declare function checkValidInput(...input: unknown[]): void;
5
1
  /**
6
2
  * Update function for the [`setItemAsync()`](#setitemasynckey-value) or [`setItemSync()`](#setitemsynckey-value) method. It computes the new value based on the previous value. The function returns the new value to set for the key.
7
3
  * @param prevValue The previous value associated with the key, or `null` if the key was not set.
@@ -14,6 +10,7 @@ export type SQLiteStorageSetItemUpdateFunction = (prevValue: string | null) => s
14
10
  export declare class SQLiteStorage {
15
11
  private readonly databaseName;
16
12
  private db;
13
+ private readonly awaitLock;
17
14
  constructor(databaseName: string);
18
15
  /**
19
16
  * Retrieves the value associated with the given key asynchronously.
@@ -111,12 +108,15 @@ export declare class SQLiteStorage {
111
108
  * Alias for [`closeAsync()`](#closeasync-1) method.
112
109
  */
113
110
  close(): Promise<void>;
111
+ private getDbAsync;
114
112
  private getDbSync;
113
+ private maybeMigrateDbAsync;
115
114
  private maybeMigrateDbSync;
116
115
  /**
117
116
  * Recursively merge two JSON objects.
118
117
  */
119
118
  private static mergeDeep;
119
+ private checkValidInput;
120
120
  }
121
121
  /**
122
122
  * This default instance of the [`SQLiteStorage`](#sqlitestorage-1) class is used as a drop-in replacement for the `AsyncStorage` module from [`@react-native-async-storage/async-storage`](https://github.com/react-native-async-storage/async-storage).
@@ -1 +1 @@
1
- {"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../src/Storage.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,QAclD;AAED;;;;GAIG;AACH,MAAM,MAAM,kCAAkC,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC;AAatF;;GAEG;AACH,qBAAa,aAAa;IAGZ,OAAO,CAAC,QAAQ,CAAC,YAAY;IAFzC,OAAO,CAAC,EAAE,CAA+B;gBAEZ,YAAY,EAAE,MAAM;IAIjD;;OAEG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAOvD;;;OAGG;IACG,YAAY,CAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,kCAAkC,GACjD,OAAO,CAAC,IAAI,CAAC;IAkBhB;;OAEG;IACG,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOpD;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAM1C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAMpC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWjC;;OAEG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOvC;;;OAGG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,kCAAkC,GAAG,IAAI;IAkBlF;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAOpC;;OAEG;IACH,cAAc,IAAI,MAAM,EAAE;IAM1B;;OAEG;IACH,SAAS,IAAI,OAAO;IAMpB;;OAEG;IACH,SAAS,IAAI,IAAI;IAWjB;;OAEG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIlD;;OAEG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,kCAAkC,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7F;;OAEG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIrC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;OAGG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa1D;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IASlE;;OAEG;IACG,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAUhE;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAUhD;;;OAGG;IACG,UAAU,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBlE;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;CA4BzB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,eAAyC,CAAC;AAEnE,eAAe,YAAY,CAAC;AAE5B;;GAEG;AACH,eAAO,MAAM,OAAO,eAAe,CAAC"}
1
+ {"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../src/Storage.ts"],"names":[],"mappings":"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"}
package/build/Storage.js CHANGED
@@ -1,16 +1,5 @@
1
- import { openDatabaseSync } from './index';
2
- /**
3
- * @hidden
4
- */
5
- export function checkValidInput(...input) {
6
- const [key, value] = input;
7
- if (typeof key !== 'string') {
8
- throw new Error(`[SQLiteStorage] Using ${typeof key} type for key is not supported. Use string instead. Key passed: ${key}`);
9
- }
10
- if (input.length > 1 && typeof value !== 'string' && typeof value !== 'function') {
11
- throw new Error(`[SQLiteStorage] Using ${typeof value} type for value is not supported. Use string instead. Key passed: ${key}. Value passed : ${value}`);
12
- }
13
- }
1
+ import AwaitLock from 'await-lock';
2
+ import { openDatabaseAsync, openDatabaseSync } from './index';
14
3
  const DATABASE_VERSION = 1;
15
4
  const STATEMENT_GET = 'SELECT value FROM storage WHERE key = ?;';
16
5
  const STATEMENT_SET = 'INSERT INTO storage (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value;';
@@ -24,6 +13,7 @@ const MIGRATION_STATEMENT_0 = 'CREATE TABLE IF NOT EXISTS storage (key TEXT PRIM
24
13
  export class SQLiteStorage {
25
14
  databaseName;
26
15
  db = null;
16
+ awaitLock = new AwaitLock();
27
17
  constructor(databaseName) {
28
18
  this.databaseName = databaseName;
29
19
  }
@@ -32,8 +22,8 @@ export class SQLiteStorage {
32
22
  * Retrieves the value associated with the given key asynchronously.
33
23
  */
34
24
  async getItemAsync(key) {
35
- checkValidInput(key);
36
- const db = this.getDbSync();
25
+ this.checkValidInput(key);
26
+ const db = await this.getDbAsync();
37
27
  const result = await db.getFirstAsync(STATEMENT_GET, key);
38
28
  return result?.value ?? null;
39
29
  }
@@ -42,14 +32,14 @@ export class SQLiteStorage {
42
32
  * If a function is provided, it computes the new value based on the previous value.
43
33
  */
44
34
  async setItemAsync(key, value) {
45
- checkValidInput(key, value);
46
- const db = this.getDbSync();
35
+ this.checkValidInput(key, value);
36
+ const db = await this.getDbAsync();
47
37
  if (typeof value === 'function') {
48
38
  await db.withExclusiveTransactionAsync(async (tx) => {
49
39
  const prevResult = await tx.getFirstAsync(STATEMENT_GET, key);
50
40
  const prevValue = prevResult?.value ?? null;
51
41
  const nextValue = value(prevValue);
52
- checkValidInput(key, nextValue);
42
+ this.checkValidInput(key, nextValue);
53
43
  await tx.runAsync(STATEMENT_SET, key, nextValue);
54
44
  });
55
45
  return;
@@ -60,8 +50,8 @@ export class SQLiteStorage {
60
50
  * Removes the value associated with the given key asynchronously.
61
51
  */
62
52
  async removeItemAsync(key) {
63
- checkValidInput(key);
64
- const db = this.getDbSync();
53
+ this.checkValidInput(key);
54
+ const db = await this.getDbAsync();
65
55
  const result = await db.runAsync(STATEMENT_REMOVE, key);
66
56
  return result.changes > 0;
67
57
  }
@@ -69,7 +59,7 @@ export class SQLiteStorage {
69
59
  * Retrieves all keys stored in the storage asynchronously.
70
60
  */
71
61
  async getAllKeysAsync() {
72
- const db = this.getDbSync();
62
+ const db = await this.getDbAsync();
73
63
  const result = await db.getAllAsync(STATEMENT_GET_ALL_KEYS);
74
64
  return result.map(({ key }) => key);
75
65
  }
@@ -77,7 +67,7 @@ export class SQLiteStorage {
77
67
  * Clears all key-value pairs from the storage asynchronously.
78
68
  */
79
69
  async clearAsync() {
80
- const db = this.getDbSync();
70
+ const db = await this.getDbAsync();
81
71
  const result = await db.runAsync(STATEMENT_CLEAR);
82
72
  return result.changes > 0;
83
73
  }
@@ -85,9 +75,15 @@ export class SQLiteStorage {
85
75
  * Closes the database connection asynchronously.
86
76
  */
87
77
  async closeAsync() {
88
- if (this.db) {
89
- await this.db.closeAsync();
90
- this.db = null;
78
+ await this.awaitLock.acquireAsync();
79
+ try {
80
+ if (this.db) {
81
+ await this.db.closeAsync();
82
+ this.db = null;
83
+ }
84
+ }
85
+ finally {
86
+ this.awaitLock.release();
91
87
  }
92
88
  }
93
89
  //#endregion
@@ -96,7 +92,7 @@ export class SQLiteStorage {
96
92
  * Retrieves the value associated with the given key synchronously.
97
93
  */
98
94
  getItemSync(key) {
99
- checkValidInput(key);
95
+ this.checkValidInput(key);
100
96
  const db = this.getDbSync();
101
97
  const result = db.getFirstSync(STATEMENT_GET, key);
102
98
  return result?.value ?? null;
@@ -106,14 +102,14 @@ export class SQLiteStorage {
106
102
  * If a function is provided, it computes the new value based on the previous value.
107
103
  */
108
104
  setItemSync(key, value) {
109
- checkValidInput(key, value);
105
+ this.checkValidInput(key, value);
110
106
  const db = this.getDbSync();
111
107
  if (typeof value === 'function') {
112
108
  db.withTransactionSync(() => {
113
109
  const prevResult = db.getFirstSync(STATEMENT_GET, key);
114
110
  const prevValue = prevResult?.value ?? null;
115
111
  const nextValue = value(prevValue);
116
- checkValidInput(key, nextValue);
112
+ this.checkValidInput(key, nextValue);
117
113
  db.runSync(STATEMENT_SET, key, nextValue);
118
114
  });
119
115
  return;
@@ -124,7 +120,7 @@ export class SQLiteStorage {
124
120
  * Removes the value associated with the given key synchronously.
125
121
  */
126
122
  removeItemSync(key) {
127
- checkValidInput(key);
123
+ this.checkValidInput(key);
128
124
  const db = this.getDbSync();
129
125
  const result = db.runSync(STATEMENT_REMOVE, key);
130
126
  return result.changes > 0;
@@ -191,7 +187,7 @@ export class SQLiteStorage {
191
187
  * If the existing value is a JSON object, performs a deep merge.
192
188
  */
193
189
  async mergeItem(key, value) {
194
- checkValidInput(key, value);
190
+ this.checkValidInput(key, value);
195
191
  await this.setItemAsync(key, (prevValue) => {
196
192
  if (prevValue == null) {
197
193
  return value;
@@ -207,7 +203,7 @@ export class SQLiteStorage {
207
203
  */
208
204
  async multiGet(keys) {
209
205
  return Promise.all(keys.map(async (key) => {
210
- checkValidInput(key);
206
+ this.checkValidInput(key);
211
207
  return [key, await this.getItemAsync(key)];
212
208
  }));
213
209
  }
@@ -215,10 +211,10 @@ export class SQLiteStorage {
215
211
  * Sets multiple key-value pairs asynchronously.
216
212
  */
217
213
  async multiSet(keyValuePairs) {
218
- const db = this.getDbSync();
214
+ const db = await this.getDbAsync();
219
215
  await db.withExclusiveTransactionAsync(async (tx) => {
220
216
  for (const [key, value] of keyValuePairs) {
221
- checkValidInput(key, value);
217
+ this.checkValidInput(key, value);
222
218
  await tx.runAsync(STATEMENT_SET, key, value);
223
219
  }
224
220
  });
@@ -227,10 +223,10 @@ export class SQLiteStorage {
227
223
  * Removes the values associated with the given keys asynchronously.
228
224
  */
229
225
  async multiRemove(keys) {
230
- const db = this.getDbSync();
226
+ const db = await this.getDbAsync();
231
227
  await db.withExclusiveTransactionAsync(async (tx) => {
232
228
  for (const key of keys) {
233
- checkValidInput(key);
229
+ this.checkValidInput(key);
234
230
  await tx.runAsync(STATEMENT_REMOVE, key);
235
231
  }
236
232
  });
@@ -240,10 +236,10 @@ export class SQLiteStorage {
240
236
  * If existing values are JSON objects, performs a deep merge.
241
237
  */
242
238
  async multiMerge(keyValuePairs) {
243
- const db = this.getDbSync();
239
+ const db = await this.getDbAsync();
244
240
  await db.withExclusiveTransactionAsync(async (tx) => {
245
241
  for (const [key, value] of keyValuePairs) {
246
- checkValidInput(key, value);
242
+ this.checkValidInput(key, value);
247
243
  const prevValue = await tx.getFirstAsync(STATEMENT_GET, key);
248
244
  if (prevValue == null) {
249
245
  await tx.runAsync(STATEMENT_SET, key, value);
@@ -264,6 +260,20 @@ export class SQLiteStorage {
264
260
  }
265
261
  //#endregion
266
262
  //#region Internals
263
+ async getDbAsync() {
264
+ await this.awaitLock.acquireAsync();
265
+ try {
266
+ if (!this.db) {
267
+ const db = await openDatabaseAsync(this.databaseName);
268
+ await this.maybeMigrateDbAsync(db);
269
+ this.db = db;
270
+ }
271
+ }
272
+ finally {
273
+ this.awaitLock.release();
274
+ }
275
+ return this.db;
276
+ }
267
277
  getDbSync() {
268
278
  if (!this.db) {
269
279
  const db = openDatabaseSync(this.databaseName);
@@ -272,6 +282,20 @@ export class SQLiteStorage {
272
282
  }
273
283
  return this.db;
274
284
  }
285
+ maybeMigrateDbAsync(db) {
286
+ return db.withTransactionAsync(async () => {
287
+ const result = await db.getFirstAsync('PRAGMA user_version');
288
+ let currentDbVersion = result?.user_version ?? 0;
289
+ if (currentDbVersion >= DATABASE_VERSION) {
290
+ return;
291
+ }
292
+ if (currentDbVersion === 0) {
293
+ await db.execAsync(MIGRATION_STATEMENT_0);
294
+ currentDbVersion = 1;
295
+ }
296
+ await db.execAsync(`PRAGMA user_version = ${DATABASE_VERSION}`);
297
+ });
298
+ }
275
299
  maybeMigrateDbSync(db) {
276
300
  db.withTransactionSync(() => {
277
301
  const result = db.getFirstSync('PRAGMA user_version');
@@ -313,6 +337,15 @@ export class SQLiteStorage {
313
337
  }
314
338
  return output;
315
339
  }
340
+ checkValidInput(...input) {
341
+ const [key, value] = input;
342
+ if (typeof key !== 'string') {
343
+ throw new Error(`[SQLiteStorage] Using ${typeof key} type for key is not supported. Use string instead. Key passed: ${key}`);
344
+ }
345
+ if (input.length > 1 && typeof value !== 'string' && typeof value !== 'function') {
346
+ throw new Error(`[SQLiteStorage] Using ${typeof value} type for value is not supported. Use string instead. Key passed: ${key}. Value passed : ${value}`);
347
+ }
348
+ }
316
349
  }
317
350
  /**
318
351
  * This default instance of the [`SQLiteStorage`](#sqlitestorage-1) class is used as a drop-in replacement for the `AsyncStorage` module from [`@react-native-async-storage/async-storage`](https://github.com/react-native-async-storage/async-storage).
@@ -1 +1 @@
1
- {"version":3,"file":"Storage.js","sourceRoot":"","sources":["../src/Storage.ts"],"names":[],"mappings":"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","sourcesContent":["import { openDatabaseSync, type SQLiteDatabase } from './index';\n\n/**\n * @hidden\n */\nexport function checkValidInput(...input: unknown[]) {\n const [key, value] = input;\n\n if (typeof key !== 'string') {\n throw new Error(\n `[SQLiteStorage] Using ${typeof key} type for key is not supported. Use string instead. Key passed: ${key}`\n );\n }\n\n if (input.length > 1 && typeof value !== 'string' && typeof value !== 'function') {\n throw new Error(\n `[SQLiteStorage] Using ${typeof value} type for value is not supported. Use string instead. Key passed: ${key}. Value passed : ${value}`\n );\n }\n}\n\n/**\n * Update function for the [`setItemAsync()`](#setitemasynckey-value) or [`setItemSync()`](#setitemsynckey-value) method. It computes the new value based on the previous value. The function returns the new value to set for the key.\n * @param prevValue The previous value associated with the key, or `null` if the key was not set.\n * @returns The new value to set for the key.\n */\nexport type SQLiteStorageSetItemUpdateFunction = (prevValue: string | null) => string;\n\nconst DATABASE_VERSION = 1;\nconst STATEMENT_GET = 'SELECT value FROM storage WHERE key = ?;';\nconst STATEMENT_SET =\n 'INSERT INTO storage (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value;';\nconst STATEMENT_REMOVE = 'DELETE FROM storage WHERE key = ?;';\nconst STATEMENT_GET_ALL_KEYS = 'SELECT key FROM storage;';\nconst STATEMENT_CLEAR = 'DELETE FROM storage;';\n\nconst MIGRATION_STATEMENT_0 =\n 'CREATE TABLE IF NOT EXISTS storage (key TEXT PRIMARY KEY NOT NULL, value TEXT);';\n\n/**\n * Key-value store backed by SQLite. This class accepts a `databaseName` parameter in its constructor, which is the name of the database file to use for the storage.\n */\nexport class SQLiteStorage {\n private db: SQLiteDatabase | null = null;\n\n constructor(private readonly databaseName: string) {}\n\n //#region Asynchronous API\n\n /**\n * Retrieves the value associated with the given key asynchronously.\n */\n async getItemAsync(key: string): Promise<string | null> {\n checkValidInput(key);\n const db = this.getDbSync();\n const result = await db.getFirstAsync<{ value: string }>(STATEMENT_GET, key);\n return result?.value ?? null;\n }\n\n /**\n * Sets the value for the given key asynchronously.\n * If a function is provided, it computes the new value based on the previous value.\n */\n async setItemAsync(\n key: string,\n value: string | SQLiteStorageSetItemUpdateFunction\n ): Promise<void> {\n checkValidInput(key, value);\n const db = this.getDbSync();\n\n if (typeof value === 'function') {\n await db.withExclusiveTransactionAsync(async (tx) => {\n const prevResult = await tx.getFirstAsync<{ value: string }>(STATEMENT_GET, key);\n const prevValue = prevResult?.value ?? null;\n const nextValue = value(prevValue);\n checkValidInput(key, nextValue);\n await tx.runAsync(STATEMENT_SET, key, nextValue);\n });\n return;\n }\n\n await db.runAsync(STATEMENT_SET, key, value);\n }\n\n /**\n * Removes the value associated with the given key asynchronously.\n */\n async removeItemAsync(key: string): Promise<boolean> {\n checkValidInput(key);\n const db = this.getDbSync();\n const result = await db.runAsync(STATEMENT_REMOVE, key);\n return result.changes > 0;\n }\n\n /**\n * Retrieves all keys stored in the storage asynchronously.\n */\n async getAllKeysAsync(): Promise<string[]> {\n const db = this.getDbSync();\n const result = await db.getAllAsync<{ key: string }>(STATEMENT_GET_ALL_KEYS);\n return result.map(({ key }) => key);\n }\n\n /**\n * Clears all key-value pairs from the storage asynchronously.\n */\n async clearAsync(): Promise<boolean> {\n const db = this.getDbSync();\n const result = await db.runAsync(STATEMENT_CLEAR);\n return result.changes > 0;\n }\n\n /**\n * Closes the database connection asynchronously.\n */\n async closeAsync(): Promise<void> {\n if (this.db) {\n await this.db.closeAsync();\n this.db = null;\n }\n }\n\n //#endregion\n\n //#region Synchronous API\n\n /**\n * Retrieves the value associated with the given key synchronously.\n */\n getItemSync(key: string): string | null {\n checkValidInput(key);\n const db = this.getDbSync();\n const result = db.getFirstSync<{ value: string }>(STATEMENT_GET, key);\n return result?.value ?? null;\n }\n\n /**\n * Sets the value for the given key synchronously.\n * If a function is provided, it computes the new value based on the previous value.\n */\n setItemSync(key: string, value: string | SQLiteStorageSetItemUpdateFunction): void {\n checkValidInput(key, value);\n const db = this.getDbSync();\n\n if (typeof value === 'function') {\n db.withTransactionSync(() => {\n const prevResult = db.getFirstSync<{ value: string }>(STATEMENT_GET, key);\n const prevValue = prevResult?.value ?? null;\n const nextValue = value(prevValue);\n checkValidInput(key, nextValue);\n db.runSync(STATEMENT_SET, key, nextValue);\n });\n return;\n }\n\n db.runSync(STATEMENT_SET, key, value);\n }\n\n /**\n * Removes the value associated with the given key synchronously.\n */\n removeItemSync(key: string): boolean {\n checkValidInput(key);\n const db = this.getDbSync();\n const result = db.runSync(STATEMENT_REMOVE, key);\n return result.changes > 0;\n }\n\n /**\n * Retrieves all keys stored in the storage synchronously.\n */\n getAllKeysSync(): string[] {\n const db = this.getDbSync();\n const result = db.getAllSync<{ key: string }>(STATEMENT_GET_ALL_KEYS);\n return result.map(({ key }) => key);\n }\n\n /**\n * Clears all key-value pairs from the storage synchronously.\n */\n clearSync(): boolean {\n const db = this.getDbSync();\n const result = db.runSync(STATEMENT_CLEAR);\n return result.changes > 0;\n }\n\n /**\n * Closes the database connection synchronously.\n */\n closeSync(): void {\n if (this.db) {\n this.db.closeSync();\n this.db = null;\n }\n }\n\n //#endregion\n\n //#region react-native-async-storage compatible API\n\n /**\n * Alias for [`getItemAsync()`](#getitemasynckey) method.\n */\n async getItem(key: string): Promise<string | null> {\n return this.getItemAsync(key);\n }\n\n /**\n * Alias for [`setItemAsync()`](#setitemasynckey-value).\n */\n async setItem(key: string, value: string | SQLiteStorageSetItemUpdateFunction): Promise<void> {\n await this.setItemAsync(key, value);\n }\n\n /**\n * Alias for [`removeItemAsync()`](#removeitemasynckey) method.\n */\n async removeItem(key: string): Promise<void> {\n await this.removeItemAsync(key);\n }\n\n /**\n * Alias for [`getAllKeysAsync()`](#getallkeysasync) method.\n */\n async getAllKeys(): Promise<string[]> {\n return this.getAllKeysAsync();\n }\n\n /**\n * Alias for [`clearAsync()`](#clearasync) method.\n */\n async clear(): Promise<void> {\n await this.clearAsync();\n }\n\n /**\n * Merges the given value with the existing value for the given key asynchronously.\n * If the existing value is a JSON object, performs a deep merge.\n */\n async mergeItem(key: string, value: string): Promise<void> {\n checkValidInput(key, value);\n await this.setItemAsync(key, (prevValue) => {\n if (prevValue == null) {\n return value;\n }\n const prevJSON = JSON.parse(prevValue);\n const newJSON = JSON.parse(value);\n const mergedJSON = SQLiteStorage.mergeDeep(prevJSON, newJSON);\n return JSON.stringify(mergedJSON);\n });\n }\n\n /**\n * Retrieves the values associated with the given keys asynchronously.\n */\n async multiGet(keys: string[]): Promise<[string, string | null][]> {\n return Promise.all(\n keys.map(async (key): Promise<[string, string | null]> => {\n checkValidInput(key);\n return [key, await this.getItemAsync(key)];\n })\n );\n }\n\n /**\n * Sets multiple key-value pairs asynchronously.\n */\n async multiSet(keyValuePairs: [string, string][]): Promise<void> {\n const db = this.getDbSync();\n await db.withExclusiveTransactionAsync(async (tx) => {\n for (const [key, value] of keyValuePairs) {\n checkValidInput(key, value);\n await tx.runAsync(STATEMENT_SET, key, value);\n }\n });\n }\n\n /**\n * Removes the values associated with the given keys asynchronously.\n */\n async multiRemove(keys: string[]): Promise<void> {\n const db = this.getDbSync();\n await db.withExclusiveTransactionAsync(async (tx) => {\n for (const key of keys) {\n checkValidInput(key);\n await tx.runAsync(STATEMENT_REMOVE, key);\n }\n });\n }\n\n /**\n * Merges multiple key-value pairs asynchronously.\n * If existing values are JSON objects, performs a deep merge.\n */\n async multiMerge(keyValuePairs: [string, string][]): Promise<void> {\n const db = this.getDbSync();\n await db.withExclusiveTransactionAsync(async (tx) => {\n for (const [key, value] of keyValuePairs) {\n checkValidInput(key, value);\n const prevValue = await tx.getFirstAsync<{ value: string }>(STATEMENT_GET, key);\n if (prevValue == null) {\n await tx.runAsync(STATEMENT_SET, key, value);\n continue;\n }\n const prevJSON = JSON.parse(prevValue.value);\n const newJSON = JSON.parse(value);\n const mergedJSON = SQLiteStorage.mergeDeep(prevJSON, newJSON);\n await tx.runAsync(STATEMENT_SET, key, JSON.stringify(mergedJSON));\n }\n });\n }\n\n /**\n * Alias for [`closeAsync()`](#closeasync-1) method.\n */\n async close(): Promise<void> {\n await this.closeAsync();\n }\n\n //#endregion\n\n //#region Internals\n\n private getDbSync(): SQLiteDatabase {\n if (!this.db) {\n const db = openDatabaseSync(this.databaseName);\n this.maybeMigrateDbSync(db);\n this.db = db;\n }\n return this.db;\n }\n\n private maybeMigrateDbSync(db: SQLiteDatabase) {\n db.withTransactionSync(() => {\n const result = db.getFirstSync<{ user_version: number }>('PRAGMA user_version');\n let currentDbVersion = result?.user_version ?? 0;\n if (currentDbVersion >= DATABASE_VERSION) {\n return;\n }\n if (currentDbVersion === 0) {\n db.execSync(MIGRATION_STATEMENT_0);\n currentDbVersion = 1;\n }\n db.execSync(`PRAGMA user_version = ${DATABASE_VERSION}`);\n });\n }\n\n /**\n * Recursively merge two JSON objects.\n */\n private static mergeDeep(target: any, source: any): any {\n if (typeof target !== 'object' || target === null) {\n return source;\n }\n\n if (typeof source !== 'object' || source === null) {\n return target;\n }\n\n const output = { ...target };\n\n for (const key of Object.keys(source)) {\n if (source[key] instanceof Array) {\n if (!output[key]) {\n output[key] = [];\n }\n output[key] = output[key].concat(source[key]);\n } else if (typeof source[key] === 'object') {\n output[key] = this.mergeDeep(target[key], source[key]);\n } else {\n output[key] = source[key];\n }\n }\n\n return output;\n }\n\n //#endregion\n}\n\n/**\n * This default instance of the [`SQLiteStorage`](#sqlitestorage-1) class is used as a drop-in replacement for the `AsyncStorage` module from [`@react-native-async-storage/async-storage`](https://github.com/react-native-async-storage/async-storage).\n */\nexport const AsyncStorage = new SQLiteStorage('ExpoSQLiteStorage');\n\nexport default AsyncStorage;\n\n/**\n * Alias for [`AsyncStorage`](#sqliteasyncstorage), given the storage not only offers asynchronous methods.\n */\nexport const Storage = AsyncStorage;\n"]}
1
+ {"version":3,"file":"Storage.js","sourceRoot":"","sources":["../src/Storage.ts"],"names":[],"mappings":"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","sourcesContent":["import AwaitLock from 'await-lock';\n\nimport { openDatabaseAsync, openDatabaseSync, type SQLiteDatabase } from './index';\n\n/**\n * Update function for the [`setItemAsync()`](#setitemasynckey-value) or [`setItemSync()`](#setitemsynckey-value) method. It computes the new value based on the previous value. The function returns the new value to set for the key.\n * @param prevValue The previous value associated with the key, or `null` if the key was not set.\n * @returns The new value to set for the key.\n */\nexport type SQLiteStorageSetItemUpdateFunction = (prevValue: string | null) => string;\n\nconst DATABASE_VERSION = 1;\nconst STATEMENT_GET = 'SELECT value FROM storage WHERE key = ?;';\nconst STATEMENT_SET =\n 'INSERT INTO storage (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value;';\nconst STATEMENT_REMOVE = 'DELETE FROM storage WHERE key = ?;';\nconst STATEMENT_GET_ALL_KEYS = 'SELECT key FROM storage;';\nconst STATEMENT_CLEAR = 'DELETE FROM storage;';\n\nconst MIGRATION_STATEMENT_0 =\n 'CREATE TABLE IF NOT EXISTS storage (key TEXT PRIMARY KEY NOT NULL, value TEXT);';\n\n/**\n * Key-value store backed by SQLite. This class accepts a `databaseName` parameter in its constructor, which is the name of the database file to use for the storage.\n */\nexport class SQLiteStorage {\n private db: SQLiteDatabase | null = null;\n private readonly awaitLock = new AwaitLock();\n\n constructor(private readonly databaseName: string) {}\n\n //#region Asynchronous API\n\n /**\n * Retrieves the value associated with the given key asynchronously.\n */\n async getItemAsync(key: string): Promise<string | null> {\n this.checkValidInput(key);\n const db = await this.getDbAsync();\n const result = await db.getFirstAsync<{ value: string }>(STATEMENT_GET, key);\n return result?.value ?? null;\n }\n\n /**\n * Sets the value for the given key asynchronously.\n * If a function is provided, it computes the new value based on the previous value.\n */\n async setItemAsync(\n key: string,\n value: string | SQLiteStorageSetItemUpdateFunction\n ): Promise<void> {\n this.checkValidInput(key, value);\n const db = await this.getDbAsync();\n\n if (typeof value === 'function') {\n await db.withExclusiveTransactionAsync(async (tx) => {\n const prevResult = await tx.getFirstAsync<{ value: string }>(STATEMENT_GET, key);\n const prevValue = prevResult?.value ?? null;\n const nextValue = value(prevValue);\n this.checkValidInput(key, nextValue);\n await tx.runAsync(STATEMENT_SET, key, nextValue);\n });\n return;\n }\n\n await db.runAsync(STATEMENT_SET, key, value);\n }\n\n /**\n * Removes the value associated with the given key asynchronously.\n */\n async removeItemAsync(key: string): Promise<boolean> {\n this.checkValidInput(key);\n const db = await this.getDbAsync();\n const result = await db.runAsync(STATEMENT_REMOVE, key);\n return result.changes > 0;\n }\n\n /**\n * Retrieves all keys stored in the storage asynchronously.\n */\n async getAllKeysAsync(): Promise<string[]> {\n const db = await this.getDbAsync();\n const result = await db.getAllAsync<{ key: string }>(STATEMENT_GET_ALL_KEYS);\n return result.map(({ key }) => key);\n }\n\n /**\n * Clears all key-value pairs from the storage asynchronously.\n */\n async clearAsync(): Promise<boolean> {\n const db = await this.getDbAsync();\n const result = await db.runAsync(STATEMENT_CLEAR);\n return result.changes > 0;\n }\n\n /**\n * Closes the database connection asynchronously.\n */\n async closeAsync(): Promise<void> {\n await this.awaitLock.acquireAsync();\n try {\n if (this.db) {\n await this.db.closeAsync();\n this.db = null;\n }\n } finally {\n this.awaitLock.release();\n }\n }\n\n //#endregion\n\n //#region Synchronous API\n\n /**\n * Retrieves the value associated with the given key synchronously.\n */\n getItemSync(key: string): string | null {\n this.checkValidInput(key);\n const db = this.getDbSync();\n const result = db.getFirstSync<{ value: string }>(STATEMENT_GET, key);\n return result?.value ?? null;\n }\n\n /**\n * Sets the value for the given key synchronously.\n * If a function is provided, it computes the new value based on the previous value.\n */\n setItemSync(key: string, value: string | SQLiteStorageSetItemUpdateFunction): void {\n this.checkValidInput(key, value);\n const db = this.getDbSync();\n\n if (typeof value === 'function') {\n db.withTransactionSync(() => {\n const prevResult = db.getFirstSync<{ value: string }>(STATEMENT_GET, key);\n const prevValue = prevResult?.value ?? null;\n const nextValue = value(prevValue);\n this.checkValidInput(key, nextValue);\n db.runSync(STATEMENT_SET, key, nextValue);\n });\n return;\n }\n\n db.runSync(STATEMENT_SET, key, value);\n }\n\n /**\n * Removes the value associated with the given key synchronously.\n */\n removeItemSync(key: string): boolean {\n this.checkValidInput(key);\n const db = this.getDbSync();\n const result = db.runSync(STATEMENT_REMOVE, key);\n return result.changes > 0;\n }\n\n /**\n * Retrieves all keys stored in the storage synchronously.\n */\n getAllKeysSync(): string[] {\n const db = this.getDbSync();\n const result = db.getAllSync<{ key: string }>(STATEMENT_GET_ALL_KEYS);\n return result.map(({ key }) => key);\n }\n\n /**\n * Clears all key-value pairs from the storage synchronously.\n */\n clearSync(): boolean {\n const db = this.getDbSync();\n const result = db.runSync(STATEMENT_CLEAR);\n return result.changes > 0;\n }\n\n /**\n * Closes the database connection synchronously.\n */\n closeSync(): void {\n if (this.db) {\n this.db.closeSync();\n this.db = null;\n }\n }\n\n //#endregion\n\n //#region react-native-async-storage compatible API\n\n /**\n * Alias for [`getItemAsync()`](#getitemasynckey) method.\n */\n async getItem(key: string): Promise<string | null> {\n return this.getItemAsync(key);\n }\n\n /**\n * Alias for [`setItemAsync()`](#setitemasynckey-value).\n */\n async setItem(key: string, value: string | SQLiteStorageSetItemUpdateFunction): Promise<void> {\n await this.setItemAsync(key, value);\n }\n\n /**\n * Alias for [`removeItemAsync()`](#removeitemasynckey) method.\n */\n async removeItem(key: string): Promise<void> {\n await this.removeItemAsync(key);\n }\n\n /**\n * Alias for [`getAllKeysAsync()`](#getallkeysasync) method.\n */\n async getAllKeys(): Promise<string[]> {\n return this.getAllKeysAsync();\n }\n\n /**\n * Alias for [`clearAsync()`](#clearasync) method.\n */\n async clear(): Promise<void> {\n await this.clearAsync();\n }\n\n /**\n * Merges the given value with the existing value for the given key asynchronously.\n * If the existing value is a JSON object, performs a deep merge.\n */\n async mergeItem(key: string, value: string): Promise<void> {\n this.checkValidInput(key, value);\n await this.setItemAsync(key, (prevValue) => {\n if (prevValue == null) {\n return value;\n }\n const prevJSON = JSON.parse(prevValue);\n const newJSON = JSON.parse(value);\n const mergedJSON = SQLiteStorage.mergeDeep(prevJSON, newJSON);\n return JSON.stringify(mergedJSON);\n });\n }\n\n /**\n * Retrieves the values associated with the given keys asynchronously.\n */\n async multiGet(keys: string[]): Promise<[string, string | null][]> {\n return Promise.all(\n keys.map(async (key): Promise<[string, string | null]> => {\n this.checkValidInput(key);\n return [key, await this.getItemAsync(key)];\n })\n );\n }\n\n /**\n * Sets multiple key-value pairs asynchronously.\n */\n async multiSet(keyValuePairs: [string, string][]): Promise<void> {\n const db = await this.getDbAsync();\n await db.withExclusiveTransactionAsync(async (tx) => {\n for (const [key, value] of keyValuePairs) {\n this.checkValidInput(key, value);\n await tx.runAsync(STATEMENT_SET, key, value);\n }\n });\n }\n\n /**\n * Removes the values associated with the given keys asynchronously.\n */\n async multiRemove(keys: string[]): Promise<void> {\n const db = await this.getDbAsync();\n await db.withExclusiveTransactionAsync(async (tx) => {\n for (const key of keys) {\n this.checkValidInput(key);\n await tx.runAsync(STATEMENT_REMOVE, key);\n }\n });\n }\n\n /**\n * Merges multiple key-value pairs asynchronously.\n * If existing values are JSON objects, performs a deep merge.\n */\n async multiMerge(keyValuePairs: [string, string][]): Promise<void> {\n const db = await this.getDbAsync();\n await db.withExclusiveTransactionAsync(async (tx) => {\n for (const [key, value] of keyValuePairs) {\n this.checkValidInput(key, value);\n const prevValue = await tx.getFirstAsync<{ value: string }>(STATEMENT_GET, key);\n if (prevValue == null) {\n await tx.runAsync(STATEMENT_SET, key, value);\n continue;\n }\n const prevJSON = JSON.parse(prevValue.value);\n const newJSON = JSON.parse(value);\n const mergedJSON = SQLiteStorage.mergeDeep(prevJSON, newJSON);\n await tx.runAsync(STATEMENT_SET, key, JSON.stringify(mergedJSON));\n }\n });\n }\n\n /**\n * Alias for [`closeAsync()`](#closeasync-1) method.\n */\n async close(): Promise<void> {\n await this.closeAsync();\n }\n\n //#endregion\n\n //#region Internals\n\n private async getDbAsync(): Promise<SQLiteDatabase> {\n await this.awaitLock.acquireAsync();\n try {\n if (!this.db) {\n const db = await openDatabaseAsync(this.databaseName);\n await this.maybeMigrateDbAsync(db);\n this.db = db;\n }\n } finally {\n this.awaitLock.release();\n }\n return this.db;\n }\n\n private getDbSync(): SQLiteDatabase {\n if (!this.db) {\n const db = openDatabaseSync(this.databaseName);\n this.maybeMigrateDbSync(db);\n this.db = db;\n }\n return this.db;\n }\n\n private maybeMigrateDbAsync(db: SQLiteDatabase) {\n return db.withTransactionAsync(async () => {\n const result = await db.getFirstAsync<{ user_version: number }>('PRAGMA user_version');\n let currentDbVersion = result?.user_version ?? 0;\n if (currentDbVersion >= DATABASE_VERSION) {\n return;\n }\n if (currentDbVersion === 0) {\n await db.execAsync(MIGRATION_STATEMENT_0);\n currentDbVersion = 1;\n }\n await db.execAsync(`PRAGMA user_version = ${DATABASE_VERSION}`);\n });\n }\n\n private maybeMigrateDbSync(db: SQLiteDatabase) {\n db.withTransactionSync(() => {\n const result = db.getFirstSync<{ user_version: number }>('PRAGMA user_version');\n let currentDbVersion = result?.user_version ?? 0;\n if (currentDbVersion >= DATABASE_VERSION) {\n return;\n }\n if (currentDbVersion === 0) {\n db.execSync(MIGRATION_STATEMENT_0);\n currentDbVersion = 1;\n }\n db.execSync(`PRAGMA user_version = ${DATABASE_VERSION}`);\n });\n }\n\n /**\n * Recursively merge two JSON objects.\n */\n private static mergeDeep(target: any, source: any): any {\n if (typeof target !== 'object' || target === null) {\n return source;\n }\n\n if (typeof source !== 'object' || source === null) {\n return target;\n }\n\n const output = { ...target };\n\n for (const key of Object.keys(source)) {\n if (source[key] instanceof Array) {\n if (!output[key]) {\n output[key] = [];\n }\n output[key] = output[key].concat(source[key]);\n } else if (typeof source[key] === 'object') {\n output[key] = this.mergeDeep(target[key], source[key]);\n } else {\n output[key] = source[key];\n }\n }\n\n return output;\n }\n\n private checkValidInput(...input: unknown[]) {\n const [key, value] = input;\n\n if (typeof key !== 'string') {\n throw new Error(\n `[SQLiteStorage] Using ${typeof key} type for key is not supported. Use string instead. Key passed: ${key}`\n );\n }\n\n if (input.length > 1 && typeof value !== 'string' && typeof value !== 'function') {\n throw new Error(\n `[SQLiteStorage] Using ${typeof value} type for value is not supported. Use string instead. Key passed: ${key}. Value passed : ${value}`\n );\n }\n }\n\n //#endregion\n}\n\n/**\n * This default instance of the [`SQLiteStorage`](#sqlitestorage-1) class is used as a drop-in replacement for the `AsyncStorage` module from [`@react-native-async-storage/async-storage`](https://github.com/react-native-async-storage/async-storage).\n */\nexport const AsyncStorage = new SQLiteStorage('ExpoSQLiteStorage');\n\nexport default AsyncStorage;\n\n/**\n * Alias for [`AsyncStorage`](#sqliteasyncstorage), given the storage not only offers asynchronous methods.\n */\nexport const Storage = AsyncStorage;\n"]}
@@ -5,12 +5,6 @@
5
5
  },
6
6
  "android": {
7
7
  "modules": ["expo.modules.sqlite.SQLiteModule"],
8
- "shouldUsePublicationScriptPath": "android/shouldUsePublication.groovy",
9
- "publication": {
10
- "groupId": "host.exp.exponent",
11
- "artifactId": "expo.modules.sqlite",
12
- "version": "15.2.8",
13
- "repository": "local-maven-repo"
14
- }
8
+ "shouldUsePublicationScriptPath": "android/shouldUsePublication.groovy"
15
9
  }
16
10
  }
@@ -6,6 +6,7 @@ final class NativeStatement: SharedObject, Equatable {
6
6
  var pointer: OpaquePointer?
7
7
  var isFinalized = false
8
8
  var extraPointer: OpaquePointer?
9
+ internal let lock = DispatchSemaphore(value: 1)
9
10
 
10
11
  // MARK: - Equatable
11
12
 
@@ -371,6 +371,13 @@ public final class SQLiteModule: Module {
371
371
  try maybeThrowForClosedDatabase(database)
372
372
  try maybeThrowForFinalizedStatement(statement)
373
373
 
374
+ // The statement with parameter bindings is stateful,
375
+ // we have to guard with a critical section for thread safety.
376
+ statement.lock.wait()
377
+ defer {
378
+ statement.lock.signal()
379
+ }
380
+
374
381
  exsqlite3_reset(statement.pointer)
375
382
  exsqlite3_clear_bindings(statement.pointer)
376
383
  for (key, param) in bindParams {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-sqlite",
3
- "version": "15.2.8",
3
+ "version": "15.2.10",
4
4
  "description": "Provides access to a database using SQLite (https://www.sqlite.org/). The database is persisted across restarts of your app.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -48,12 +48,14 @@
48
48
  "jest": {
49
49
  "preset": "expo-module-scripts"
50
50
  },
51
- "dependencies": {},
51
+ "dependencies": {
52
+ "await-lock": "^2.2.2"
53
+ },
52
54
  "devDependencies": {
53
55
  "@testing-library/react-native": "^13.1.0",
54
56
  "@types/better-sqlite3": "^7.6.6",
55
57
  "better-sqlite3": "^11.6.0",
56
- "expo-module-scripts": "^4.1.5",
58
+ "expo-module-scripts": "^4.1.7",
57
59
  "react-error-boundary": "^4.0.11"
58
60
  },
59
61
  "peerDependencies": {
@@ -61,5 +63,5 @@
61
63
  "react": "*",
62
64
  "react-native": "*"
63
65
  },
64
- "gitHead": "bb2cf89d99a9d7f70b07419cc36cdf80c2764217"
66
+ "gitHead": "49c9d53cf0a9fc8179d1c8f5268beadd141f70ca"
65
67
  }
package/src/Storage.ts CHANGED
@@ -1,23 +1,6 @@
1
- import { openDatabaseSync, type SQLiteDatabase } from './index';
1
+ import AwaitLock from 'await-lock';
2
2
 
3
- /**
4
- * @hidden
5
- */
6
- export function checkValidInput(...input: unknown[]) {
7
- const [key, value] = input;
8
-
9
- if (typeof key !== 'string') {
10
- throw new Error(
11
- `[SQLiteStorage] Using ${typeof key} type for key is not supported. Use string instead. Key passed: ${key}`
12
- );
13
- }
14
-
15
- if (input.length > 1 && typeof value !== 'string' && typeof value !== 'function') {
16
- throw new Error(
17
- `[SQLiteStorage] Using ${typeof value} type for value is not supported. Use string instead. Key passed: ${key}. Value passed : ${value}`
18
- );
19
- }
20
- }
3
+ import { openDatabaseAsync, openDatabaseSync, type SQLiteDatabase } from './index';
21
4
 
22
5
  /**
23
6
  * Update function for the [`setItemAsync()`](#setitemasynckey-value) or [`setItemSync()`](#setitemsynckey-value) method. It computes the new value based on the previous value. The function returns the new value to set for the key.
@@ -42,6 +25,7 @@ const MIGRATION_STATEMENT_0 =
42
25
  */
43
26
  export class SQLiteStorage {
44
27
  private db: SQLiteDatabase | null = null;
28
+ private readonly awaitLock = new AwaitLock();
45
29
 
46
30
  constructor(private readonly databaseName: string) {}
47
31
 
@@ -51,8 +35,8 @@ export class SQLiteStorage {
51
35
  * Retrieves the value associated with the given key asynchronously.
52
36
  */
53
37
  async getItemAsync(key: string): Promise<string | null> {
54
- checkValidInput(key);
55
- const db = this.getDbSync();
38
+ this.checkValidInput(key);
39
+ const db = await this.getDbAsync();
56
40
  const result = await db.getFirstAsync<{ value: string }>(STATEMENT_GET, key);
57
41
  return result?.value ?? null;
58
42
  }
@@ -65,15 +49,15 @@ export class SQLiteStorage {
65
49
  key: string,
66
50
  value: string | SQLiteStorageSetItemUpdateFunction
67
51
  ): Promise<void> {
68
- checkValidInput(key, value);
69
- const db = this.getDbSync();
52
+ this.checkValidInput(key, value);
53
+ const db = await this.getDbAsync();
70
54
 
71
55
  if (typeof value === 'function') {
72
56
  await db.withExclusiveTransactionAsync(async (tx) => {
73
57
  const prevResult = await tx.getFirstAsync<{ value: string }>(STATEMENT_GET, key);
74
58
  const prevValue = prevResult?.value ?? null;
75
59
  const nextValue = value(prevValue);
76
- checkValidInput(key, nextValue);
60
+ this.checkValidInput(key, nextValue);
77
61
  await tx.runAsync(STATEMENT_SET, key, nextValue);
78
62
  });
79
63
  return;
@@ -86,8 +70,8 @@ export class SQLiteStorage {
86
70
  * Removes the value associated with the given key asynchronously.
87
71
  */
88
72
  async removeItemAsync(key: string): Promise<boolean> {
89
- checkValidInput(key);
90
- const db = this.getDbSync();
73
+ this.checkValidInput(key);
74
+ const db = await this.getDbAsync();
91
75
  const result = await db.runAsync(STATEMENT_REMOVE, key);
92
76
  return result.changes > 0;
93
77
  }
@@ -96,7 +80,7 @@ export class SQLiteStorage {
96
80
  * Retrieves all keys stored in the storage asynchronously.
97
81
  */
98
82
  async getAllKeysAsync(): Promise<string[]> {
99
- const db = this.getDbSync();
83
+ const db = await this.getDbAsync();
100
84
  const result = await db.getAllAsync<{ key: string }>(STATEMENT_GET_ALL_KEYS);
101
85
  return result.map(({ key }) => key);
102
86
  }
@@ -105,7 +89,7 @@ export class SQLiteStorage {
105
89
  * Clears all key-value pairs from the storage asynchronously.
106
90
  */
107
91
  async clearAsync(): Promise<boolean> {
108
- const db = this.getDbSync();
92
+ const db = await this.getDbAsync();
109
93
  const result = await db.runAsync(STATEMENT_CLEAR);
110
94
  return result.changes > 0;
111
95
  }
@@ -114,9 +98,14 @@ export class SQLiteStorage {
114
98
  * Closes the database connection asynchronously.
115
99
  */
116
100
  async closeAsync(): Promise<void> {
117
- if (this.db) {
118
- await this.db.closeAsync();
119
- this.db = null;
101
+ await this.awaitLock.acquireAsync();
102
+ try {
103
+ if (this.db) {
104
+ await this.db.closeAsync();
105
+ this.db = null;
106
+ }
107
+ } finally {
108
+ this.awaitLock.release();
120
109
  }
121
110
  }
122
111
 
@@ -128,7 +117,7 @@ export class SQLiteStorage {
128
117
  * Retrieves the value associated with the given key synchronously.
129
118
  */
130
119
  getItemSync(key: string): string | null {
131
- checkValidInput(key);
120
+ this.checkValidInput(key);
132
121
  const db = this.getDbSync();
133
122
  const result = db.getFirstSync<{ value: string }>(STATEMENT_GET, key);
134
123
  return result?.value ?? null;
@@ -139,7 +128,7 @@ export class SQLiteStorage {
139
128
  * If a function is provided, it computes the new value based on the previous value.
140
129
  */
141
130
  setItemSync(key: string, value: string | SQLiteStorageSetItemUpdateFunction): void {
142
- checkValidInput(key, value);
131
+ this.checkValidInput(key, value);
143
132
  const db = this.getDbSync();
144
133
 
145
134
  if (typeof value === 'function') {
@@ -147,7 +136,7 @@ export class SQLiteStorage {
147
136
  const prevResult = db.getFirstSync<{ value: string }>(STATEMENT_GET, key);
148
137
  const prevValue = prevResult?.value ?? null;
149
138
  const nextValue = value(prevValue);
150
- checkValidInput(key, nextValue);
139
+ this.checkValidInput(key, nextValue);
151
140
  db.runSync(STATEMENT_SET, key, nextValue);
152
141
  });
153
142
  return;
@@ -160,7 +149,7 @@ export class SQLiteStorage {
160
149
  * Removes the value associated with the given key synchronously.
161
150
  */
162
151
  removeItemSync(key: string): boolean {
163
- checkValidInput(key);
152
+ this.checkValidInput(key);
164
153
  const db = this.getDbSync();
165
154
  const result = db.runSync(STATEMENT_REMOVE, key);
166
155
  return result.changes > 0;
@@ -238,7 +227,7 @@ export class SQLiteStorage {
238
227
  * If the existing value is a JSON object, performs a deep merge.
239
228
  */
240
229
  async mergeItem(key: string, value: string): Promise<void> {
241
- checkValidInput(key, value);
230
+ this.checkValidInput(key, value);
242
231
  await this.setItemAsync(key, (prevValue) => {
243
232
  if (prevValue == null) {
244
233
  return value;
@@ -256,7 +245,7 @@ export class SQLiteStorage {
256
245
  async multiGet(keys: string[]): Promise<[string, string | null][]> {
257
246
  return Promise.all(
258
247
  keys.map(async (key): Promise<[string, string | null]> => {
259
- checkValidInput(key);
248
+ this.checkValidInput(key);
260
249
  return [key, await this.getItemAsync(key)];
261
250
  })
262
251
  );
@@ -266,10 +255,10 @@ export class SQLiteStorage {
266
255
  * Sets multiple key-value pairs asynchronously.
267
256
  */
268
257
  async multiSet(keyValuePairs: [string, string][]): Promise<void> {
269
- const db = this.getDbSync();
258
+ const db = await this.getDbAsync();
270
259
  await db.withExclusiveTransactionAsync(async (tx) => {
271
260
  for (const [key, value] of keyValuePairs) {
272
- checkValidInput(key, value);
261
+ this.checkValidInput(key, value);
273
262
  await tx.runAsync(STATEMENT_SET, key, value);
274
263
  }
275
264
  });
@@ -279,10 +268,10 @@ export class SQLiteStorage {
279
268
  * Removes the values associated with the given keys asynchronously.
280
269
  */
281
270
  async multiRemove(keys: string[]): Promise<void> {
282
- const db = this.getDbSync();
271
+ const db = await this.getDbAsync();
283
272
  await db.withExclusiveTransactionAsync(async (tx) => {
284
273
  for (const key of keys) {
285
- checkValidInput(key);
274
+ this.checkValidInput(key);
286
275
  await tx.runAsync(STATEMENT_REMOVE, key);
287
276
  }
288
277
  });
@@ -293,10 +282,10 @@ export class SQLiteStorage {
293
282
  * If existing values are JSON objects, performs a deep merge.
294
283
  */
295
284
  async multiMerge(keyValuePairs: [string, string][]): Promise<void> {
296
- const db = this.getDbSync();
285
+ const db = await this.getDbAsync();
297
286
  await db.withExclusiveTransactionAsync(async (tx) => {
298
287
  for (const [key, value] of keyValuePairs) {
299
- checkValidInput(key, value);
288
+ this.checkValidInput(key, value);
300
289
  const prevValue = await tx.getFirstAsync<{ value: string }>(STATEMENT_GET, key);
301
290
  if (prevValue == null) {
302
291
  await tx.runAsync(STATEMENT_SET, key, value);
@@ -321,6 +310,20 @@ export class SQLiteStorage {
321
310
 
322
311
  //#region Internals
323
312
 
313
+ private async getDbAsync(): Promise<SQLiteDatabase> {
314
+ await this.awaitLock.acquireAsync();
315
+ try {
316
+ if (!this.db) {
317
+ const db = await openDatabaseAsync(this.databaseName);
318
+ await this.maybeMigrateDbAsync(db);
319
+ this.db = db;
320
+ }
321
+ } finally {
322
+ this.awaitLock.release();
323
+ }
324
+ return this.db;
325
+ }
326
+
324
327
  private getDbSync(): SQLiteDatabase {
325
328
  if (!this.db) {
326
329
  const db = openDatabaseSync(this.databaseName);
@@ -330,6 +333,21 @@ export class SQLiteStorage {
330
333
  return this.db;
331
334
  }
332
335
 
336
+ private maybeMigrateDbAsync(db: SQLiteDatabase) {
337
+ return db.withTransactionAsync(async () => {
338
+ const result = await db.getFirstAsync<{ user_version: number }>('PRAGMA user_version');
339
+ let currentDbVersion = result?.user_version ?? 0;
340
+ if (currentDbVersion >= DATABASE_VERSION) {
341
+ return;
342
+ }
343
+ if (currentDbVersion === 0) {
344
+ await db.execAsync(MIGRATION_STATEMENT_0);
345
+ currentDbVersion = 1;
346
+ }
347
+ await db.execAsync(`PRAGMA user_version = ${DATABASE_VERSION}`);
348
+ });
349
+ }
350
+
333
351
  private maybeMigrateDbSync(db: SQLiteDatabase) {
334
352
  db.withTransactionSync(() => {
335
353
  const result = db.getFirstSync<{ user_version: number }>('PRAGMA user_version');
@@ -375,6 +393,22 @@ export class SQLiteStorage {
375
393
  return output;
376
394
  }
377
395
 
396
+ private checkValidInput(...input: unknown[]) {
397
+ const [key, value] = input;
398
+
399
+ if (typeof key !== 'string') {
400
+ throw new Error(
401
+ `[SQLiteStorage] Using ${typeof key} type for key is not supported. Use string instead. Key passed: ${key}`
402
+ );
403
+ }
404
+
405
+ if (input.length > 1 && typeof value !== 'string' && typeof value !== 'function') {
406
+ throw new Error(
407
+ `[SQLiteStorage] Using ${typeof value} type for value is not supported. Use string instead. Key passed: ${key}. Value passed : ${value}`
408
+ );
409
+ }
410
+ }
411
+
378
412
  //#endregion
379
413
  }
380
414
 
@@ -37,7 +37,7 @@ export function sendWorkerResult({
37
37
  const { lockBuffer, resultBuffer } = syncTrait;
38
38
  const lock = new Int32Array(lockBuffer);
39
39
  const resultArray = new Uint8Array(resultBuffer);
40
- const resultJson = result ? serialize({ result }) : serialize({ error });
40
+ const resultJson = error != null ? serialize({ error }) : serialize({ result });
41
41
  const resultBytes = new TextEncoder().encode(resultJson);
42
42
  const length = resultBytes.length;
43
43
  resultArray.set(new Uint32Array([length]), 0);
@@ -117,13 +117,23 @@ export function invokeWorkerSync<T extends SQLiteWorkerMessageType & keyof Resul
117
117
  });
118
118
 
119
119
  let i = 0;
120
+ // @ts-expect-error: Remove this when TypeScript supports Atomics.pause
121
+ const useAtomicsPause = typeof Atomics.pause === 'function';
120
122
  while (Atomics.load(lock, 0) === PENDING) {
121
- // NOTE(kudo): Unfortunate busy loop,
122
- // because we don't have a way for main thread to yield its execution to other callbacks.
123
- // Maybe we can wait for [`Atomics.pause`](https://github.com/tc39/proposal-atomics-microwait) to be implemented.
124
123
  ++i;
125
- if (i > 1000000000) {
126
- throw new Error('Sync operation timeout');
124
+
125
+ if (useAtomicsPause) {
126
+ if (i > 1_000_000) {
127
+ throw new Error('Sync operation timeout');
128
+ }
129
+ // @ts-expect-error: Remove this when TypeScript supports Atomics.pause
130
+ Atomics.pause();
131
+ } else {
132
+ // NOTE(kudo): Unfortunate for the busy loop,
133
+ // because we don't have a way for main thread to yield its execution to other callbacks.
134
+ if (i > 1000_000_000) {
135
+ throw new Error('Sync operation timeout');
136
+ }
127
137
  }
128
138
  }
129
139
 
@@ -1 +0,0 @@
1
- df4580eb041e8620081acf960e64263a63771e856a40cc5ee17fa654fe3672da
@@ -1 +0,0 @@
1
- 4917cf35bb225309902a2482186f53d3cdde720c66d66ecf0dfa7aa42684a6ac4af424f8ea0e2bc7f7095b6301c1560ccb1fe9b224d8179e86e73e2c0a4c96c1
@@ -1 +0,0 @@
1
- 373c2a5b48f8c86abf1a2c022bf19461e156f976
@@ -1 +0,0 @@
1
- 12c296c7b073a3619de123a5780a8f448c21d0ec477741729ae3e22969147991
@@ -1 +0,0 @@
1
- c70d17eeafa0bb42f27a0e06919ee3e04a96a88ed852002640fc02d834602d86b622cefb08fa6e181d73758f9eb9f80c021f94161d8fae0ce5f6490261c3cd82
@@ -1,87 +0,0 @@
1
- {
2
- "formatVersion": "1.1",
3
- "component": {
4
- "group": "host.exp.exponent",
5
- "module": "expo.modules.sqlite",
6
- "version": "15.2.8",
7
- "attributes": {
8
- "org.gradle.status": "release"
9
- }
10
- },
11
- "createdBy": {
12
- "gradle": {
13
- "version": "8.13"
14
- }
15
- },
16
- "variants": [
17
- {
18
- "name": "releaseVariantReleaseApiPublication",
19
- "attributes": {
20
- "org.gradle.category": "library",
21
- "org.gradle.dependency.bundling": "external",
22
- "org.gradle.libraryelements": "aar",
23
- "org.gradle.usage": "java-api"
24
- },
25
- "files": [
26
- {
27
- "name": "expo.modules.sqlite-15.2.8.aar",
28
- "url": "expo.modules.sqlite-15.2.8.aar",
29
- "size": 3758068,
30
- "sha512": "c70d17eeafa0bb42f27a0e06919ee3e04a96a88ed852002640fc02d834602d86b622cefb08fa6e181d73758f9eb9f80c021f94161d8fae0ce5f6490261c3cd82",
31
- "sha256": "12c296c7b073a3619de123a5780a8f448c21d0ec477741729ae3e22969147991",
32
- "sha1": "373c2a5b48f8c86abf1a2c022bf19461e156f976",
33
- "md5": "17a83d0d04765f8cadda48e88a48b683"
34
- }
35
- ]
36
- },
37
- {
38
- "name": "releaseVariantReleaseRuntimePublication",
39
- "attributes": {
40
- "org.gradle.category": "library",
41
- "org.gradle.dependency.bundling": "external",
42
- "org.gradle.libraryelements": "aar",
43
- "org.gradle.usage": "java-runtime"
44
- },
45
- "dependencies": [
46
- {
47
- "group": "org.jetbrains.kotlin",
48
- "module": "kotlin-stdlib-jdk7",
49
- "version": {
50
- "requires": "2.0.21"
51
- }
52
- }
53
- ],
54
- "files": [
55
- {
56
- "name": "expo.modules.sqlite-15.2.8.aar",
57
- "url": "expo.modules.sqlite-15.2.8.aar",
58
- "size": 3758068,
59
- "sha512": "c70d17eeafa0bb42f27a0e06919ee3e04a96a88ed852002640fc02d834602d86b622cefb08fa6e181d73758f9eb9f80c021f94161d8fae0ce5f6490261c3cd82",
60
- "sha256": "12c296c7b073a3619de123a5780a8f448c21d0ec477741729ae3e22969147991",
61
- "sha1": "373c2a5b48f8c86abf1a2c022bf19461e156f976",
62
- "md5": "17a83d0d04765f8cadda48e88a48b683"
63
- }
64
- ]
65
- },
66
- {
67
- "name": "releaseVariantReleaseSourcePublication",
68
- "attributes": {
69
- "org.gradle.category": "documentation",
70
- "org.gradle.dependency.bundling": "external",
71
- "org.gradle.docstype": "sources",
72
- "org.gradle.usage": "java-runtime"
73
- },
74
- "files": [
75
- {
76
- "name": "expo.modules.sqlite-15.2.8-sources.jar",
77
- "url": "expo.modules.sqlite-15.2.8-sources.jar",
78
- "size": 11071,
79
- "sha512": "4917cf35bb225309902a2482186f53d3cdde720c66d66ecf0dfa7aa42684a6ac4af424f8ea0e2bc7f7095b6301c1560ccb1fe9b224d8179e86e73e2c0a4c96c1",
80
- "sha256": "df4580eb041e8620081acf960e64263a63771e856a40cc5ee17fa654fe3672da",
81
- "sha1": "1e52a7388cd71d0ad044ecd2658b8f7a89496240",
82
- "md5": "bb2978541a06d96c8c2180a09fe4aedc"
83
- }
84
- ]
85
- }
86
- ]
87
- }
@@ -1 +0,0 @@
1
- 6e100e76f2d2aa965f62c2fad77288bddff9869753ed5e8ccdfce17906806125
@@ -1 +0,0 @@
1
- 51467664d410566ae09beedec81353d9beca8e1fd09ffef3d7162032cc0e3b0788778d84d390e6074bb93ef938f23a5adf8a4a6bff7c28154c69a38dd59ca4cd
@@ -1,35 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
3
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4
- <!-- This module was also published with a richer model, Gradle metadata, -->
5
- <!-- which should be used instead. Do not delete the following line which -->
6
- <!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
7
- <!-- that they should prefer consuming it instead. -->
8
- <!-- do_not_remove: published-with-gradle-metadata -->
9
- <modelVersion>4.0.0</modelVersion>
10
- <groupId>host.exp.exponent</groupId>
11
- <artifactId>expo.modules.sqlite</artifactId>
12
- <version>15.2.8</version>
13
- <packaging>aar</packaging>
14
- <name>expo.modules.sqlite</name>
15
- <url>https://github.com/expo/expo</url>
16
- <licenses>
17
- <license>
18
- <name>MIT License</name>
19
- <url>https://github.com/expo/expo/blob/main/LICENSE</url>
20
- </license>
21
- </licenses>
22
- <scm>
23
- <connection>https://github.com/expo/expo.git</connection>
24
- <developerConnection>https://github.com/expo/expo.git</developerConnection>
25
- <url>https://github.com/expo/expo</url>
26
- </scm>
27
- <dependencies>
28
- <dependency>
29
- <groupId>org.jetbrains.kotlin</groupId>
30
- <artifactId>kotlin-stdlib-jdk7</artifactId>
31
- <version>2.0.21</version>
32
- <scope>runtime</scope>
33
- </dependency>
34
- </dependencies>
35
- </project>
@@ -1 +0,0 @@
1
- f2105f606d51a0265372320bc66e8336bf647a05
@@ -1 +0,0 @@
1
- 45a08465c72f5ceda3d441237f7c67107c35de4346f494564bbe8675231370dc
@@ -1 +0,0 @@
1
- e915ce90a954d2b9d2da8ed0381fadc4b12c04023855483f256b935efd253cb909290d5b92a125249adfe7fac2ea9a0f2cbe45f838fa0349f954dd48261a16dd
@@ -1,13 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <metadata>
3
- <groupId>host.exp.exponent</groupId>
4
- <artifactId>expo.modules.sqlite</artifactId>
5
- <versioning>
6
- <latest>15.2.8</latest>
7
- <release>15.2.8</release>
8
- <versions>
9
- <version>15.2.8</version>
10
- </versions>
11
- <lastUpdated>20250430004833</lastUpdated>
12
- </versioning>
13
- </metadata>
@@ -1 +0,0 @@
1
- 34281fd770bcfdde100e2a826b84cf11
@@ -1 +0,0 @@
1
- 521b94cad30343107562622504b4bfb0e937031c
@@ -1 +0,0 @@
1
- e492abde13ac3e8aad89adf146ddbee7429cd0db1db14908ac2925de2f8ad0c6
@@ -1 +0,0 @@
1
- 79efeb5cd7f3446b05cc5f58154f3ba85c92a28f8eb49f3ac2c6475756d6e13aabe136a0ba5a9caae3275ee22f4f191184dc92c9c2a9265b8d3f137816db31bf