@capacitor-community/sqlite 5.0.5-2 → 5.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/android/src/main/java/com/getcapacitor/community/database/sqlite/CapacitorSQLite.java +118 -156
  2. package/android/src/main/java/com/getcapacitor/community/database/sqlite/CapacitorSQLitePlugin.java +81 -249
  3. package/android/src/main/java/com/getcapacitor/community/database/sqlite/NotificationCenter.java +1 -1
  4. package/android/src/main/java/com/getcapacitor/community/database/sqlite/RetHandler.java +0 -12
  5. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/Database.java +184 -40
  6. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/ExportToJson.java +141 -135
  7. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/ImportFromJson.java +2 -1
  8. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/UtilsEncryption.java +111 -0
  9. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsBiometric.java +0 -4
  10. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsFile.java +30 -18
  11. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsMigrate.java +12 -4
  12. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsNCDatabase.java +4 -1
  13. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsSQLCipher.java +8 -6
  14. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsSQLite.java +14 -28
  15. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsSecret.java +3 -4
  16. package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsUpgrade.java +0 -1
  17. package/dist/esm/definitions.d.ts +91 -4
  18. package/dist/esm/definitions.js +79 -19
  19. package/dist/esm/definitions.js.map +1 -1
  20. package/dist/esm/web.d.ts +3 -1
  21. package/dist/esm/web.js +8 -0
  22. package/dist/esm/web.js.map +1 -1
  23. package/dist/plugin.cjs.js +87 -19
  24. package/dist/plugin.cjs.js.map +1 -1
  25. package/dist/plugin.js +87 -19
  26. package/dist/plugin.js.map +1 -1
  27. package/electron/dist/plugin.js +333 -148
  28. package/electron/dist/plugin.js.map +1 -1
  29. package/electron/rollup.config.js +2 -0
  30. package/ios/Plugin/CapacitorSQLite.swift +125 -92
  31. package/ios/Plugin/CapacitorSQLitePlugin.swift +6 -3
  32. package/ios/Plugin/Database.swift +45 -19
  33. package/ios/Plugin/ImportExportJson/ExportToJson.swift +10 -5
  34. package/ios/Plugin/ImportExportJson/ImportData.swift +434 -0
  35. package/ios/Plugin/ImportExportJson/ImportFromJson.swift +47 -59
  36. package/ios/Plugin/ImportExportJson/JsonSQLite.swift +7 -0
  37. package/ios/Plugin/Utils/UtilsDownloadFromHTTP.swift +61 -61
  38. package/ios/Plugin/Utils/UtilsDrop.swift +2 -1
  39. package/ios/Plugin/Utils/UtilsJson.swift +123 -1
  40. package/ios/Plugin/Utils/UtilsSQLCipher.swift +254 -23
  41. package/ios/Plugin/Utils/UtilsUpgrade.swift +0 -1
  42. package/package.json +2 -2
  43. package/src/definitions.ts +171 -18
  44. package/src/web.ts +10 -0
@@ -37,6 +37,9 @@ enum UtilsSQLCipherError: Error {
37
37
  case openDBNoPassword(message: String)
38
38
  case openDBStoredPassword(message: String)
39
39
  case openDBGlobalPassword(message: String)
40
+ case returningWorkAround(message: String)
41
+ case getUpdDelReturnedValues(message: String)
42
+ case getFirstPK(message: String)
40
43
  }
