@capgo/capacitor-fast-sql 8.2.16 → 8.2.18
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/README.md +17 -16
- package/android/build.gradle +1 -0
- package/android/consumer-rules.pro +14 -0
- package/android/src/main/java/app/capgo/capacitor/fastsql/CapgoCapacitorFastSqlPlugin.java +29 -6
- package/android/src/main/java/app/capgo/capacitor/fastsql/DatabaseConnection.java +2 -0
- package/android/src/main/java/app/capgo/capacitor/fastsql/EncryptedSQLDatabase.java +33 -46
- package/android/src/main/java/app/capgo/capacitor/fastsql/SQLDatabase.java +32 -50
- package/android/src/main/java/app/capgo/capacitor/fastsql/SQLHTTPServer.java +11 -23
- package/dist/esm/definitions.d.ts +17 -2
- package/dist/esm/definitions.d.ts.map +1 -1
- package/dist/esm/definitions.js +3 -1
- package/dist/esm/fast-sql.d.ts +4 -0
- package/dist/esm/fast-sql.d.ts.map +1 -1
- package/dist/esm/fast-sql.js +35 -3
- package/dist/esm/native-sql-connection.d.ts +1 -0
- package/dist/esm/native-sql-connection.d.ts.map +1 -1
- package/dist/esm/native-sql-connection.js +13 -6
- package/dist/esm/transaction-isolation.d.ts +3 -0
- package/dist/esm/transaction-isolation.d.ts.map +1 -0
- package/dist/esm/transaction-isolation.js +6 -0
- package/dist/esm/vector-store.d.ts.map +1 -1
- package/dist/esm/vector-store.js +5 -2
- package/dist/esm/web-sql-connection.d.ts.map +1 -1
- package/dist/esm/web-sql-connection.js +2 -0
- package/dist/esm/web.d.ts +2 -0
- package/dist/esm/web.d.ts.map +1 -1
- package/dist/esm/web.js +32 -4
- package/dist/plugin.cjs.js +93 -16
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +93 -16
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCapacitorFastSqlPlugin/CapgoCapacitorFastSqlPlugin.swift +25 -3
- package/ios/Sources/CapgoCapacitorFastSqlPlugin/SQLDatabase.swift +15 -5
- package/ios/Sources/CapgoCapacitorFastSqlPlugin/SQLHTTPServer.swift +6 -0
- package/ios/Tests/CapgoCapacitorFastSqlPluginTests/CapgoCapacitorFastSqlPluginTests.swift +13 -3
- package/ios/Tests/CapgoCapacitorFastSqlPluginTests/SQLResultMetadataTests.swift +15 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -383,7 +383,7 @@ bypassing Capacitor's standard bridge for better performance with sync operation
|
|
|
383
383
|
### connect(...)
|
|
384
384
|
|
|
385
385
|
```typescript
|
|
386
|
-
connect(options: SQLConnectionOptions) => Promise<{ port: number; token: string; database: string; }>
|
|
386
|
+
connect(options: SQLConnectionOptions) => Promise<{ port: number; token: string; database: string; persistent?: boolean; }>
|
|
387
387
|
```
|
|
388
388
|
|
|
389
389
|
Initialize the database connection and start the HTTP server.
|
|
@@ -392,7 +392,7 @@ Initialize the database connection and start the HTTP server.
|
|
|
392
392
|
| ------------- | --------------------------------------------------------------------- | -------------------- |
|
|
393
393
|
| **`options`** | <code><a href="#sqlconnectionoptions">SQLConnectionOptions</a></code> | - Connection options |
|
|
394
394
|
|
|
395
|
-
**Returns:** <code>Promise<{ port: number; token: string; database: string; }></code>
|
|
395
|
+
**Returns:** <code>Promise<{ port: number; token: string; database: string; persistent?: boolean; }></code>
|
|
396
396
|
|
|
397
397
|
**Since:** 0.0.1
|
|
398
398
|
|
|
@@ -419,7 +419,7 @@ Close database connection and stop the HTTP server.
|
|
|
419
419
|
### getServerInfo(...)
|
|
420
420
|
|
|
421
421
|
```typescript
|
|
422
|
-
getServerInfo(options: { database: string; }) => Promise<{ port: number; token: string; }>
|
|
422
|
+
getServerInfo(options: { database: string; }) => Promise<{ port: number; token: string; persistent?: boolean; }>
|
|
423
423
|
```
|
|
424
424
|
|
|
425
425
|
Get the HTTP server port and token for direct communication.
|
|
@@ -428,7 +428,7 @@ Get the HTTP server port and token for direct communication.
|
|
|
428
428
|
| ------------- | ---------------------------------- | --------------- |
|
|
429
429
|
| **`options`** | <code>{ database: string; }</code> | - Database name |
|
|
430
430
|
|
|
431
|
-
**Returns:** <code>Promise<{ port: number; token: string; }></code>
|
|
431
|
+
**Returns:** <code>Promise<{ port: number; token: string; persistent?: boolean; }></code>
|
|
432
432
|
|
|
433
433
|
**Since:** 0.0.1
|
|
434
434
|
|
|
@@ -548,14 +548,14 @@ or supply a custom Worker. This method is a no-op on iOS and Android.
|
|
|
548
548
|
|
|
549
549
|
Database connection options
|
|
550
550
|
|
|
551
|
-
| Prop | Type | Description
|
|
552
|
-
| ------------------------ | -------------------- |
|
|
553
|
-
| **`database`** | <code>string</code> | Database name (file will be created in app data directory)
|
|
554
|
-
| **`encrypted`** | <code>boolean</code> | Enable encryption (iOS/Android only)
|
|
555
|
-
| **`encryptionKey`** | <code>string</code> | Encryption key (required if encrypted is true)
|
|
556
|
-
| **`readOnly`** | <code>boolean</code> |
|
|
557
|
-
| **`walMode`** | <code>boolean</code> | Enable WAL (Write-Ahead Logging) journal mode for better concurrency and performance. Executes `PRAGMA journal_mode = WAL` immediately after opening the database.
|
|
558
|
-
| **`performancePresets`** | <code>boolean</code> | Apply recommended SQLite performance PRAGMAs after opening the database: `synchronous = NORMAL`, `busy_timeout = 5000`, `cache_size = -2000`, and `foreign_keys = ON`.
|
|
551
|
+
| Prop | Type | Description | Since |
|
|
552
|
+
| ------------------------ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
|
|
553
|
+
| **`database`** | <code>string</code> | Database name (file will be created in app data directory) | |
|
|
554
|
+
| **`encrypted`** | <code>boolean</code> | Enable encryption (iOS/Android only) | |
|
|
555
|
+
| **`encryptionKey`** | <code>string</code> | Encryption key (required if encrypted is true) | |
|
|
556
|
+
| **`readOnly`** | <code>boolean</code> | Open an existing native database read-only. Writes and missing-file opens fail. WAL mode changes are skipped for read-only connections. The web Worker transport rejects this option instead of silently opening writable. | |
|
|
557
|
+
| **`walMode`** | <code>boolean</code> | Enable WAL (Write-Ahead Logging) journal mode for better concurrency and performance. Executes `PRAGMA journal_mode = WAL` immediately after opening the database. | 8.0.49 |
|
|
558
|
+
| **`performancePresets`** | <code>boolean</code> | Apply recommended SQLite performance PRAGMAs after opening the database: `synchronous = NORMAL`, `busy_timeout = 5000`, `cache_size = -2000`, and `foreign_keys = ON`. | 8.0.49 |
|
|
559
559
|
|
|
560
560
|
|
|
561
561
|
#### SQLResult
|
|
@@ -658,10 +658,11 @@ OPFS persistence requires Cross-Origin Isolation headers on your web server:
|
|
|
658
658
|
`Cross-Origin-Opener-Policy: same-origin` and
|
|
659
659
|
`Cross-Origin-Embedder-Policy: require-corp`.
|
|
660
660
|
|
|
661
|
-
| Prop
|
|
662
|
-
|
|
|
663
|
-
| **`useOpfs`**
|
|
664
|
-
| **`
|
|
661
|
+
| Prop | Type | Description | Default |
|
|
662
|
+
| ------------------------ | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ |
|
|
663
|
+
| **`useOpfs`** | <code>boolean</code> | Prefer OPFS persistence via a Web Worker (default: `true`). When OPFS is unavailable, the plugin falls back to a non-persistent database and logs a warning. | <code>true</code> |
|
|
664
|
+
| **`requirePersistence`** | <code>boolean</code> | Reject web connections unless the Worker confirms persistent storage. Defaults to false for compatibility. Consider requiring persistence by default in the next Capacitor major, rather than changing fallback behavior in a minor. | <code>false</code> |
|
|
665
|
+
| **`worker`** | <code><a href="#sqlitewebworker">SqliteWebWorker</a></code> | Custom Worker instance or factory for SQLite Wasm. Advanced: override the default worker from `@sqlite.org/sqlite-wasm`. | |
|
|
665
666
|
|
|
666
667
|
|
|
667
668
|
### Type Aliases
|
package/android/build.gradle
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Consumer ProGuard rules for @capgo/capacitor-fast-sql (merged into app R8 when this AAR is a dependency).
|
|
2
|
+
|
|
3
|
+
# CapgoCapacitorFastSqlPlugin uses Class.forName on this class when encrypted databases are enabled.
|
|
4
|
+
# R8 must keep the type so the optional SQLCipher dependency still resolves at runtime.
|
|
5
|
+
-keep class net.zetetic.database.sqlcipher.SQLiteDatabase { *; }
|
|
6
|
+
|
|
7
|
+
# SQLCipher is compileOnly and also exposes types such as DatabaseErrorHandler
|
|
8
|
+
# directly under net.zetetic.database. Plain-SQLite apps omit the entire artifact.
|
|
9
|
+
-dontwarn net.zetetic.database.**
|
|
10
|
+
|
|
11
|
+
# EncryptedSQLDatabase loads the SQLCipher JNI library by name; keep JNI method names linked from Java.
|
|
12
|
+
-keepclasseswithmembernames class * {
|
|
13
|
+
native <methods>;
|
|
14
|
+
}
|
|
@@ -19,7 +19,7 @@ import java.util.Map;
|
|
|
19
19
|
@CapacitorPlugin(name = "CapgoCapacitorFastSql")
|
|
20
20
|
public class CapgoCapacitorFastSqlPlugin extends Plugin {
|
|
21
21
|
|
|
22
|
-
private final String pluginVersion = "8.2.
|
|
22
|
+
private final String pluginVersion = "8.2.18";
|
|
23
23
|
|
|
24
24
|
private Map<String, DatabaseConnection> databases = new HashMap<>();
|
|
25
25
|
private SQLHTTPServer server;
|
|
@@ -31,6 +31,7 @@ public class CapgoCapacitorFastSqlPlugin extends Plugin {
|
|
|
31
31
|
call.reject("Database name is required");
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
+
boolean readOnly = call.getBoolean("readOnly", false);
|
|
34
35
|
boolean encrypted = call.getBoolean("encrypted", false);
|
|
35
36
|
String encryptionKey = call.getString("encryptionKey");
|
|
36
37
|
boolean walMode = call.getBoolean("walMode", false);
|
|
@@ -42,6 +43,10 @@ public class CapgoCapacitorFastSqlPlugin extends Plugin {
|
|
|
42
43
|
|
|
43
44
|
// Check if already connected
|
|
44
45
|
if (databases.containsKey(database)) {
|
|
46
|
+
if (databases.get(database).isReadOnly() != readOnly) {
|
|
47
|
+
call.reject("Database is already open with a different readOnly option");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
45
50
|
if (server != null) {
|
|
46
51
|
JSObject ret = new JSObject();
|
|
47
52
|
ret.put("port", server.getPort());
|
|
@@ -69,9 +74,9 @@ public class CapgoCapacitorFastSqlPlugin extends Plugin {
|
|
|
69
74
|
);
|
|
70
75
|
return;
|
|
71
76
|
}
|
|
72
|
-
db = new EncryptedSQLDatabase(dbFile.getAbsolutePath(), encryptionKey, walMode, performancePresets);
|
|
77
|
+
db = new EncryptedSQLDatabase(dbFile.getAbsolutePath(), encryptionKey, walMode, performancePresets, readOnly);
|
|
73
78
|
} else {
|
|
74
|
-
db = new SQLDatabase(dbFile.getAbsolutePath(), walMode, performancePresets);
|
|
79
|
+
db = new SQLDatabase(dbFile.getAbsolutePath(), walMode, performancePresets, readOnly);
|
|
75
80
|
}
|
|
76
81
|
databases.put(database, db);
|
|
77
82
|
|
|
@@ -173,6 +178,10 @@ public class CapgoCapacitorFastSqlPlugin extends Plugin {
|
|
|
173
178
|
|
|
174
179
|
@PluginMethod
|
|
175
180
|
public void beginTransaction(PluginCall call) {
|
|
181
|
+
if (!"SERIALIZABLE".equals(call.getString("isolationLevel", "SERIALIZABLE"))) {
|
|
182
|
+
call.reject("Only SERIALIZABLE transaction isolation is supported");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
176
185
|
String database = call.getString("database");
|
|
177
186
|
if (database == null) {
|
|
178
187
|
call.reject("Database name is required");
|
|
@@ -250,8 +259,22 @@ public class CapgoCapacitorFastSqlPlugin extends Plugin {
|
|
|
250
259
|
call.resolve(ret);
|
|
251
260
|
}
|
|
252
261
|
|
|
253
|
-
private File getDatabasePath(String database) {
|
|
254
|
-
|
|
255
|
-
|
|
262
|
+
private File getDatabasePath(String database) throws java.io.IOException {
|
|
263
|
+
if (
|
|
264
|
+
database.isEmpty() ||
|
|
265
|
+
database.equals(".") ||
|
|
266
|
+
database.equals("..") ||
|
|
267
|
+
database.indexOf('/') >= 0 ||
|
|
268
|
+
database.indexOf('\\') >= 0 ||
|
|
269
|
+
database.indexOf(0) >= 0
|
|
270
|
+
) {
|
|
271
|
+
throw new java.io.IOException("Database must be a non-empty file name without path separators");
|
|
272
|
+
}
|
|
273
|
+
File dataDir = getContext().getFilesDir().getCanonicalFile();
|
|
274
|
+
File dbFile = new File(dataDir, database + ".db").getCanonicalFile();
|
|
275
|
+
if (!dataDir.equals(dbFile.getParentFile())) {
|
|
276
|
+
throw new java.io.IOException("Database path must remain inside app storage");
|
|
277
|
+
}
|
|
278
|
+
return dbFile;
|
|
256
279
|
}
|
|
257
280
|
}
|
|
@@ -5,9 +5,9 @@ import android.util.Base64;
|
|
|
5
5
|
import com.getcapacitor.JSArray;
|
|
6
6
|
import com.getcapacitor.JSObject;
|
|
7
7
|
import java.nio.charset.StandardCharsets;
|
|
8
|
-
import
|
|
9
|
-
import java.util.List;
|
|
8
|
+
import net.zetetic.database.sqlcipher.SQLiteCursor;
|
|
10
9
|
import net.zetetic.database.sqlcipher.SQLiteDatabase;
|
|
10
|
+
import net.zetetic.database.sqlcipher.SQLiteProgram;
|
|
11
11
|
import net.zetetic.database.sqlcipher.SQLiteStatement;
|
|
12
12
|
import org.json.JSONObject;
|
|
13
13
|
|
|
@@ -20,6 +20,11 @@ public class EncryptedSQLDatabase implements DatabaseConnection {
|
|
|
20
20
|
private volatile boolean inTransaction = false;
|
|
21
21
|
|
|
22
22
|
public EncryptedSQLDatabase(String path, String encryptionKey, boolean walMode, boolean performancePresets) throws Exception {
|
|
23
|
+
this(path, encryptionKey, walMode, performancePresets, false);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public EncryptedSQLDatabase(String path, String encryptionKey, boolean walMode, boolean performancePresets, boolean readOnly)
|
|
27
|
+
throws Exception {
|
|
23
28
|
if (encryptionKey == null || encryptionKey.isEmpty()) {
|
|
24
29
|
throw new Exception("Encryption key is required when encrypted is true");
|
|
25
30
|
}
|
|
@@ -34,8 +39,14 @@ public class EncryptedSQLDatabase implements DatabaseConnection {
|
|
|
34
39
|
);
|
|
35
40
|
}
|
|
36
41
|
byte[] keyBytes = encryptionKey.getBytes(StandardCharsets.UTF_8);
|
|
37
|
-
this.db =
|
|
38
|
-
|
|
42
|
+
this.db = readOnly
|
|
43
|
+
? SQLiteDatabase.openDatabase(path, keyBytes, null, SQLiteDatabase.OPEN_READONLY, null)
|
|
44
|
+
: SQLiteDatabase.openOrCreateDatabase(path, keyBytes, null, null);
|
|
45
|
+
SQLPerformanceConfig.apply(db::execSQL, walMode && !readOnly, performancePresets);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public boolean isReadOnly() {
|
|
49
|
+
return db.isReadOnly();
|
|
39
50
|
}
|
|
40
51
|
|
|
41
52
|
public void close() {
|
|
@@ -49,23 +60,24 @@ public class EncryptedSQLDatabase implements DatabaseConnection {
|
|
|
49
60
|
throw new Exception("Database is not open");
|
|
50
61
|
}
|
|
51
62
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
Cursor cursor = db.rawQueryWithFactory(
|
|
64
|
+
(database, driver, editTable, query) -> {
|
|
65
|
+
try {
|
|
66
|
+
bindParams(query, params);
|
|
67
|
+
} catch (Exception error) {
|
|
68
|
+
throw new IllegalArgumentException("Invalid query parameters", error);
|
|
69
|
+
}
|
|
70
|
+
return new SQLiteCursor(driver, editTable, query);
|
|
71
|
+
},
|
|
72
|
+
statement,
|
|
73
|
+
new String[0],
|
|
74
|
+
null
|
|
75
|
+
);
|
|
65
76
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
if (cursor.getColumnCount() == 0) {
|
|
78
|
+
cursor.close();
|
|
79
|
+
return executeUpdate(statement, params);
|
|
80
|
+
}
|
|
69
81
|
JSArray rows = new JSArray();
|
|
70
82
|
while (cursor.moveToNext()) {
|
|
71
83
|
JSObject row = new JSObject();
|
|
@@ -142,32 +154,7 @@ public class EncryptedSQLDatabase implements DatabaseConnection {
|
|
|
142
154
|
inTransaction = false;
|
|
143
155
|
}
|
|
144
156
|
|
|
145
|
-
private
|
|
146
|
-
if (params == null || params.length() == 0) {
|
|
147
|
-
return new String[0];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
List<String> args = new ArrayList<>();
|
|
151
|
-
for (int i = 0; i < params.length(); i++) {
|
|
152
|
-
Object value = params.get(i);
|
|
153
|
-
|
|
154
|
-
if (value == null || value == JSONObject.NULL) {
|
|
155
|
-
args.add(null);
|
|
156
|
-
} else if (value instanceof JSONObject) {
|
|
157
|
-
JSONObject obj = (JSONObject) value;
|
|
158
|
-
if (obj.has("_type") && "binary".equals(obj.getString("_type"))) {
|
|
159
|
-
args.add(obj.getString("_data"));
|
|
160
|
-
} else {
|
|
161
|
-
args.add(value.toString());
|
|
162
|
-
}
|
|
163
|
-
} else {
|
|
164
|
-
args.add(value.toString());
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return args.toArray(new String[0]);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
private void bindParams(SQLiteStatement stmt, JSArray params) throws Exception {
|
|
157
|
+
private void bindParams(SQLiteProgram stmt, JSArray params) throws Exception {
|
|
171
158
|
if (params == null || params.length() == 0) {
|
|
172
159
|
return;
|
|
173
160
|
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
package app.capgo.capacitor.fastsql;
|
|
2
2
|
|
|
3
3
|
import android.database.Cursor;
|
|
4
|
+
import android.database.sqlite.SQLiteCursor;
|
|
4
5
|
import android.database.sqlite.SQLiteDatabase;
|
|
6
|
+
import android.database.sqlite.SQLiteProgram;
|
|
5
7
|
import android.database.sqlite.SQLiteStatement;
|
|
6
8
|
import android.util.Base64;
|
|
7
9
|
import com.getcapacitor.JSArray;
|
|
8
10
|
import com.getcapacitor.JSObject;
|
|
9
|
-
import java.util.ArrayList;
|
|
10
|
-
import java.util.List;
|
|
11
11
|
import org.json.JSONArray;
|
|
12
|
-
import org.json.JSONException;
|
|
13
12
|
import org.json.JSONObject;
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -21,8 +20,18 @@ public class SQLDatabase implements DatabaseConnection {
|
|
|
21
20
|
private volatile boolean inTransaction = false;
|
|
22
21
|
|
|
23
22
|
public SQLDatabase(String path, boolean walMode, boolean performancePresets) throws Exception {
|
|
24
|
-
this
|
|
25
|
-
|
|
23
|
+
this(path, walMode, performancePresets, false);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public SQLDatabase(String path, boolean walMode, boolean performancePresets, boolean readOnly) throws Exception {
|
|
27
|
+
this.db = readOnly
|
|
28
|
+
? SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY)
|
|
29
|
+
: SQLiteDatabase.openOrCreateDatabase(path, null);
|
|
30
|
+
SQLPerformanceConfig.apply(db::execSQL, walMode && !readOnly, performancePresets);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public boolean isReadOnly() {
|
|
34
|
+
return db.isReadOnly();
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
public void close() {
|
|
@@ -36,25 +45,24 @@ public class SQLDatabase implements DatabaseConnection {
|
|
|
36
45
|
throw new Exception("Database is not open");
|
|
37
46
|
}
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Cursor cursor = null;
|
|
48
|
+
Cursor cursor = db.rawQueryWithFactory(
|
|
49
|
+
(database, driver, editTable, query) -> {
|
|
50
|
+
try {
|
|
51
|
+
bindParams(query, params);
|
|
52
|
+
} catch (Exception error) {
|
|
53
|
+
throw new IllegalArgumentException("Invalid query parameters", error);
|
|
54
|
+
}
|
|
55
|
+
return new SQLiteCursor(driver, editTable, query);
|
|
56
|
+
},
|
|
57
|
+
statement,
|
|
58
|
+
new String[0],
|
|
59
|
+
null
|
|
60
|
+
);
|
|
53
61
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
if (cursor.getColumnCount() == 0) {
|
|
63
|
+
cursor.close();
|
|
64
|
+
return executeUpdate(statement, params);
|
|
65
|
+
}
|
|
58
66
|
// Build result
|
|
59
67
|
JSArray rows = new JSArray();
|
|
60
68
|
while (cursor.moveToNext()) {
|
|
@@ -136,33 +144,7 @@ public class SQLDatabase implements DatabaseConnection {
|
|
|
136
144
|
inTransaction = false;
|
|
137
145
|
}
|
|
138
146
|
|
|
139
|
-
private
|
|
140
|
-
if (params == null || params.length() == 0) {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
List<String> args = new ArrayList<>();
|
|
145
|
-
for (int i = 0; i < params.length(); i++) {
|
|
146
|
-
Object value = params.get(i);
|
|
147
|
-
if (value == null || value == JSONObject.NULL) {
|
|
148
|
-
args.add(null);
|
|
149
|
-
} else if (value instanceof JSONObject) {
|
|
150
|
-
JSONObject obj = (JSONObject) value;
|
|
151
|
-
if (obj.has("_type") && "binary".equals(obj.getString("_type"))) {
|
|
152
|
-
// For queries, we can't bind binary data as string
|
|
153
|
-
// This is a limitation - for binary data, use executeUpdate
|
|
154
|
-
args.add(obj.getString("_data"));
|
|
155
|
-
} else {
|
|
156
|
-
args.add(value.toString());
|
|
157
|
-
}
|
|
158
|
-
} else {
|
|
159
|
-
args.add(value.toString());
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return args.toArray(new String[0]);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
private void bindParams(SQLiteStatement stmt, JSArray params) throws Exception {
|
|
147
|
+
private void bindParams(SQLiteProgram stmt, JSArray params) throws Exception {
|
|
166
148
|
if (params == null || params.length() == 0) {
|
|
167
149
|
return;
|
|
168
150
|
}
|
|
@@ -33,7 +33,7 @@ public class SQLHTTPServer extends NanoHTTPD {
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
public SQLHTTPServer(Map<String, DatabaseConnection> databases) throws IOException {
|
|
36
|
-
super(
|
|
36
|
+
super("127.0.0.1", 0);
|
|
37
37
|
this.databases = databases;
|
|
38
38
|
this.token = generateToken();
|
|
39
39
|
}
|
|
@@ -152,14 +152,22 @@ public class SQLHTTPServer extends NanoHTTPD {
|
|
|
152
152
|
HttpRequestJsonParams.populateJsArrayFromParamsJson(paramsJson, params, rawParamsArray);
|
|
153
153
|
|
|
154
154
|
JSObject result = db.execute(statement, params);
|
|
155
|
-
results.put(
|
|
155
|
+
results.put(result);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
return newFixedLengthResponse(Response.Status.OK, "application/json", results.toString());
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
private Response handleBeginTransaction(IHTTPSession session, DatabaseConnection db) throws Exception {
|
|
162
|
-
readRequestBody(session);
|
|
162
|
+
String body = readRequestBody(session);
|
|
163
|
+
JSONObject request = body.isEmpty() ? new JSONObject() : new JSONObject(body);
|
|
164
|
+
if (!"SERIALIZABLE".equals(request.optString("isolationLevel", "SERIALIZABLE"))) {
|
|
165
|
+
return newFixedLengthResponse(
|
|
166
|
+
Response.Status.BAD_REQUEST,
|
|
167
|
+
"text/plain",
|
|
168
|
+
"Only SERIALIZABLE transaction isolation is supported"
|
|
169
|
+
);
|
|
170
|
+
}
|
|
163
171
|
db.beginTransaction();
|
|
164
172
|
return newFixedLengthResponse(Response.Status.OK, "application/json", "{}");
|
|
165
173
|
}
|
|
@@ -193,24 +201,4 @@ public class SQLHTTPServer extends NanoHTTPD {
|
|
|
193
201
|
}
|
|
194
202
|
return sb.toString();
|
|
195
203
|
}
|
|
196
|
-
|
|
197
|
-
private static int findAvailablePort() {
|
|
198
|
-
// Try ports in the range 9000-9100
|
|
199
|
-
for (int port = 9000; port < 9100; port++) {
|
|
200
|
-
try {
|
|
201
|
-
NanoHTTPD testServer = new NanoHTTPD(port) {
|
|
202
|
-
@Override
|
|
203
|
-
public Response serve(IHTTPSession session) {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
testServer.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
|
|
208
|
-
testServer.stop();
|
|
209
|
-
return port;
|
|
210
|
-
} catch (IOException e) {
|
|
211
|
-
// Port not available, try next one
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return 9000; // Fallback
|
|
215
|
-
}
|
|
216
204
|
}
|
|
@@ -55,7 +55,9 @@ export interface SQLConnectionOptions {
|
|
|
55
55
|
*/
|
|
56
56
|
encryptionKey?: string;
|
|
57
57
|
/**
|
|
58
|
-
*
|
|
58
|
+
* Open an existing native database read-only. Writes and missing-file opens fail.
|
|
59
|
+
* WAL mode changes are skipped for read-only connections.
|
|
60
|
+
* The web Worker transport rejects this option instead of silently opening writable.
|
|
59
61
|
*/
|
|
60
62
|
readOnly?: boolean;
|
|
61
63
|
/**
|
|
@@ -94,6 +96,13 @@ export interface WebConfig {
|
|
|
94
96
|
* @default true
|
|
95
97
|
*/
|
|
96
98
|
useOpfs?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Reject web connections unless the Worker confirms persistent storage.
|
|
101
|
+
* Defaults to false for compatibility. Consider requiring persistence by default
|
|
102
|
+
* in the next Capacitor major, rather than changing fallback behavior in a minor.
|
|
103
|
+
* @default false
|
|
104
|
+
*/
|
|
105
|
+
requirePersistence?: boolean;
|
|
97
106
|
/**
|
|
98
107
|
* Custom Worker instance or factory for SQLite Wasm.
|
|
99
108
|
* Advanced: override the default worker from `@sqlite.org/sqlite-wasm`.
|
|
@@ -101,7 +110,9 @@ export interface WebConfig {
|
|
|
101
110
|
worker?: SqliteWebWorker;
|
|
102
111
|
}
|
|
103
112
|
/**
|
|
104
|
-
* Transaction isolation levels
|
|
113
|
+
* Transaction isolation levels. Only Serializable is supported by the current
|
|
114
|
+
* SQLite backends. Other values are retained for source compatibility but reject
|
|
115
|
+
* before starting a transaction; they are not silently mapped to another level.
|
|
105
116
|
*/
|
|
106
117
|
export declare enum IsolationLevel {
|
|
107
118
|
ReadUncommitted = "READ UNCOMMITTED",
|
|
@@ -135,6 +146,8 @@ export interface CapgoCapacitorFastSqlPlugin {
|
|
|
135
146
|
port: number;
|
|
136
147
|
token: string;
|
|
137
148
|
database: string;
|
|
149
|
+
/** Whether the web Worker confirms persistent storage. Absent on native. */
|
|
150
|
+
persistent?: boolean;
|
|
138
151
|
}>;
|
|
139
152
|
/**
|
|
140
153
|
* Close database connection and stop the HTTP server.
|
|
@@ -169,6 +182,8 @@ export interface CapgoCapacitorFastSqlPlugin {
|
|
|
169
182
|
}): Promise<{
|
|
170
183
|
port: number;
|
|
171
184
|
token: string;
|
|
185
|
+
/** Whether the web Worker confirms persistent storage. Absent on native. */
|
|
186
|
+
persistent?: boolean;
|
|
172
187
|
}>;
|
|
173
188
|
/**
|
|
174
189
|
* Execute a SQL query via Capacitor bridge (for simple queries).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,UAAU,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,EAAE,CAAC;IAEf;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/definitions.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Transaction isolation levels
|
|
2
|
+
* Transaction isolation levels. Only Serializable is supported by the current
|
|
3
|
+
* SQLite backends. Other values are retained for source compatibility but reject
|
|
4
|
+
* before starting a transaction; they are not silently mapped to another level.
|
|
3
5
|
*/
|
|
4
6
|
export var IsolationLevel;
|
|
5
7
|
(function (IsolationLevel) {
|
package/dist/esm/fast-sql.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ import type { SQLConnection } from './sql-connection';
|
|
|
7
7
|
* and managing multiple databases simultaneously.
|
|
8
8
|
*/
|
|
9
9
|
export declare class FastSQL {
|
|
10
|
+
private static opening;
|
|
11
|
+
private static openOptions;
|
|
10
12
|
private static connections;
|
|
11
13
|
private static sharedConnections;
|
|
12
14
|
private static connectionRetainers;
|
|
@@ -18,6 +20,8 @@ export declare class FastSQL {
|
|
|
18
20
|
* @returns SQLConnection instance for executing queries
|
|
19
21
|
*/
|
|
20
22
|
static connect(options: SQLConnectionOptions): Promise<SQLConnection>;
|
|
23
|
+
private static optionsMatch;
|
|
24
|
+
private static open;
|
|
21
25
|
/**
|
|
22
26
|
* Close a database connection
|
|
23
27
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fast-sql.d.ts","sourceRoot":"","sources":["../../src/fast-sql.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAG1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD;;;;;GAKG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAC,WAAW,CAAyC;IACnE,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA0B;IAC1D,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAkC;IACpE,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAA0B;IAE3D;;;;;OAKG;WACU,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC;IA0B3E;;;;OAIG;WACU,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"fast-sql.d.ts","sourceRoot":"","sources":["../../src/fast-sql.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAG1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD;;;;;GAKG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAC,OAAO,CAA6C;IACnE,OAAO,CAAC,MAAM,CAAC,WAAW,CAA2C;IACrE,OAAO,CAAC,MAAM,CAAC,WAAW,CAAyC;IACnE,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA0B;IAC1D,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAkC;IACpE,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAA0B;IAE3D;;;;;OAKG;WACU,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC;IA0B3E,OAAO,CAAC,MAAM,CAAC,YAAY;mBAUN,IAAI;IAmBzB;;;;OAIG;WACU,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBxD;;;;;OAKG;IACH,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAI5D;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIpD;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAO/C;;OAEG;WACU,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBlE;;OAEG;WACU,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3C;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,IAAI,MAAM,EAAE;CAGpC"}
|