@capacitor-community/sqlite 5.7.2 → 5.7.3-2
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 +8 -2
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/Database.java +3 -3
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsDownloadFromHTTP.java +71 -46
- package/electron/dist/plugin.js +37 -27
- package/electron/dist/plugin.js.map +1 -1
- package/ios/Plugin/CapacitorSQLite.swift +13 -12
- package/ios/Plugin/CapacitorSQLitePlugin.swift +9 -14
- package/ios/Plugin/Utils/UtilsBinding.swift +2 -3
- package/ios/Plugin/Utils/UtilsDelete.swift +25 -12
- package/ios/Plugin/Utils/UtilsDownloadFromHTTP.swift +168 -98
- package/ios/Plugin/Utils/UtilsJson.swift +6 -6
- package/ios/Plugin/Utils/UtilsSQLCipher.swift +4 -4
- package/ios/Plugin/Utils/UtilsSQLStatement.swift +284 -90
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<a href="https://www.npmjs.com/package/@capacitor-community/sqlite"><img src="https://img.shields.io/npm/dw/@capacitor-community/sqlite?style=flat-square" /></a>
|
|
19
19
|
<a href="https://www.npmjs.com/package/@capacitor-community/sqlite"><img src="https://img.shields.io/npm/v/@capacitor-community/sqlite?style=flat-square" /></a>
|
|
20
20
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
21
|
-
<a href="#contributors-"><img src="https://img.shields.io/badge/all%20contributors-
|
|
21
|
+
<a href="#contributors-"><img src="https://img.shields.io/badge/all%20contributors-43-orange?style=flat-square" /></a>
|
|
22
22
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
23
23
|
</p>
|
|
24
24
|
|
|
@@ -357,7 +357,7 @@ npm install --save-dev electron-builder@24.6.4
|
|
|
357
357
|
|
|
358
358
|
The iOS and Android codes are using `SQLCipher` allowing for database encryption.
|
|
359
359
|
The iOS codes is using `ZIPFoundation` for unzipping assets files
|
|
360
|
-
The Electron code is using `better-sqlite3-multiple-ciphers` , `electron-json-storage and `node-fetch` from 5.0.4.
|
|
360
|
+
The Electron code is using `better-sqlite3-multiple-ciphers` , `electron-json-storage` and `node-fetch` from 5.0.4.
|
|
361
361
|
The Web code is using the Stencil component `jeep-sqlite` based on `sql.js`, `localforage`. and `jszip`
|
|
362
362
|
|
|
363
363
|
## Contributors ✨
|
|
@@ -408,6 +408,12 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|
|
408
408
|
<a href="https://github.com/DawidWetzler" title="DawidWetzler"><img src="https://avatars.githubusercontent.com/u/49675685?v=4" width="50" height="50" /></a>
|
|
409
409
|
<a href="https://github.com/mmouterde" title="mmouterde"><img src="https://avatars.githubusercontent.com/u/733538?v=4" width="50" height="50" /></a>
|
|
410
410
|
<a href="https://github.com/msfstef" title="msfstef"><img src="https://avatars.githubusercontent.com/u/12274098?v=4" width="50" height="50" /></a>
|
|
411
|
+
<a href="https://github.com/ChrisHSandN" title="
|
|
412
|
+
ChrisHSandN"><img src="https://avatars.githubusercontent.com/u/13466620?v=4" width="50" height="50" /></a>
|
|
413
|
+
<a href="https://github.com/lasher23" title="
|
|
414
|
+
lasher23"><img src="https://avatars.githubusercontent.com/u/24244618?v=4" width="50" height="50" /></a>
|
|
415
|
+
<a href="https://github.com/mirsella" title="
|
|
416
|
+
mirsella"><img src="https://avatars.githubusercontent.com/u/45905567?v=4" width="50" height="50" /></a>
|
|
411
417
|
</p>
|
|
412
418
|
|
|
413
419
|
|
package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/Database.java
CHANGED
|
@@ -12,6 +12,7 @@ import static com.getcapacitor.community.database.sqlite.SQLite.UtilsSQLStatemen
|
|
|
12
12
|
|
|
13
13
|
import android.content.Context;
|
|
14
14
|
import android.content.SharedPreferences;
|
|
15
|
+
import android.database.DatabaseUtils;
|
|
15
16
|
import android.os.Build;
|
|
16
17
|
import android.util.Log;
|
|
17
18
|
import androidx.sqlite.db.SimpleSQLiteQuery;
|
|
@@ -503,7 +504,7 @@ public class Database {
|
|
|
503
504
|
String elementValue = "";
|
|
504
505
|
|
|
505
506
|
if (innerElement instanceof String) {
|
|
506
|
-
elementValue =
|
|
507
|
+
elementValue = DatabaseUtils.sqlEscapeString((String) innerElement);
|
|
507
508
|
} else {
|
|
508
509
|
elementValue = String.valueOf(innerElement);
|
|
509
510
|
}
|
|
@@ -520,7 +521,6 @@ public class Database {
|
|
|
520
521
|
sqlBuilder.append(",");
|
|
521
522
|
}
|
|
522
523
|
}
|
|
523
|
-
sqlBuilder.append(";");
|
|
524
524
|
String questionMark = extractQuestionMarkValues(statement);
|
|
525
525
|
String finalSql = "";
|
|
526
526
|
if (questionMark != null) {
|
|
@@ -537,7 +537,7 @@ public class Database {
|
|
|
537
537
|
}
|
|
538
538
|
|
|
539
539
|
public String extractQuestionMarkValues(String input) {
|
|
540
|
-
Pattern pattern = Pattern.compile("VALUES \\((\\?(?:,\\s*\\?\\s*)*)\\)");
|
|
540
|
+
Pattern pattern = Pattern.compile("(?i)VALUES \\((\\?(?:,\\s*\\?\\s*)*)\\)");
|
|
541
541
|
Matcher matcher = pattern.matcher(input);
|
|
542
542
|
|
|
543
543
|
if (matcher.find()) {
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
package com.getcapacitor.community.database.sqlite.SQLite;
|
|
2
2
|
|
|
3
|
+
import java.net.MalformedURLException;
|
|
3
4
|
import android.content.Context;
|
|
4
|
-
import android.content.res.AssetManager;
|
|
5
5
|
import java.io.File;
|
|
6
6
|
import java.io.FileOutputStream;
|
|
7
7
|
import java.io.IOException;
|
|
8
8
|
import java.io.InputStream;
|
|
9
9
|
import java.net.HttpURLConnection;
|
|
10
10
|
import java.net.URL;
|
|
11
|
+
import java.util.regex.Matcher;
|
|
12
|
+
import java.util.regex.Pattern;
|
|
13
|
+
import java.net.URLDecoder;
|
|
14
|
+
import java.nio.charset.StandardCharsets;
|
|
11
15
|
|
|
12
16
|
public class UtilsDownloadFromHTTP {
|
|
13
17
|
|
|
@@ -16,34 +20,46 @@ public class UtilsDownloadFromHTTP {
|
|
|
16
20
|
private final UtilsFile _uFile = new UtilsFile();
|
|
17
21
|
|
|
18
22
|
public void download(Context context, String fileUrl) throws Exception {
|
|
19
|
-
|
|
20
|
-
String fileName =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
Boolean isZip = false;
|
|
24
|
+
String fileName = "";
|
|
25
|
+
try {
|
|
26
|
+
String[] fileDetails = getFileDetails(fileUrl);
|
|
27
|
+
fileName = fileDetails[0];
|
|
28
|
+
String extension = fileDetails[1];
|
|
29
|
+
if (!fileName.contains("SQLite.db")) {
|
|
30
|
+
switch(extension) {
|
|
31
|
+
case "db":
|
|
32
|
+
fileName = fileName.substring(0, fileName.length() - 3) + "SQLite.db";
|
|
33
|
+
break;
|
|
34
|
+
case "zip":
|
|
35
|
+
isZip = true;
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
throw new Exception("Unknown file type. Filename: " + fileName);
|
|
39
|
+
}
|
|
29
40
|
}
|
|
41
|
+
|
|
42
|
+
} catch (Exception e) {
|
|
43
|
+
throw new Exception(e.getMessage());
|
|
30
44
|
}
|
|
45
|
+
|
|
46
|
+
|
|
31
47
|
File cacheDir = context.getCacheDir();
|
|
32
48
|
String cachePath = cacheDir.getAbsolutePath();
|
|
33
|
-
String tmpFilePath = cachePath + File.separator +
|
|
49
|
+
String tmpFilePath = cachePath + File.separator + fileName;
|
|
34
50
|
String databasePath = _uFile.getDatabaseDirectoryPath(context);
|
|
35
51
|
File databaseDir = new File(databasePath);
|
|
36
52
|
try {
|
|
37
53
|
// delete file if exists in cache
|
|
38
54
|
Boolean isExists = _uFile.isPathExists(tmpFilePath);
|
|
39
55
|
if (isExists) {
|
|
40
|
-
_uFile.deleteFile(cachePath,
|
|
56
|
+
_uFile.deleteFile(cachePath, fileName);
|
|
41
57
|
}
|
|
42
|
-
downloadFileToCache(fileUrl, cachePath);
|
|
58
|
+
downloadFileToCache(fileUrl, fileName, cachePath);
|
|
43
59
|
if (isZip) {
|
|
44
60
|
_uFile.unzipCopyDatabase(cachePath, null, tmpFilePath, true);
|
|
45
61
|
// delete zip file from cache
|
|
46
|
-
_uFile.deleteFile(cachePath,
|
|
62
|
+
_uFile.deleteFile(cachePath, fileName);
|
|
47
63
|
}
|
|
48
64
|
// move files to database folder
|
|
49
65
|
_uFile.moveAllDBs(cacheDir, databaseDir);
|
|
@@ -52,28 +68,41 @@ public class UtilsDownloadFromHTTP {
|
|
|
52
68
|
}
|
|
53
69
|
}
|
|
54
70
|
|
|
55
|
-
public static
|
|
71
|
+
public static String[] getFileDetails(String url) throws Exception {
|
|
72
|
+
try {
|
|
73
|
+
URL javaUrl = new URL(url);
|
|
74
|
+
String path = javaUrl.getPath();
|
|
75
|
+
String decodedPath = URLDecoder.decode(path, StandardCharsets.UTF_8.toString()); // Decode URL-encoded path
|
|
76
|
+
String filename = decodedPath.substring(decodedPath.lastIndexOf('/') + 1); // Extract filename from decoded path
|
|
77
|
+
String extension = getFileExtension(filename);
|
|
78
|
+
if(extension == null) {
|
|
79
|
+
throw new Exception("extension db or zip not found");
|
|
80
|
+
}
|
|
81
|
+
return new String[]{filename, extension};
|
|
82
|
+
} catch (MalformedURLException e) {
|
|
83
|
+
e.printStackTrace();
|
|
84
|
+
throw new Exception(e.getMessage());
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
public static String getFileExtension(String filename) {
|
|
88
|
+
Pattern pattern = Pattern.compile("\\.([a-zA-Z0-9]+)(?:[\\?#]|$)");
|
|
89
|
+
Matcher matcher = pattern.matcher(filename);
|
|
90
|
+
|
|
91
|
+
if (matcher.find()) {
|
|
92
|
+
return matcher.group(1).toLowerCase(); // returns the matched extension in lowercase
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return null; // no extension found
|
|
96
|
+
}
|
|
97
|
+
public static void downloadFileToCache(String fileURL, String fileName, String cacheDir) throws Exception {
|
|
56
98
|
HttpURLConnection httpConn = null;
|
|
57
99
|
try {
|
|
58
100
|
URL url = new URL(fileURL);
|
|
59
101
|
httpConn = (HttpURLConnection) url.openConnection();
|
|
102
|
+
httpConn.setRequestMethod("GET");
|
|
60
103
|
int responseCode = httpConn.getResponseCode();
|
|
61
104
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
|
62
|
-
String fileName = "";
|
|
63
|
-
String disposition = httpConn.getHeaderField("Content-Disposition");
|
|
64
|
-
// String contentType = httpConn.getContentType();
|
|
65
105
|
int contentLength = httpConn.getContentLength();
|
|
66
|
-
|
|
67
|
-
if (disposition != null) {
|
|
68
|
-
// extracts file name from header field
|
|
69
|
-
int index = disposition.indexOf("filename=");
|
|
70
|
-
if (index > 0) {
|
|
71
|
-
fileName = disposition.substring(index + 10, disposition.length() - 1);
|
|
72
|
-
}
|
|
73
|
-
} else {
|
|
74
|
-
// extracts file name from URL
|
|
75
|
-
fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1);
|
|
76
|
-
}
|
|
77
106
|
String dbName = fileName;
|
|
78
107
|
if (!fileName.contains("SQLite.db")) {
|
|
79
108
|
if (fileName.substring(fileName.length() - 3).equals(".db")) {
|
|
@@ -81,26 +110,22 @@ public class UtilsDownloadFromHTTP {
|
|
|
81
110
|
}
|
|
82
111
|
}
|
|
83
112
|
|
|
84
|
-
// System.out.println("Content-Type = " + contentType);
|
|
85
|
-
// System.out.println("Content-Disposition = " + disposition);
|
|
86
|
-
// System.out.println("Content-Length = " + contentLength);
|
|
87
|
-
// System.out.println("fileName = " + fileName);
|
|
88
|
-
// opens input stream from the HTTP connection
|
|
89
|
-
InputStream inputStream = httpConn.getInputStream();
|
|
90
113
|
// create temporary file path
|
|
91
114
|
String tmpFilePath = cacheDir + File.separator + dbName;
|
|
92
|
-
// opens
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
byte[] buffer = new byte[BUFFER_SIZE];
|
|
96
|
-
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
|
97
|
-
outputStream.write(buffer, 0, bytesRead);
|
|
98
|
-
}
|
|
115
|
+
// opens input stream from the HTTP connection
|
|
116
|
+
try (InputStream inputStream = httpConn.getInputStream();
|
|
117
|
+
FileOutputStream outputStream = new FileOutputStream(tmpFilePath)) {
|
|
99
118
|
|
|
100
|
-
|
|
101
|
-
|
|
119
|
+
byte[] buffer = new byte[1024];
|
|
120
|
+
int bytesRead;
|
|
121
|
+
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
|
122
|
+
outputStream.write(buffer, 0, bytesRead);
|
|
123
|
+
}
|
|
124
|
+
outputStream.close();
|
|
125
|
+
inputStream.close();
|
|
102
126
|
|
|
103
|
-
|
|
127
|
+
System.out.println("File " + fileName + " downloaded (" + contentLength + ")");
|
|
128
|
+
}
|
|
104
129
|
} else {
|
|
105
130
|
String msg = "No file to download. Server replied HTTP code: " + responseCode;
|
|
106
131
|
throw new IOException(msg);
|
package/electron/dist/plugin.js
CHANGED
|
@@ -447,10 +447,14 @@ class UtilsFile {
|
|
|
447
447
|
* @returns
|
|
448
448
|
*/
|
|
449
449
|
getExtName(filePath) {
|
|
450
|
-
|
|
450
|
+
const matches = filePath.match(/\.([a-zA-Z0-9]+)(?:[\\?#]|$)/);
|
|
451
|
+
return matches ? `.${matches[1].toLowerCase()}` : ''; // returns the matched extension in lowercase
|
|
452
|
+
// return this.Path.extname(filePath);
|
|
451
453
|
}
|
|
452
454
|
getBaseName(filePath) {
|
|
453
|
-
|
|
455
|
+
const decodedUrl = decodeURIComponent(filePath); // Decode the URL component
|
|
456
|
+
const baseName = this.Path.basename(decodedUrl, this.Path.extname(filePath));
|
|
457
|
+
return baseName;
|
|
454
458
|
}
|
|
455
459
|
/**
|
|
456
460
|
* IsPathExists
|
|
@@ -589,34 +593,38 @@ class UtilsFile {
|
|
|
589
593
|
*/
|
|
590
594
|
async unzipDatabase(db, fPath, overwrite) {
|
|
591
595
|
const pZip = this.Path.join(fPath, db);
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
console.log(err);
|
|
596
|
-
return Promise.reject(`unzipDatabase ${JSON.stringify(err)}`);
|
|
597
|
-
}
|
|
596
|
+
try {
|
|
597
|
+
// Read the Zip file
|
|
598
|
+
const data = await this.NodeFs.promises.readFile(pZip);
|
|
598
599
|
const zip = new this.JSZip();
|
|
599
|
-
zip.loadAsync(data)
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
this.
|
|
600
|
+
const contents = await zip.loadAsync(data);
|
|
601
|
+
// Create an array to store promises for writing files
|
|
602
|
+
const writePromises = [];
|
|
603
|
+
Object.keys(contents.files).forEach(filename => {
|
|
604
|
+
writePromises.push(zip
|
|
605
|
+
.file(filename)
|
|
606
|
+
.async('nodebuffer')
|
|
607
|
+
.then(async (content) => {
|
|
608
|
+
const toDb = this.setPathSuffix(filename);
|
|
609
|
+
const pDb = this.Path.join(this.getDatabasesPath(), toDb);
|
|
610
|
+
// check filePath exists
|
|
611
|
+
const isPath = this.isPathExists(pDb);
|
|
612
|
+
if (!isPath || overwrite) {
|
|
613
|
+
if (overwrite && isPath) {
|
|
614
|
+
await this.deleteFilePath(pDb);
|
|
614
615
|
}
|
|
615
|
-
|
|
616
|
-
}
|
|
617
|
-
});
|
|
616
|
+
await this.NodeFs.promises.writeFile(pDb, content);
|
|
617
|
+
}
|
|
618
|
+
}));
|
|
618
619
|
});
|
|
619
|
-
|
|
620
|
+
// Wait for all write promises to resolve
|
|
621
|
+
await Promise.all(writePromises);
|
|
622
|
+
return Promise.resolve();
|
|
623
|
+
}
|
|
624
|
+
catch (err) {
|
|
625
|
+
console.log(err);
|
|
626
|
+
return Promise.reject(`unzipDatabase ${JSON.stringify(err)}`);
|
|
627
|
+
}
|
|
620
628
|
}
|
|
621
629
|
/**
|
|
622
630
|
* CopyFileName
|
|
@@ -871,6 +879,7 @@ class UtilsFile {
|
|
|
871
879
|
}
|
|
872
880
|
}
|
|
873
881
|
}
|
|
882
|
+
return Promise.resolve();
|
|
874
883
|
}
|
|
875
884
|
/**
|
|
876
885
|
* RestoreFileName
|
|
@@ -5893,6 +5902,7 @@ class CapacitorSQLite {
|
|
|
5893
5902
|
else {
|
|
5894
5903
|
throw new Error(`getFromHTTPRequest: cannot move file from cache overwrite: ${overwrite}`);
|
|
5895
5904
|
}
|
|
5905
|
+
return;
|
|
5896
5906
|
}
|
|
5897
5907
|
async getDatabaseList() {
|
|
5898
5908
|
// get the database folder
|