41
44
  enum State: String {
42
45
  case DOESNOTEXIST, UNENCRYPTED, ENCRYPTEDSECRET,
@@ -414,20 +417,40 @@ class UtilsSQLCipher {
414
417
  // swiftlint:disable function_body_length
415
418
  // swiftlint:disable cyclomatic_complexity
416
419
  class func prepareSQL(mDB: Database, sql: String, values: [Any],
417
- fromJson: Bool) throws -> Int64 {
420
+ fromJson: Bool, returnMode: String) throws -> (Int64, [[String: Any]]) {
418
421
  var msg: String = "Error prepareSQL: "
419
422
  if !mDB.isDBOpen() {
420
423
  msg.append("Database not opened")
421
424
  throw UtilsSQLCipherError.prepareSQL(message: msg)
422
425
  }
426
+ let systemVersion = UIDevice.current.systemVersion
423
427
  var runSQLStatement: OpaquePointer?
424
428
  var message: String = ""
425
429
  var lastId: Int64 = -1
426
430
  var sqlStmt = sql
431
+ var names: String = ""
432
+ var result: [[String: Any]] = []
433
+ var retMode: String
434
+ if #available(iOS 15, *) {
435
+ retMode = returnMode
436
+ } else {
437
+ retMode = returnMode
438
+ if retMode != "no" {
439
+ retMode = "wA\(retMode)"
440
+ }
441
+ }
442
+
443
+ if (retMode == "no" || retMode.prefix(2) == "wA") &&
444
+ sqlStmt.uppercased().contains("RETURNING") {
445
+ let stmtNames = getStmtAndRetColNames(sqlStmt: sqlStmt,
446
+ retMode: retMode)
447
+ sqlStmt = stmtNames["stmt"] ?? sqlStmt
448
+ names = stmtNames["names"] ?? ""
449
+ }
427
450
  // Check for DELETE statement
428
451
  if !fromJson && sqlStmt.prefix(6).uppercased() == "DELETE" {
429
452
  do {
430
- sqlStmt = try deleteSQL(mDB: mDB, sql: sql,
453
+ sqlStmt = try deleteSQL(mDB: mDB, sql: sqlStmt,
431
454
  values: values)
432
455
  } catch UtilsSQLCipherError.deleteSQL(let message) {
433
456
  let msg = "Error: prepareSQL \(message)"
@@ -438,6 +461,7 @@ class UtilsSQLCipher {
438
461
  mDB.mDb, sqlStmt, -1, &runSQLStatement, nil)
439
462
  if returnCode == SQLITE_OK {
440
463
  if !values.isEmpty {
464
+ // retMode = "no"
441
465
  // do the binding of values
442
466
  var idx: Int = 1
443
467
  for value in values {
@@ -452,12 +476,35 @@ class UtilsSQLCipher {
452
476
  if message.count > 0 { break }
453
477
  }
454
478
  }
455
- returnCode = sqlite3_step(runSQLStatement)
456
- if returnCode != SQLITE_DONE {
457
- let errmsg: String = String(
458
- cString: sqlite3_errmsg(mDB.mDb))
459
- message = "Error: prepareSQL step failed rc: "
460
- message.append("\(returnCode) message: \(errmsg)")
479
+ if retMode == "no" {
480
+ returnCode = sqlite3_step(runSQLStatement)
481
+ if returnCode != SQLITE_DONE {
482
+ let errmsg: String = String(
483
+ cString: sqlite3_errmsg(mDB.mDb))
484
+ message = "Error: prepareSQL step failed rc: "
485
+ message.append("\(returnCode) message: \(errmsg)")
486
+ }
487
+ } else {
488
+ if retMode.prefix(2) == "wA" {
489
+ do {
490
+ result = try UtilsSQLCipher.returningWorkAround(
491
+ mDB: mDB,
492
+ runSQLStatement: runSQLStatement, sqlStmt: sqlStmt,
493
+ names: names, returnMode: retMode)
494
+ } catch UtilsSQLCipherError
495
+ .returningWorkAround(let message) {
496
+ throw UtilsSQLCipherError.prepareSQL(message: message)
497
+ }
498
+ } else {
499
+
500
+ do {
501
+ result = try UtilsSQLCipher.fetchColumnInfo(
502
+ handle: runSQLStatement, returnMode: retMode)
503
+ } catch UtilsSQLCipherError
504
+ .fetchColumnInfo(let message) {
505
+ throw UtilsSQLCipherError.prepareSQL(message: message)
506
+ }
507
+ }
461
508
  }
462
509
  } else {
463
510
  let errmsg: String = String(
@@ -476,9 +523,156 @@ class UtilsSQLCipher {
476
523
  throw UtilsSQLCipherError.prepareSQL(message: message)
477
524
  } else {
478
525
  lastId = Int64(sqlite3_last_insert_rowid(mDB.mDb))
479
- return lastId
526
+ return (lastId, result)
527
+ }
528
+ }
529
+
530
+ // MARK: - getStmtAndRetColNames
531
+
532
+ class func getStmtAndRetColNames(sqlStmt: String, retMode: String) -> [String: String] {
533
+ let retWord = "RETURNING"
534
+
535
+ var retStmtNames: [String: String] = [:]
536
+ retStmtNames["stmt"] = sqlStmt
537
+ retStmtNames["names"] = ""
538
+ if let range = sqlStmt.uppercased().range(of: retWord) {
539
+ let prefix = sqlStmt.prefix(upTo: range.lowerBound)
540
+ retStmtNames["stmt"] = "\(prefix);"
541
+ retStmtNames["names"] = ""
542
+ if retMode.prefix(2) == "wA" {
543
+ let suffix = sqlStmt.suffix(from: range.upperBound)
544
+ let names = "\(suffix)".trimmingLeadingAndTrailingSpaces()
545
+ if names.suffix(1) == ";" {
546
+ retStmtNames["names"] = String(names.dropLast())
547
+ }
548
+ }
549
+
550
+ }
551
+ return retStmtNames
552
+ }
553
+
554
+ // MARK: - returningWorkAround
555
+
556
+ class func returningWorkAround(mDB: Database, runSQLStatement: OpaquePointer?,
557
+ sqlStmt: String, names: String,
558
+ returnMode: String) throws -> [[String: Any]] {
559
+ var result: [[String: Any]] = []
560
+ let initLastId = Int64(sqlite3_last_insert_rowid(mDB.mDb))
561
+ if sqlStmt.prefix(6).uppercased() == "DELETE" && names.count > 0 {
562
+ do {
563
+ result = try getUpdDelReturnedValues(mDB: mDB, sqlStmt: sqlStmt,
564
+ names: names )
565
+ } catch UtilsSQLCipherError
566
+ .getUpdDelReturnedValues(let message) {
567
+ throw UtilsSQLCipherError.returningWorkAround(message: message)
568
+ }
569
+ }
570
+ let returnCode: Int32 = sqlite3_step(runSQLStatement)
571
+ if returnCode != SQLITE_DONE {
572
+ let errmsg: String = String(
573
+ cString: sqlite3_errmsg(mDB.mDb))
574
+ var message = "Error: prepareSQL step failed rc: "
575
+ message.append("\(returnCode) message: \(errmsg)")
576
+ throw UtilsSQLCipherError.returningWorkAround(message: message)
577
+
578
+ }
579
+ if sqlStmt.prefix(6).uppercased() == "INSERT" {
580
+ let lastId = Int64(sqlite3_last_insert_rowid(mDB.mDb))
581
+ let tableName = extractTableName(from: sqlStmt)
582
+ if let tblName = tableName {
583
+ var query = "SELECT \(names) FROM \(tblName) WHERE rowid "
584
+ if returnMode == "wAone" {
585
+ query += "= \(initLastId + 1);"
586
+ } else {
587
+ query += "BETWEEN \(initLastId + 1) AND \(lastId);"
588
+ }
589
+ do {
590
+ result = try querySQL(mDB: mDB, sql: query, values: [])
591
+ } catch UtilsSQLCipherError.querySQL(let message) {
592
+ throw UtilsSQLCipherError.returningWorkAround(message: message)
593
+ }
594
+
595
+ }
596
+
597
+ } else if sqlStmt.prefix(6).uppercased() == "UPDATE" {
598
+ do {
599
+ result = try getUpdDelReturnedValues(mDB: mDB, sqlStmt: sqlStmt,
600
+ names: names )
601
+ } catch UtilsSQLCipherError
602
+ .getUpdDelReturnedValues(let message) {
603
+ throw UtilsSQLCipherError.returningWorkAround(message: message)
604
+ }
605
+
480
606
  }
607
+
608
+ return result
609
+ }
610
+
611
+ // MARK: - getUpdDelReturnedValues
612
+
613
+ class func getUpdDelReturnedValues(mDB: Database, sqlStmt: String,
614
+ names: String ) throws -> [[String: Any]] {
615
+ var result: [[String: Any]] = []
616
+ let tableName = extractTableName(from: sqlStmt)
617
+ let whereClause = extractWhereClause(from: sqlStmt)
618
+ if let tblName = tableName {
619
+ if var wClause = whereClause {
620
+ if wClause.suffix(1) == ";" {
621
+ wClause = String(wClause.dropLast())
622
+ }
623
+ do {
624
+ var query: String = "SELECT \(names) FROM \(tblName) WHERE "
625
+ query += "\(wClause);"
626
+ result = try querySQL(mDB: mDB, sql: query, values: [])
627
+ } catch UtilsSQLCipherError.querySQL(let message) {
628
+ throw UtilsSQLCipherError.getUpdDelReturnedValues(message: message)
629
+ }
630
+ }
631
+ }
632
+ return result
633
+ }
634
+
635
+ // MARK: - extractTableName
636
+
637
+ class func extractTableName(from statement: String) -> String? {
638
+ let pattern = "(?:INSERT\\s+INTO|UPDATE|DELETE\\s+FROM)\\s+([^\\s]+)"
639
+ guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return nil }
640
+
641
+ let range = NSRange(location: 0, length: statement.count)
642
+ if let match = regex.firstMatch(in: statement, options: [], range: range) {
643
+ let tableNameRange = match.range(at: 1)
644
+ if let tableNameRange = Range(tableNameRange, in: statement) {
645
+ let tableName = String(statement[tableNameRange])
646
+ return tableName
647
+ }
648
+ }
649
+
650
+ return nil
651
+ }
652
+
653
+ // MARK: - extractWhereClause
654
+
655
+ class func extractWhereClause(from statement: String) -> String? {
656
+ let pattern = "WHERE(.+?)(?:ORDER\\s+BY|LIMIT|$)"
657
+ guard let regex = try? NSRegularExpression(
658
+ pattern: pattern,
659
+ options: [.caseInsensitive, .dotMatchesLineSeparators]) else {
660
+ return nil
661
+
662
+ }
663
+
664
+ let range = NSRange(location: 0, length: statement.count)
665
+ if let match = regex.firstMatch(in: statement, options: [], range: range) {
666
+ let whereClauseRange = match.range(at: 1)
667
+ if let whereClauseRange = Range(whereClauseRange, in: statement) {
668
+ let whereClause = String(statement[whereClauseRange])
669
+ return whereClause.trimmingCharacters(in: .whitespacesAndNewlines)
670
+ }
671
+ }
672
+
673
+ return nil
481
674
  }
675
+
482
676
  // swiftlint:enable cyclomatic_complexity
483
677
  // swiftlint:enable function_body_length
484
678
 
@@ -530,6 +724,7 @@ class UtilsSQLCipher {
530
724
  class func findReferencesAndUpdate(mDB: Database, tableName: String,
531
725
  whereStmt: String,
532
726
  values: [Any]) throws {
727
+ var lastId: Int64 = -1
533
728
  do {
534
729
  var references = try getReferences(mDB: mDB,
535
730
  tableName: tableName)
@@ -590,9 +785,10 @@ class UtilsSQLCipher {
590
785
  }
591
786
  }
592
787
 
593
- let lastId = try prepareSQL(mDB: mDB, sql: stmt,
594
- values: selValues,
595
- fromJson: false)
788
+ let resp = try prepareSQL(mDB: mDB, sql: stmt,
789
+ values: selValues,
790
+ fromJson: false, returnMode: "no")
791
+ lastId = resp.0
596
792
  if lastId == -1 {
597
793
  let msg = "UPDATE sql_deleted failed for references " +
598
794
  "table: \(refTable) "
@@ -825,7 +1021,7 @@ class UtilsSQLCipher {
825
1021
 
826
1022
  class func querySQL(mDB: Database, sql: String,
827
1023
  values: [Any]) throws -> [[String: Any]] {
828
- var msg: String = "Error prepareSQL: "
1024
+ var msg: String = "Error querySQL: "
829
1025
  if !mDB.isDBOpen() {
830
1026
  msg.append("Database not opened")
831
1027
  throw UtilsSQLCipherError.querySQL(message: msg)
@@ -845,7 +1041,7 @@ class UtilsSQLCipher {
845
1041
  if message.count == 0 {
846
1042
  do {
847
1043
  result = try UtilsSQLCipher.fetchColumnInfo(
848
- handle: selectSQLStatement)
1044
+ handle: selectSQLStatement, returnMode: "all")
849
1045
  } catch UtilsSQLCipherError
850
1046
  .fetchColumnInfo(let message) {
851
1047
  throw UtilsSQLCipherError.querySQL(message: message)
@@ -875,7 +1071,7 @@ class UtilsSQLCipher {
875
1071
 
876
1072
  // swiftlint:disable function_body_length
877
1073
  // swiftlint:disable cyclomatic_complexity
878
- class func fetchColumnInfo(handle: OpaquePointer?)
1074
+ class func fetchColumnInfo(handle: OpaquePointer?, returnMode: String)
879
1075
  throws -> [[String: Any]] {
880
1076
  var result: [[String: Any]] = []
881
1077
  var columnCount: Int32 = 0
@@ -937,7 +1133,9 @@ class UtilsSQLCipher {
937
1133
  }
938
1134
  }
939
1135
  result.append(rowData)
940
-
1136
+ if returnMode == "one" {
1137
+ break
1138
+ }
941
1139
  }
942
1140
  return result
943
1141
  }
@@ -1026,14 +1224,16 @@ class UtilsSQLCipher {
1026
1224
 
1027
1225
  // MARK: - ExecuteSet
1028
1226
 
1029
- class func executeSet(mDB: Database, set: [[String: Any]])
1030
- throws -> Int64 {
1227
+ // swiftlint:disable function_body_length
1228
+ class func executeSet(mDB: Database, set: [[String: Any]], returnMode: String)
1229
+ throws -> (Int64, [[String: Any]]) {
1031
1230
  var msg: String = "Error executeSet: "
1032
1231
  if !mDB.isDBOpen() {
1033
1232
  msg.append("Database not opened")
1034
1233
  throw UtilsSQLCipherError.executeSet(message: msg)
1035
1234
  }
1036
1235
  var lastId: Int64 = -1
1236
+ var response: [[String: Any]] = []
1037
1237
  do {
1038
1238
  for dict in set {
1039
1239
  guard let sql: String = dict["statement"] as? String
@@ -1046,39 +1246,70 @@ class UtilsSQLCipher {
1046
1246
  throw UtilsSQLCipherError.executeSet(
1047
1247
  message: "No values given")
1048
1248
  }
1249
+ var respSet: [[String: Any]] = []
1049
1250
  let isArray = values.count > 0 ? UtilsSQLCipher.parse(mVar: values[0]) : false
1050
1251
  if isArray {
1051
1252
  if let arrValues = values as? [[Any]] {
1052
1253
  for vals in arrValues {
1053
- lastId = try UtilsSQLCipher
1254
+ let resp = try UtilsSQLCipher
1054
1255
  .prepareSQL(mDB: mDB, sql: sql,
1055
- values: vals, fromJson: false)
1256
+ values: vals, fromJson: false,
1257
+ returnMode: returnMode)
1258
+ lastId = resp.0
1259
+ respSet = resp.1
1260
+
1056
1261
  if lastId == -1 {
1057
1262
  let message: String = "lastId < 0"
1058
1263
  throw UtilsSQLCipherError
1059
1264
  .executeSet(message: message)
1060
1265
  }
1266
+
1267
+ response = addToResponse(response: response,
1268
+ respSet: respSet)
1061
1269
  }
1062
1270
  }
1063
1271
  } else {
1064
- lastId = try UtilsSQLCipher
1272
+ let resp = try UtilsSQLCipher
1065
1273
  .prepareSQL(mDB: mDB, sql: sql, values: values,
1066
- fromJson: false)
1274
+ fromJson: false, returnMode: returnMode)
1275
+ lastId = resp.0
1276
+ respSet = resp.1
1067
1277
  if lastId == -1 {
1068
1278
  let message: String = "lastId < 0"
1069
1279
  throw UtilsSQLCipherError.executeSet(
1070
1280
  message: message)
1071
1281
  }
1282
+ response = addToResponse(response: response, respSet: respSet)
1072
1283
  }
1073
1284
  }
1074
1285
 
1075
- return lastId
1286
+ return (lastId, response)
1076
1287
  } catch UtilsSQLCipherError.prepareSQL(let message) {
1077
1288
  throw UtilsSQLCipherError.executeSet(
1078
1289
  message: message)
1079
1290
  }
1080
1291
  }
1081
1292
 
1293
+ class func addToResponse(response: [[String: Any]],
1294
+ respSet: [[String: Any]]) -> [[String: Any]] {
1295
+ var retResponse = response
1296
+ var mRespSet = respSet
1297
+ if !retResponse.isEmpty {
1298
+ let keysInArray1 = ["ios_columns"]
1299
+ mRespSet = mRespSet.filter { dict2 in
1300
+ guard let dict2Key = dict2.keys.first else {
1301
+ return true // Keep dictionaries without any keys
1302
+ }
1303
+ return !keysInArray1.contains(dict2Key)
1304
+ }
1305
+ }
1306
+ retResponse.append(contentsOf: mRespSet)
1307
+
1308
+ return retResponse
1309
+
1310
+ }
1311
+ // swiftlint:enable function_body_length
1312
+
1082
1313
  // MARK: - RestoreDB
1083
1314
 
1084
1315
  class func restoreDB(databaseLocation: String, databaseName: String) throws {
@@ -26,7 +26,6 @@ class UtilsUpgrade {
26
26
 
27
27
  for (versionKey, upgrade) in Array(upgDict).sorted(by: {$0.0 < $1.0}) {
28
28
  if versionKey > currentVersion && versionKey <= targetVersion {
29
- print("- UtilsUpgrade.onUpgrade toVersion: \(versionKey)")
30
29
 
31
30
  guard let statements = upgrade["statements"] as? [String] else {
32
31
  let msg: String = "Error: onUpgrade statements not given"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor-community/sqlite",
3
- "version": "5.0.5-2",
3
+ "version": "5.0.6",
4
4
  "description": "Community plugin for native & electron SQLite databases",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -95,6 +95,6 @@
95
95
  }
96
96
  },
97
97
  "dependencies": {
98
- "jeep-sqlite": "^2.3.6"
98
+ "jeep-sqlite": "^2.3.8"
99
99
  }
100
100
  }