expo-sqlite 15.0.3 → 15.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/android/build.gradle +2 -2
- package/android/src/main/cpp/SQLite3Main.cpp +0 -2
- package/build/Storage.d.ts +0 -2
- package/build/Storage.d.ts.map +1 -1
- package/build/Storage.js +14 -36
- package/build/Storage.js.map +1 -1
- package/ios/SQLiteModule.swift +1 -1
- package/package.json +2 -2
- package/src/Storage.ts +14 -38
- package/android/src/main/cpp/SQLite3Wrapper.cpp +0 -223
- package/android/src/main/cpp/SQLite3Wrapper.h +0 -55
- package/android/src/main/java/expo/modules/sqlite/SQLite3Wrapper.kt +0 -51
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,18 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 15.0.4 — 2024-12-26
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- Fixed exceptions when converting empty blob data on iOS. ([#33564](https://github.com/expo/expo/pull/33564) by [@kudo](https://github.com/kudo))
|
|
18
|
+
- Fixed `expo-sqlite/kv-store` async API not being well handled when using AsyncStorage compatible api ([#33847](https://github.com/expo/expo/pull/33847) by [@rtorrente](https://github.com/rtorrente))
|
|
19
|
+
- Fixed `database is locked` error from parallel `kv-store` operations. ([#33834](https://github.com/expo/expo/pull/33834) by [@kudo](https://github.com/kudo))
|
|
20
|
+
|
|
21
|
+
### 💡 Others
|
|
22
|
+
|
|
23
|
+
- Removed unused `SQLite3Wrapper` code for legacy implementation on Android. ([#33565](https://github.com/expo/expo/pull/33565) by [@kudo](https://github.com/kudo))
|
|
24
|
+
|
|
13
25
|
## 15.0.3 — 2024-11-12
|
|
14
26
|
|
|
15
27
|
### 🐛 Bug fixes
|
package/android/build.gradle
CHANGED
|
@@ -3,7 +3,7 @@ import org.apache.tools.ant.taskdefs.condition.Os
|
|
|
3
3
|
apply plugin: 'com.android.library'
|
|
4
4
|
|
|
5
5
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '15.0.
|
|
6
|
+
version = '15.0.4'
|
|
7
7
|
|
|
8
8
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
9
9
|
apply from: expoModulesCorePlugin
|
|
@@ -53,7 +53,7 @@ android {
|
|
|
53
53
|
namespace "expo.modules.sqlite"
|
|
54
54
|
defaultConfig {
|
|
55
55
|
versionCode 18
|
|
56
|
-
versionName "15.0.
|
|
56
|
+
versionName "15.0.4"
|
|
57
57
|
|
|
58
58
|
externalNativeBuild {
|
|
59
59
|
cmake {
|
|
@@ -4,12 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
#include "NativeDatabaseBinding.h"
|
|
6
6
|
#include "NativeStatementBinding.h"
|
|
7
|
-
#include "SQLite3Wrapper.h"
|
|
8
7
|
|
|
9
8
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
|
|
10
9
|
return facebook::jni::initialize(vm, [] {
|
|
11
10
|
expo::NativeDatabaseBinding::registerNatives();
|
|
12
11
|
expo::NativeStatementBinding::registerNatives();
|
|
13
|
-
expo::SQLite3Wrapper::registerNatives();
|
|
14
12
|
});
|
|
15
13
|
}
|
package/build/Storage.d.ts
CHANGED
|
@@ -107,9 +107,7 @@ export declare class SQLiteStorage {
|
|
|
107
107
|
* Alias for [`closeAsync()`](#closeasync-1) method.
|
|
108
108
|
*/
|
|
109
109
|
close(): Promise<void>;
|
|
110
|
-
private getDbAsync;
|
|
111
110
|
private getDbSync;
|
|
112
|
-
private maybeMigrateDbAsync;
|
|
113
111
|
private maybeMigrateDbSync;
|
|
114
112
|
/**
|
|
115
113
|
* Recursively merge two JSON objects.
|
package/build/Storage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../src/Storage.ts"],"names":[],"mappings":"AAEA;;;;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;IAMvD;;;OAGG;IACG,YAAY,CAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,kCAAkC,GACjD,OAAO,CAAC,IAAI,CAAC;IAgBhB;;OAEG;IACG,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMpD;;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;IAMvC;;;OAGG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,kCAAkC,GAAG,IAAI;IAgBlF;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAMpC;;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;IAY1D;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAclE;;OAEG;IACG,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAShE;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAShD;;;OAGG;IACG,UAAU,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlE;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../src/Storage.ts"],"names":[],"mappings":"AAEA;;;;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;IAMvD;;;OAGG;IACG,YAAY,CAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,kCAAkC,GACjD,OAAO,CAAC,IAAI,CAAC;IAgBhB;;OAEG;IACG,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMpD;;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;IAMvC;;;OAGG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,kCAAkC,GAAG,IAAI;IAgBlF;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAMpC;;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;IAY1D;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAclE;;OAEG;IACG,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAShE;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAShD;;;OAGG;IACG,UAAU,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlE;;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"}
|
package/build/Storage.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { openDatabaseSync } from './index';
|
|
2
2
|
const DATABASE_VERSION = 1;
|
|
3
3
|
const STATEMENT_GET = 'SELECT value FROM storage WHERE key = ?;';
|
|
4
4
|
const STATEMENT_SET = 'INSERT INTO storage (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value;';
|
|
@@ -20,7 +20,7 @@ export class SQLiteStorage {
|
|
|
20
20
|
* Retrieves the value associated with the given key asynchronously.
|
|
21
21
|
*/
|
|
22
22
|
async getItemAsync(key) {
|
|
23
|
-
const db =
|
|
23
|
+
const db = this.getDbSync();
|
|
24
24
|
const result = await db.getFirstAsync(STATEMENT_GET, key);
|
|
25
25
|
return result?.value ?? null;
|
|
26
26
|
}
|
|
@@ -29,7 +29,7 @@ export class SQLiteStorage {
|
|
|
29
29
|
* If a function is provided, it computes the new value based on the previous value.
|
|
30
30
|
*/
|
|
31
31
|
async setItemAsync(key, value) {
|
|
32
|
-
const db =
|
|
32
|
+
const db = this.getDbSync();
|
|
33
33
|
if (typeof value === 'function') {
|
|
34
34
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
35
35
|
const prevResult = await tx.getFirstAsync(STATEMENT_GET, key);
|
|
@@ -45,7 +45,7 @@ export class SQLiteStorage {
|
|
|
45
45
|
* Removes the value associated with the given key asynchronously.
|
|
46
46
|
*/
|
|
47
47
|
async removeItemAsync(key) {
|
|
48
|
-
const db =
|
|
48
|
+
const db = this.getDbSync();
|
|
49
49
|
const result = await db.runAsync(STATEMENT_REMOVE, key);
|
|
50
50
|
return result.changes > 0;
|
|
51
51
|
}
|
|
@@ -53,7 +53,7 @@ export class SQLiteStorage {
|
|
|
53
53
|
* Retrieves all keys stored in the storage asynchronously.
|
|
54
54
|
*/
|
|
55
55
|
async getAllKeysAsync() {
|
|
56
|
-
const db =
|
|
56
|
+
const db = this.getDbSync();
|
|
57
57
|
const result = await db.getAllAsync(STATEMENT_GET_ALL_KEYS);
|
|
58
58
|
return result.map(({ key }) => key);
|
|
59
59
|
}
|
|
@@ -61,7 +61,7 @@ export class SQLiteStorage {
|
|
|
61
61
|
* Clears all key-value pairs from the storage asynchronously.
|
|
62
62
|
*/
|
|
63
63
|
async clearAsync() {
|
|
64
|
-
const db =
|
|
64
|
+
const db = this.getDbSync();
|
|
65
65
|
const result = await db.runAsync(STATEMENT_CLEAR);
|
|
66
66
|
return result.changes > 0;
|
|
67
67
|
}
|
|
@@ -146,13 +146,13 @@ export class SQLiteStorage {
|
|
|
146
146
|
* Alias for [`setItemAsync()`](#setitemasynckey-value).
|
|
147
147
|
*/
|
|
148
148
|
async setItem(key, value) {
|
|
149
|
-
this.setItemAsync(key, value);
|
|
149
|
+
await this.setItemAsync(key, value);
|
|
150
150
|
}
|
|
151
151
|
/**
|
|
152
152
|
* Alias for [`removeItemAsync()`](#removeitemasynckey) method.
|
|
153
153
|
*/
|
|
154
154
|
async removeItem(key) {
|
|
155
|
-
this.removeItemAsync(key);
|
|
155
|
+
await this.removeItemAsync(key);
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
158
|
* Alias for [`getAllKeysAsync()`](#getallkeysasync) method.
|
|
@@ -164,7 +164,7 @@ export class SQLiteStorage {
|
|
|
164
164
|
* Alias for [`clearAsync()`](#clearasync) method.
|
|
165
165
|
*/
|
|
166
166
|
async clear() {
|
|
167
|
-
this.clearAsync();
|
|
167
|
+
await this.clearAsync();
|
|
168
168
|
}
|
|
169
169
|
/**
|
|
170
170
|
* Merges the given value with the existing value for the given key asynchronously.
|
|
@@ -185,7 +185,7 @@ export class SQLiteStorage {
|
|
|
185
185
|
* Retrieves the values associated with the given keys asynchronously.
|
|
186
186
|
*/
|
|
187
187
|
async multiGet(keys) {
|
|
188
|
-
const db =
|
|
188
|
+
const db = this.getDbSync();
|
|
189
189
|
let result = [];
|
|
190
190
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
191
191
|
result = await Promise.all(keys.map(async (key) => {
|
|
@@ -199,7 +199,7 @@ export class SQLiteStorage {
|
|
|
199
199
|
* Sets multiple key-value pairs asynchronously.
|
|
200
200
|
*/
|
|
201
201
|
async multiSet(keyValuePairs) {
|
|
202
|
-
const db =
|
|
202
|
+
const db = this.getDbSync();
|
|
203
203
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
204
204
|
for (const [key, value] of keyValuePairs) {
|
|
205
205
|
await tx.runAsync(STATEMENT_SET, key, value);
|
|
@@ -210,7 +210,7 @@ export class SQLiteStorage {
|
|
|
210
210
|
* Removes the values associated with the given keys asynchronously.
|
|
211
211
|
*/
|
|
212
212
|
async multiRemove(keys) {
|
|
213
|
-
const db =
|
|
213
|
+
const db = this.getDbSync();
|
|
214
214
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
215
215
|
for (const key of keys) {
|
|
216
216
|
await tx.runAsync(STATEMENT_REMOVE, key);
|
|
@@ -222,7 +222,7 @@ export class SQLiteStorage {
|
|
|
222
222
|
* If existing values are JSON objects, performs a deep merge.
|
|
223
223
|
*/
|
|
224
224
|
async multiMerge(keyValuePairs) {
|
|
225
|
-
const db =
|
|
225
|
+
const db = this.getDbSync();
|
|
226
226
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
227
227
|
for (const [key, value] of keyValuePairs) {
|
|
228
228
|
const prevValue = await tx.getFirstAsync(STATEMENT_GET, key);
|
|
@@ -241,18 +241,10 @@ export class SQLiteStorage {
|
|
|
241
241
|
* Alias for [`closeAsync()`](#closeasync-1) method.
|
|
242
242
|
*/
|
|
243
243
|
async close() {
|
|
244
|
-
this.closeAsync();
|
|
244
|
+
await this.closeAsync();
|
|
245
245
|
}
|
|
246
246
|
//#endregion
|
|
247
247
|
//#region Internals
|
|
248
|
-
async getDbAsync() {
|
|
249
|
-
if (!this.db) {
|
|
250
|
-
const db = await openDatabaseAsync(this.databaseName);
|
|
251
|
-
await this.maybeMigrateDbAsync(db);
|
|
252
|
-
this.db = db;
|
|
253
|
-
}
|
|
254
|
-
return this.db;
|
|
255
|
-
}
|
|
256
248
|
getDbSync() {
|
|
257
249
|
if (!this.db) {
|
|
258
250
|
const db = openDatabaseSync(this.databaseName);
|
|
@@ -261,20 +253,6 @@ export class SQLiteStorage {
|
|
|
261
253
|
}
|
|
262
254
|
return this.db;
|
|
263
255
|
}
|
|
264
|
-
async maybeMigrateDbAsync(db) {
|
|
265
|
-
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
266
|
-
const result = await tx.getFirstAsync('PRAGMA user_version');
|
|
267
|
-
let currentDbVersion = result?.user_version ?? 0;
|
|
268
|
-
if (currentDbVersion >= DATABASE_VERSION) {
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
if (currentDbVersion === 0) {
|
|
272
|
-
await tx.execAsync(MIGRATION_STATEMENT_0);
|
|
273
|
-
currentDbVersion = 1;
|
|
274
|
-
}
|
|
275
|
-
await tx.execAsync(`PRAGMA user_version = ${DATABASE_VERSION}`);
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
256
|
maybeMigrateDbSync(db) {
|
|
279
257
|
db.withTransactionSync(() => {
|
|
280
258
|
const result = db.getFirstSync('PRAGMA user_version');
|
package/build/Storage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Storage.js","sourceRoot":"","sources":["../src/Storage.ts"],"names":[],"mappings":"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","sourcesContent":["import { 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\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 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 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 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 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 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 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 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 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 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 this.setItemAsync(key, value);\n }\n\n /**\n * Alias for [`removeItemAsync()`](#removeitemasynckey) method.\n */\n async removeItem(key: string): Promise<void> {\n 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 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 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 const db = await this.getDbAsync();\n let result: [string, string | null][] = [];\n await db.withExclusiveTransactionAsync(async (tx) => {\n result = await Promise.all(\n keys.map(async (key) => {\n const row = await tx.getFirstAsync<{ value: string }>(STATEMENT_GET, key);\n return [key, row?.value ?? null];\n })\n );\n });\n return result;\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 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 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 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 this.closeAsync();\n }\n\n //#endregion\n\n //#region Internals\n\n private async getDbAsync(): Promise<SQLiteDatabase> {\n if (!this.db) {\n const db = await openDatabaseAsync(this.databaseName);\n await this.maybeMigrateDbAsync(db);\n this.db = db;\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 async maybeMigrateDbAsync(db: SQLiteDatabase) {\n await db.withExclusiveTransactionAsync(async (tx) => {\n const result = await tx.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 tx.execAsync(MIGRATION_STATEMENT_0);\n currentDbVersion = 1;\n }\n await tx.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 //#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 { 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\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 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 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 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 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 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 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 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 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 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 const db = this.getDbSync();\n let result: [string, string | null][] = [];\n await db.withExclusiveTransactionAsync(async (tx) => {\n result = await Promise.all(\n keys.map(async (key) => {\n const row = await tx.getFirstAsync<{ value: string }>(STATEMENT_GET, key);\n return [key, row?.value ?? null];\n })\n );\n });\n return result;\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 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 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 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"]}
|
package/ios/SQLiteModule.swift
CHANGED
|
@@ -493,7 +493,7 @@ public final class SQLiteModule: Module {
|
|
|
493
493
|
return String(cString: text)
|
|
494
494
|
case SQLITE_BLOB:
|
|
495
495
|
guard let blob = exsqlite3_column_blob(instance, index) else {
|
|
496
|
-
|
|
496
|
+
return Data()
|
|
497
497
|
}
|
|
498
498
|
let size = exsqlite3_column_bytes(instance, index)
|
|
499
499
|
return Data(bytes: blob, count: Int(size))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-sqlite",
|
|
3
|
-
"version": "15.0.
|
|
3
|
+
"version": "15.0.4",
|
|
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",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"react": "*",
|
|
62
62
|
"react-native": "*"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "64d037d767a487f402ffd0d7d919aa7e848815ac"
|
|
65
65
|
}
|
package/src/Storage.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { openDatabaseSync, type SQLiteDatabase } from './index';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* 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.
|
|
@@ -32,7 +32,7 @@ export class SQLiteStorage {
|
|
|
32
32
|
* Retrieves the value associated with the given key asynchronously.
|
|
33
33
|
*/
|
|
34
34
|
async getItemAsync(key: string): Promise<string | null> {
|
|
35
|
-
const db =
|
|
35
|
+
const db = this.getDbSync();
|
|
36
36
|
const result = await db.getFirstAsync<{ value: string }>(STATEMENT_GET, key);
|
|
37
37
|
return result?.value ?? null;
|
|
38
38
|
}
|
|
@@ -45,7 +45,7 @@ export class SQLiteStorage {
|
|
|
45
45
|
key: string,
|
|
46
46
|
value: string | SQLiteStorageSetItemUpdateFunction
|
|
47
47
|
): Promise<void> {
|
|
48
|
-
const db =
|
|
48
|
+
const db = this.getDbSync();
|
|
49
49
|
|
|
50
50
|
if (typeof value === 'function') {
|
|
51
51
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
@@ -64,7 +64,7 @@ export class SQLiteStorage {
|
|
|
64
64
|
* Removes the value associated with the given key asynchronously.
|
|
65
65
|
*/
|
|
66
66
|
async removeItemAsync(key: string): Promise<boolean> {
|
|
67
|
-
const db =
|
|
67
|
+
const db = this.getDbSync();
|
|
68
68
|
const result = await db.runAsync(STATEMENT_REMOVE, key);
|
|
69
69
|
return result.changes > 0;
|
|
70
70
|
}
|
|
@@ -73,7 +73,7 @@ export class SQLiteStorage {
|
|
|
73
73
|
* Retrieves all keys stored in the storage asynchronously.
|
|
74
74
|
*/
|
|
75
75
|
async getAllKeysAsync(): Promise<string[]> {
|
|
76
|
-
const db =
|
|
76
|
+
const db = this.getDbSync();
|
|
77
77
|
const result = await db.getAllAsync<{ key: string }>(STATEMENT_GET_ALL_KEYS);
|
|
78
78
|
return result.map(({ key }) => key);
|
|
79
79
|
}
|
|
@@ -82,7 +82,7 @@ export class SQLiteStorage {
|
|
|
82
82
|
* Clears all key-value pairs from the storage asynchronously.
|
|
83
83
|
*/
|
|
84
84
|
async clearAsync(): Promise<boolean> {
|
|
85
|
-
const db =
|
|
85
|
+
const db = this.getDbSync();
|
|
86
86
|
const result = await db.runAsync(STATEMENT_CLEAR);
|
|
87
87
|
return result.changes > 0;
|
|
88
88
|
}
|
|
@@ -182,14 +182,14 @@ export class SQLiteStorage {
|
|
|
182
182
|
* Alias for [`setItemAsync()`](#setitemasynckey-value).
|
|
183
183
|
*/
|
|
184
184
|
async setItem(key: string, value: string | SQLiteStorageSetItemUpdateFunction): Promise<void> {
|
|
185
|
-
this.setItemAsync(key, value);
|
|
185
|
+
await this.setItemAsync(key, value);
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
/**
|
|
189
189
|
* Alias for [`removeItemAsync()`](#removeitemasynckey) method.
|
|
190
190
|
*/
|
|
191
191
|
async removeItem(key: string): Promise<void> {
|
|
192
|
-
this.removeItemAsync(key);
|
|
192
|
+
await this.removeItemAsync(key);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/**
|
|
@@ -203,7 +203,7 @@ export class SQLiteStorage {
|
|
|
203
203
|
* Alias for [`clearAsync()`](#clearasync) method.
|
|
204
204
|
*/
|
|
205
205
|
async clear(): Promise<void> {
|
|
206
|
-
this.clearAsync();
|
|
206
|
+
await this.clearAsync();
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/**
|
|
@@ -226,7 +226,7 @@ export class SQLiteStorage {
|
|
|
226
226
|
* Retrieves the values associated with the given keys asynchronously.
|
|
227
227
|
*/
|
|
228
228
|
async multiGet(keys: string[]): Promise<[string, string | null][]> {
|
|
229
|
-
const db =
|
|
229
|
+
const db = this.getDbSync();
|
|
230
230
|
let result: [string, string | null][] = [];
|
|
231
231
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
232
232
|
result = await Promise.all(
|
|
@@ -243,7 +243,7 @@ export class SQLiteStorage {
|
|
|
243
243
|
* Sets multiple key-value pairs asynchronously.
|
|
244
244
|
*/
|
|
245
245
|
async multiSet(keyValuePairs: [string, string][]): Promise<void> {
|
|
246
|
-
const db =
|
|
246
|
+
const db = this.getDbSync();
|
|
247
247
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
248
248
|
for (const [key, value] of keyValuePairs) {
|
|
249
249
|
await tx.runAsync(STATEMENT_SET, key, value);
|
|
@@ -255,7 +255,7 @@ export class SQLiteStorage {
|
|
|
255
255
|
* Removes the values associated with the given keys asynchronously.
|
|
256
256
|
*/
|
|
257
257
|
async multiRemove(keys: string[]): Promise<void> {
|
|
258
|
-
const db =
|
|
258
|
+
const db = this.getDbSync();
|
|
259
259
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
260
260
|
for (const key of keys) {
|
|
261
261
|
await tx.runAsync(STATEMENT_REMOVE, key);
|
|
@@ -268,7 +268,7 @@ export class SQLiteStorage {
|
|
|
268
268
|
* If existing values are JSON objects, performs a deep merge.
|
|
269
269
|
*/
|
|
270
270
|
async multiMerge(keyValuePairs: [string, string][]): Promise<void> {
|
|
271
|
-
const db =
|
|
271
|
+
const db = this.getDbSync();
|
|
272
272
|
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
273
273
|
for (const [key, value] of keyValuePairs) {
|
|
274
274
|
const prevValue = await tx.getFirstAsync<{ value: string }>(STATEMENT_GET, key);
|
|
@@ -288,22 +288,13 @@ export class SQLiteStorage {
|
|
|
288
288
|
* Alias for [`closeAsync()`](#closeasync-1) method.
|
|
289
289
|
*/
|
|
290
290
|
async close(): Promise<void> {
|
|
291
|
-
this.closeAsync();
|
|
291
|
+
await this.closeAsync();
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
//#endregion
|
|
295
295
|
|
|
296
296
|
//#region Internals
|
|
297
297
|
|
|
298
|
-
private async getDbAsync(): Promise<SQLiteDatabase> {
|
|
299
|
-
if (!this.db) {
|
|
300
|
-
const db = await openDatabaseAsync(this.databaseName);
|
|
301
|
-
await this.maybeMigrateDbAsync(db);
|
|
302
|
-
this.db = db;
|
|
303
|
-
}
|
|
304
|
-
return this.db;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
298
|
private getDbSync(): SQLiteDatabase {
|
|
308
299
|
if (!this.db) {
|
|
309
300
|
const db = openDatabaseSync(this.databaseName);
|
|
@@ -313,21 +304,6 @@ export class SQLiteStorage {
|
|
|
313
304
|
return this.db;
|
|
314
305
|
}
|
|
315
306
|
|
|
316
|
-
private async maybeMigrateDbAsync(db: SQLiteDatabase) {
|
|
317
|
-
await db.withExclusiveTransactionAsync(async (tx) => {
|
|
318
|
-
const result = await tx.getFirstAsync<{ user_version: number }>('PRAGMA user_version');
|
|
319
|
-
let currentDbVersion = result?.user_version ?? 0;
|
|
320
|
-
if (currentDbVersion >= DATABASE_VERSION) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
if (currentDbVersion === 0) {
|
|
324
|
-
await tx.execAsync(MIGRATION_STATEMENT_0);
|
|
325
|
-
currentDbVersion = 1;
|
|
326
|
-
}
|
|
327
|
-
await tx.execAsync(`PRAGMA user_version = ${DATABASE_VERSION}`);
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
|
|
331
307
|
private maybeMigrateDbSync(db: SQLiteDatabase) {
|
|
332
308
|
db.withTransactionSync(() => {
|
|
333
309
|
const result = db.getFirstSync<{ user_version: number }>('PRAGMA user_version');
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
-
|
|
3
|
-
#include "SQLite3Wrapper.h"
|
|
4
|
-
|
|
5
|
-
#include <android/log.h>
|
|
6
|
-
|
|
7
|
-
namespace jni = facebook::jni;
|
|
8
|
-
|
|
9
|
-
namespace expo {
|
|
10
|
-
|
|
11
|
-
namespace {
|
|
12
|
-
|
|
13
|
-
constexpr char TAG[] = "expo-sqlite";
|
|
14
|
-
|
|
15
|
-
} // namespace
|
|
16
|
-
|
|
17
|
-
// static
|
|
18
|
-
void SQLite3Wrapper::registerNatives() {
|
|
19
|
-
registerHybrid({
|
|
20
|
-
makeNativeMethod("initHybrid", SQLite3Wrapper::initHybrid),
|
|
21
|
-
makeNativeMethod("executeSql", SQLite3Wrapper::executeSql),
|
|
22
|
-
makeNativeMethod("sqlite3_open", SQLite3Wrapper::sqlite3_open),
|
|
23
|
-
makeNativeMethod("sqlite3_close", SQLite3Wrapper::sqlite3_close),
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
jni::local_ref<jni::JList<jni::JObject>>
|
|
28
|
-
SQLite3Wrapper::executeSql(const std::string &sql,
|
|
29
|
-
jni::alias_ref<jni::JList<jni::JObject>> args,
|
|
30
|
-
bool readOnly) {
|
|
31
|
-
auto resultRows = jni::JArrayList<jni::JObject>::create();
|
|
32
|
-
exsqlite3_stmt *statement = nullptr;
|
|
33
|
-
int rowsAffected = 0;
|
|
34
|
-
sqlite3_int64 insertId = 0;
|
|
35
|
-
jni::local_ref<jni::JString> error;
|
|
36
|
-
|
|
37
|
-
if (exsqlite3_prepare_v2(db, sql.c_str(), -1, &statement, nullptr) !=
|
|
38
|
-
SQLITE_OK) {
|
|
39
|
-
auto results = jni::JArrayList<jni::JObject>::create();
|
|
40
|
-
results->add(convertSqlLiteErrorToString(db));
|
|
41
|
-
return results;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
bool queryIsReadOnly = exsqlite3_stmt_readonly(statement) > 0;
|
|
45
|
-
if (readOnly && !queryIsReadOnly) {
|
|
46
|
-
auto results = jni::JArrayList<jni::JObject>::create();
|
|
47
|
-
std::string error("could not prepare ");
|
|
48
|
-
error += sql;
|
|
49
|
-
results->add(jni::make_jstring(error));
|
|
50
|
-
return results;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
int index = 1;
|
|
54
|
-
for (const auto &arg : *args) {
|
|
55
|
-
bindStatement(statement, arg, index++);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
int columnCount = 0;
|
|
59
|
-
auto columnNames = jni::JArrayList<jni::JString>::create();
|
|
60
|
-
int columnType;
|
|
61
|
-
bool fetchedColumns = false;
|
|
62
|
-
jni::local_ref<jni::JObject> value;
|
|
63
|
-
bool hasMore = true;
|
|
64
|
-
|
|
65
|
-
while (hasMore) {
|
|
66
|
-
switch (exsqlite3_step(statement)) {
|
|
67
|
-
case SQLITE_ROW: {
|
|
68
|
-
if (!fetchedColumns) {
|
|
69
|
-
columnCount = exsqlite3_column_count(statement);
|
|
70
|
-
|
|
71
|
-
for (int i = 0; i < columnCount; ++i) {
|
|
72
|
-
const char *columnName = exsqlite3_column_name(statement, i);
|
|
73
|
-
columnNames->add(jni::make_jstring(columnName));
|
|
74
|
-
}
|
|
75
|
-
fetchedColumns = true;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
auto entry = jni::JArrayList<jni::JObject>::create();
|
|
79
|
-
|
|
80
|
-
for (int i = 0; i < columnCount; ++i) {
|
|
81
|
-
columnType = exsqlite3_column_type(statement, i);
|
|
82
|
-
value = getSqlValue(columnType, statement, i);
|
|
83
|
-
entry->add(value);
|
|
84
|
-
}
|
|
85
|
-
resultRows->add(entry);
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
case SQLITE_DONE: {
|
|
89
|
-
hasMore = false;
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
default: {
|
|
93
|
-
error = convertSqlLiteErrorToString(db);
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (!queryIsReadOnly) {
|
|
100
|
-
rowsAffected = exsqlite3_changes(db);
|
|
101
|
-
if (rowsAffected > 0) {
|
|
102
|
-
insertId = exsqlite3_last_insert_rowid(db);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
exsqlite3_finalize(statement);
|
|
107
|
-
|
|
108
|
-
if (error) {
|
|
109
|
-
auto results = jni::JArrayList<jni::JObject>::create();
|
|
110
|
-
results->add(error);
|
|
111
|
-
return results;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
auto results = jni::JArrayList<jni::JObject>::create();
|
|
115
|
-
results->add(nullptr);
|
|
116
|
-
results->add(jni::JLong::valueOf(insertId));
|
|
117
|
-
results->add(jni::JInteger::valueOf(rowsAffected));
|
|
118
|
-
results->add(columnNames);
|
|
119
|
-
results->add(resultRows);
|
|
120
|
-
return results;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
int SQLite3Wrapper::sqlite3_open(const std::string &dbPath) {
|
|
124
|
-
return ::exsqlite3_open(dbPath.c_str(), &db);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
int SQLite3Wrapper::sqlite3_close() {
|
|
128
|
-
int ret = ::exsqlite3_close(db);
|
|
129
|
-
db = nullptr;
|
|
130
|
-
return ret;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// static
|
|
134
|
-
jni::local_ref<SQLite3Wrapper::jhybriddata>
|
|
135
|
-
SQLite3Wrapper::initHybrid(jni::alias_ref<jhybridobject> jThis) {
|
|
136
|
-
return makeCxxInstance(jThis);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// static
|
|
140
|
-
jni::local_ref<jni::JString>
|
|
141
|
-
SQLite3Wrapper::convertSqlLiteErrorToString(sqlite3 *db) {
|
|
142
|
-
int code = exsqlite3_errcode(db);
|
|
143
|
-
const char *message = exsqlite3_errmsg(db);
|
|
144
|
-
std::string result("Error code ");
|
|
145
|
-
result += code;
|
|
146
|
-
result += ": ";
|
|
147
|
-
result += message;
|
|
148
|
-
return jni::make_jstring(result);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// static
|
|
152
|
-
void SQLite3Wrapper::bindStatement(exsqlite3_stmt *statement,
|
|
153
|
-
jni::alias_ref<jni::JObject> arg,
|
|
154
|
-
int index) {
|
|
155
|
-
static const auto integerClass = jni::JInteger::javaClassStatic();
|
|
156
|
-
static const auto longClass = jni::JLong::javaClassStatic();
|
|
157
|
-
static const auto doubleClass = jni::JDouble::javaClassStatic();
|
|
158
|
-
static const auto stringClass = jni::JString::javaClassStatic();
|
|
159
|
-
|
|
160
|
-
if (arg == nullptr) {
|
|
161
|
-
exsqlite3_bind_null(statement, index);
|
|
162
|
-
} else if (arg->isInstanceOf(integerClass)) {
|
|
163
|
-
exsqlite3_bind_int(statement, index,
|
|
164
|
-
jni::static_ref_cast<jni::JInteger>(arg)->value());
|
|
165
|
-
} else if (arg->isInstanceOf(longClass)) {
|
|
166
|
-
exsqlite3_bind_int64(statement, index,
|
|
167
|
-
jni::static_ref_cast<jni::JLong>(arg)->value());
|
|
168
|
-
} else if (arg->isInstanceOf(doubleClass)) {
|
|
169
|
-
exsqlite3_bind_double(statement, index,
|
|
170
|
-
jni::static_ref_cast<jni::JDouble>(arg)->value());
|
|
171
|
-
} else {
|
|
172
|
-
std::string stringArg;
|
|
173
|
-
if (arg->isInstanceOf(stringClass)) {
|
|
174
|
-
stringArg = jni::static_ref_cast<jni::JString>(arg)->toStdString();
|
|
175
|
-
} else {
|
|
176
|
-
stringArg = arg->toString();
|
|
177
|
-
}
|
|
178
|
-
exsqlite3_bind_text(statement, index, stringArg.c_str(), stringArg.length(),
|
|
179
|
-
SQLITE_TRANSIENT);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// static
|
|
184
|
-
jni::local_ref<jni::JObject>
|
|
185
|
-
SQLite3Wrapper::getSqlValue(int columnType, exsqlite3_stmt *statement,
|
|
186
|
-
int index) {
|
|
187
|
-
switch (columnType) {
|
|
188
|
-
case SQLITE_INTEGER: {
|
|
189
|
-
return jni::JLong::valueOf(exsqlite3_column_int64(statement, index));
|
|
190
|
-
}
|
|
191
|
-
case SQLITE_FLOAT: {
|
|
192
|
-
return jni::JDouble::valueOf(exsqlite3_column_double(statement, index));
|
|
193
|
-
}
|
|
194
|
-
case SQLITE_BLOB: {
|
|
195
|
-
JNIEnv *env = jni::Environment::current();
|
|
196
|
-
return jni::adopt_local(env->NewString(
|
|
197
|
-
reinterpret_cast<const jchar *>(exsqlite3_column_blob(statement, index)),
|
|
198
|
-
static_cast<size_t>(exsqlite3_column_bytes(statement, index))));
|
|
199
|
-
}
|
|
200
|
-
case SQLITE_TEXT: {
|
|
201
|
-
std::string text(
|
|
202
|
-
reinterpret_cast<const char *>(exsqlite3_column_text(statement, index)),
|
|
203
|
-
static_cast<size_t>(exsqlite3_column_bytes(statement, index)));
|
|
204
|
-
return jni::make_jstring(text);
|
|
205
|
-
}
|
|
206
|
-
default: {
|
|
207
|
-
return nullptr;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// static
|
|
213
|
-
void SQLite3Wrapper::OnUpdateHook(void *arg, int action, char const *dbName,
|
|
214
|
-
char const *tableName, sqlite3_int64 rowId) {
|
|
215
|
-
SQLite3Wrapper *pThis = reinterpret_cast<SQLite3Wrapper *>(arg);
|
|
216
|
-
static const auto method =
|
|
217
|
-
jni::findClassStatic("expo/modules/sqlite/SQLite3Wrapper")
|
|
218
|
-
->getMethod<void(jint, jstring, jstring, jlong)>("onUpdate");
|
|
219
|
-
method(pThis->javaPart_, action, jni::make_jstring(dbName).get(),
|
|
220
|
-
jni::make_jstring(tableName).get(), rowId);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
} // namespace expo
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
-
|
|
3
|
-
#pragma once
|
|
4
|
-
|
|
5
|
-
#include <fbjni/fbjni.h>
|
|
6
|
-
#include <string>
|
|
7
|
-
|
|
8
|
-
#include "sqlite3.h"
|
|
9
|
-
|
|
10
|
-
namespace jni = facebook::jni;
|
|
11
|
-
|
|
12
|
-
namespace expo {
|
|
13
|
-
|
|
14
|
-
class SQLite3Wrapper : public jni::HybridClass<SQLite3Wrapper> {
|
|
15
|
-
public:
|
|
16
|
-
static constexpr auto kJavaDescriptor =
|
|
17
|
-
"Lexpo/modules/sqlite/SQLite3Wrapper;";
|
|
18
|
-
|
|
19
|
-
static void registerNatives();
|
|
20
|
-
|
|
21
|
-
jni::local_ref<jni::JList<jni::JObject>>
|
|
22
|
-
executeSql(const std::string &sql,
|
|
23
|
-
jni::alias_ref<jni::JList<jni::JObject>> args, bool readOnly);
|
|
24
|
-
|
|
25
|
-
// sqlite3 bindings
|
|
26
|
-
int sqlite3_open(const std::string &dbPath);
|
|
27
|
-
int sqlite3_close();
|
|
28
|
-
|
|
29
|
-
private:
|
|
30
|
-
explicit SQLite3Wrapper(jni::alias_ref<SQLite3Wrapper::jhybridobject> jThis)
|
|
31
|
-
: javaPart_(jni::make_global(jThis)) {}
|
|
32
|
-
|
|
33
|
-
private:
|
|
34
|
-
static jni::local_ref<jhybriddata>
|
|
35
|
-
initHybrid(jni::alias_ref<jhybridobject> jThis);
|
|
36
|
-
|
|
37
|
-
static jni::local_ref<jni::JString> convertSqlLiteErrorToString(sqlite3 *db);
|
|
38
|
-
|
|
39
|
-
static void bindStatement(exsqlite3_stmt *statement,
|
|
40
|
-
jni::alias_ref<jni::JObject> arg, int index);
|
|
41
|
-
|
|
42
|
-
static jni::local_ref<jni::JObject>
|
|
43
|
-
getSqlValue(int columnType, exsqlite3_stmt *statement, int index);
|
|
44
|
-
|
|
45
|
-
static void OnUpdateHook(void *arg, int action, char const *dbName,
|
|
46
|
-
char const *tableName, sqlite3_int64 rowId);
|
|
47
|
-
|
|
48
|
-
private:
|
|
49
|
-
friend HybridBase;
|
|
50
|
-
|
|
51
|
-
jni::global_ref<SQLite3Wrapper::javaobject> javaPart_;
|
|
52
|
-
sqlite3 *db;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
} // namespace expo
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
package expo.modules.sqlite
|
|
2
|
-
|
|
3
|
-
import com.facebook.jni.HybridData
|
|
4
|
-
import expo.modules.core.interfaces.DoNotStrip
|
|
5
|
-
|
|
6
|
-
@Suppress("KotlinJniMissingFunction")
|
|
7
|
-
@DoNotStrip
|
|
8
|
-
class SQLite3Wrapper private constructor() {
|
|
9
|
-
@DoNotStrip
|
|
10
|
-
private val mHybridData: HybridData
|
|
11
|
-
|
|
12
|
-
init {
|
|
13
|
-
mHybridData = initHybrid()
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Execute SQL commands
|
|
18
|
-
*/
|
|
19
|
-
external fun executeSql(sql: String, args: List<Any?>, readOnly: Boolean): List<Any>
|
|
20
|
-
|
|
21
|
-
// region sqlite3 bindings
|
|
22
|
-
|
|
23
|
-
external fun sqlite3_open(dbPath: String): Int
|
|
24
|
-
external fun sqlite3_close(): Int
|
|
25
|
-
|
|
26
|
-
// endregion
|
|
27
|
-
|
|
28
|
-
// region internals
|
|
29
|
-
|
|
30
|
-
private external fun initHybrid(): HybridData
|
|
31
|
-
|
|
32
|
-
// endregion
|
|
33
|
-
|
|
34
|
-
companion object {
|
|
35
|
-
init {
|
|
36
|
-
System.loadLibrary("expo-sqlite")
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@JvmStatic
|
|
40
|
-
fun open(dbPath: String): SQLite3Wrapper? {
|
|
41
|
-
val instance = SQLite3Wrapper()
|
|
42
|
-
if (instance.sqlite3_open(dbPath) != SQLITE_OK) {
|
|
43
|
-
return null
|
|
44
|
-
}
|
|
45
|
-
return instance
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// These error code should be synced with sqlite3.h
|
|
49
|
-
const val SQLITE_OK = 0
|
|
50
|
-
}
|
|
51
|
-
}
|