@capacitor-community/sqlite 3.5.2-dev1 → 4.0.0-0

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.
@@ -558,14 +558,20 @@ class Database {
558
558
  do {
559
559
  let date = Date()
560
560
  let syncTime: Int = Int(date.timeIntervalSince1970)
561
- // Set the last exported date
562
- try ExportToJson.setLastExportDate(mDB: self, sTime: syncTime)
561
+ let isExists: Bool = try UtilsJson.isTableExists(
562
+ mDB: self, tableName: "sync_table")
563
+ if isExists {
564
+ // Set the last exported date
565
+ try ExportToJson.setLastExportDate(mDB: self, sTime: syncTime)
566
+ }
563
567
  // Launch the export process
564
568
  let data: [String: Any] = [
565
569
  "dbName": dbName, "encrypted": self.encrypted,
566
570
  "expMode": expMode, "version": dbVersion]
567
571
  retObj = try ExportToJson
568
572
  .createExportObject(mDB: self, data: data)
573
+ } catch UtilsJsonError.tableNotExists(let message) {
574
+ throw DatabaseError.exportToJson(message: message)
569
575
  } catch ExportToJsonError.setLastExportDate(let message) {
570
576
  throw DatabaseError.exportToJson(message: message)
571
577
  } catch ExportToJsonError.createExportObject(let message) {
@@ -8,12 +8,18 @@
8
8
  import Foundation
9
9
 
10
10
  extension String {
11
- public func indicesOf(string: String) -> [Int] {
11
+ public func indicesOf(string: String, fromIdx: Int? = 0) -> [Int] {
12
12
  var indices = [Int]()
13
13
  var searchStartIndex = self.startIndex
14
+ if let fIdx = fromIdx {
15
+ if fIdx != 0 {
16
+ searchStartIndex = self.index(self.startIndex, offsetBy: fIdx)
17
+ }
18
+ }
19
+
14
20
 
15
21
  while searchStartIndex < self.endIndex,
16
- let range = self.range(of: string, range: searchStartIndex..<self.endIndex),
22
+ let range = self.range(of: string, options: .caseInsensitive, range: searchStartIndex..<self.endIndex),
17
23
  !range.isEmpty {
18
24
  let index = distance(from: self.startIndex, to: range.lowerBound)
19
25
  indices.append(index)
@@ -20,6 +20,7 @@ enum UtilsFileError: Error {
20
20
  case getDatabasesURLFailed
21
21
  case getApplicationPathFailed
22
22
  case getApplicationURLFailed
23
+ case getCacheURLFailed
23
24
  case getLibraryPathFailed
24
25
  case getLibraryURLFailed
25
26
  case getFileListFailed
@@ -148,6 +149,8 @@ class UtilsFile {
148
149
  dbPathURL = try UtilsFile.getApplicationURL().absoluteURL
149
150
  } else if first[0] == "Library" {
150
151
  dbPathURL = try UtilsFile.getLibraryURL().absoluteURL
152
+ } else if first[0].caseInsensitiveCompare("cache") == .orderedSame {
153
+ dbPathURL = try UtilsFile.getCacheURL().absoluteURL
151
154
  } else if first[0] == "Documents" || first[0] == "default" {
152
155
  dbPathURL = databaseURL
153
156
  } else {
@@ -238,6 +241,19 @@ class UtilsFile {
238
241
  throw UtilsFileError.getApplicationPathFailed
239
242
  }
240
243
  }
244
+
245
+ // MARK: - getCacheURL
246
+
247
+ class func getCacheURL() throws -> URL {
248
+ if let path: String = NSSearchPathForDirectoriesInDomains(
249
+ .cachesDirectory, .userDomainMask, true
250
+ ).first {
251
+ return NSURL(fileURLWithPath: path) as URL
252
+ } else {
253
+ print("Error: getCacheURL did not find the cache folder")
254
+ throw UtilsFileError.getCacheURLFailed
255
+ }
256
+ }
241
257
 
242
258
  // MARK: - getLibraryURL
243
259
 
@@ -25,8 +25,9 @@ enum UtilsSQLCipherError: Error {
25
25
  case execute(message: String)
26
26
  case prepareSQL(message: String)
27
27
  case deleteSQL(message: String)
28
- case findReferenciesAndUpdate(message: String)
29
- case getReferencies(message: String)
28
+ case findReferencesAndUpdate(message: String)
29
+ case getReferences(message: String)
30
+ case getRefs(message: String)
30
31
  case querySQL(message: String)
31
32
  case fetchColumnInfo(message: String)
32
33
  case deleteDB(message: String)
@@ -503,17 +504,17 @@ class UtilsSQLCipher {
503
504
  sqlStmt = "UPDATE \(tableName) SET sql_deleted = 1 "
504
505
  sqlStmt += clauseStmt
505
506
  // Find REFERENCIES if any and update the sql_deleted column
506
- try findReferenciesAndUpdate(mDB: mDB,
507
- tableName: tableName,
508
- whereStmt: clauseStmt,
509
- values: values)
507
+ try findReferencesAndUpdate(mDB: mDB,
508
+ tableName: tableName,
509
+ whereStmt: clauseStmt,
510
+ values: values)
510
511
  } else {
511
512
  let msg: String = "deleteSQL cannot find a WHERE clause"
512
513
  throw UtilsSQLCipherError.deleteSQL(message: msg)
513
514
  }
514
515
  }
515
516
  return sqlStmt
516
- } catch UtilsSQLCipherError.findReferenciesAndUpdate(let message) {
517
+ } catch UtilsSQLCipherError.findReferencesAndUpdate(let message) {
517
518
  throw UtilsSQLCipherError.deleteSQL(message: message)
518
519
  } catch UtilsJsonError.isLastModified(let message) {
519
520
  throw UtilsSQLCipherError.deleteSQL(message: message)
@@ -524,155 +525,301 @@ class UtilsSQLCipher {
524
525
 
525
526
  // MARK: - findReferencesAndUpdate
526
527
 
527
- class func findReferenciesAndUpdate(mDB: Database, tableName: String,
528
- whereStmt: String,
529
- values: [Any]) throws {
528
+ // swiftlint:disable function_body_length
529
+ // swiftlint:disable cyclomatic_complexity
530
+ class func findReferencesAndUpdate(mDB: Database, tableName: String,
531
+ whereStmt: String,
532
+ values: [Any]) throws {
530
533
  do {
531
- let referencies = try getReferencies(mDB: mDB,
532
- tableName: tableName)
533
- if referencies.count <= 0 {
534
+ var references = try getReferences(mDB: mDB,
535
+ tableName: tableName)
536
+ if references.count <= 0 {
537
+ return
538
+ }
539
+ guard let tableNameWithRefs = references.last else {
534
540
  return
535
541
  }
536
- // Loop through referencies
537
- for ref in referencies {
542
+ references.removeLast()
543
+ // Loop through references
544
+ for ref in references {
538
545
  // get the tableName of the references
539
546
  let refTable: String = getReferencesTableName(value: ref)
540
547
  if refTable.count <= 0 {
541
548
  continue
542
549
  }
550
+ // get the with ref columnName
551
+ let withRefsNames: [String] = getWithRefsColumnName(value: ref)
552
+ if withRefsNames.count <= 0 {
553
+ continue
554
+ }
543
555
  // get the columnName
544
- let colName: String = getReferencesColumnName(value: ref)
545
- if colName.count <= 0 {
556
+ let colNames: [String] = getReferencesColumnName(value: ref)
557
+ if colNames.count <= 0 {
546
558
  continue
547
559
  }
548
560
  // update the where clause
549
561
  let uWhereStmt: String = updateWhere(whStmt: whereStmt,
550
- colName: colName)
562
+ withRefs: withRefsNames,
563
+ colNames: colNames)
551
564
 
552
565
  if uWhereStmt.count <= 0 {
553
566
  continue
554
567
  }
568
+ var updTableName: String = tableNameWithRefs
569
+ var updColNames: [String] = colNames
570
+ if tableNameWithRefs == tableName {
571
+ updTableName = refTable
572
+ updColNames = withRefsNames
573
+ }
555
574
  //update sql_deleted for this references
556
- let stmt = "UPDATE \(refTable) SET sql_deleted = 1 " +
575
+ let stmt = "UPDATE \(updTableName) SET sql_deleted = 1 " +
557
576
  uWhereStmt
577
+ var selValues: [Any] = []
578
+ if !values.isEmpty {
579
+ var arrVal: [String] = whereStmt.components(separatedBy: "?")
580
+ if arrVal[arrVal.count - 1] == ";" {
581
+ arrVal.removeLast()
582
+ }
583
+ for (jdx, val) in arrVal.enumerated() {
584
+ for updVal in updColNames {
585
+ let indices: [Int] = val.indicesOf(string: updVal)
586
+ if indices.count > 0 {
587
+ selValues.append(values[jdx])
588
+ }
589
+ }
590
+ }
591
+ }
592
+
558
593
  let lastId = try prepareSQL(mDB: mDB, sql: stmt,
559
- values: values, fromJson: false)
594
+ values: selValues,
595
+ fromJson: false)
560
596
  if lastId == -1 {
561
597
  let msg = "UPDATE sql_deleted failed for references " +
562
598
  "table: \(refTable) "
563
599
  throw UtilsSQLCipherError
564
- .findReferenciesAndUpdate(message: msg)
600
+ .findReferencesAndUpdate(message: msg)
565
601
  }
566
602
  }
567
603
  return
568
604
  } catch UtilsSQLCipherError.prepareSQL(let message) {
569
605
  throw UtilsSQLCipherError
570
- .findReferenciesAndUpdate(message: message)
606
+ .findReferencesAndUpdate(message: message)
571
607
  } catch UtilsSQLCipherError.querySQL(let message) {
572
608
  throw UtilsSQLCipherError
573
- .findReferenciesAndUpdate(message: message)
609
+ .findReferencesAndUpdate(message: message)
574
610
  }
575
611
 
576
612
  }
613
+ // swiftlint:enable cyclomatic_complexity
614
+ // swiftlint:enable function_body_length
577
615
 
578
- // MARK: - getReferencies
616
+ // MARK: - getReferences
579
617
 
580
- class func getReferencies(mDB: Database, tableName: String)
581
- throws -> [[String: Any]] {
582
- // find the REFERENCIES
618
+ class func getReferences(mDB: Database, tableName: String)
619
+ throws -> [String] {
620
+ // find the REFERENCES
583
621
  var sqlStmt = "SELECT sql FROM sqlite_master "
584
- sqlStmt += "WHERE sql LIKE('%REFERENCES%') AND "
622
+ sqlStmt += "WHERE sql LIKE('%FOREIGN KEY%') AND "
623
+ sqlStmt += "sql LIKE('%REFERENCES%') AND "
585
624
  sqlStmt += "sql LIKE('%\(tableName)%') AND sql LIKE('%ON DELETE%');"
586
625
  do {
587
- var referencies: [[String: Any]] = try querySQL(mDB: mDB,
588
- sql: sqlStmt,
589
- values: [])
590
- if referencies.count > 1 {
591
- referencies.removeFirst()
626
+ var references: [[String: Any]] = try querySQL(mDB: mDB,
627
+ sql: sqlStmt,
628
+ values: [])
629
+ var retRefs: [String] = []
630
+ if references.count > 1 {
631
+ references.removeFirst()
632
+ if let refValue = references[0]["sql"] as? String {
633
+ retRefs = try getRefs(str: refValue)
634
+ }
592
635
  }
593
- return referencies
636
+ return retRefs
637
+ } catch UtilsSQLCipherError.getRefs(let message) {
638
+ throw UtilsSQLCipherError
639
+ .getReferences(message: message)
594
640
  } catch UtilsSQLCipherError.querySQL(let message) {
595
641
  throw UtilsSQLCipherError
596
- .getReferencies(message: message)
642
+ .getReferences(message: message)
643
+ }
644
+ }
645
+ class func getRefs(str: String) throws -> [String] {
646
+ var retRefs: [String] = []
647
+ let indicesFK: [Int] = str.indicesOf(string: "FOREIGN KEY")
648
+ let indicesOD: [Int] = str.indicesOf(string: "ON DELETE")
649
+ if indicesFK.count > 0 && indicesOD.count > 0
650
+ && indicesFK.count != indicesOD.count {
651
+ let msg: String = "Indices of FOREIGN KEY and ON DELETE not equal"
652
+ throw UtilsSQLCipherError.getRefs(message: msg)
653
+
654
+ }
655
+ for (idx, iFK) in indicesFK.enumerated() {
656
+ let ref: String = String(str.stringRange(fromIdx: iFK + 11,
657
+ toIdx: indicesOD[idx]))
658
+ .trimmingLeadingAndTrailingSpaces()
659
+ retRefs.append(ref)
597
660
  }
661
+
662
+ if let range: Range<String.Index> = str
663
+ .range(of: "CREATE TABLE", options: .caseInsensitive) {
664
+ let index: Int = str
665
+ .distance(from: str.startIndex, to: range.lowerBound)
666
+ let stmt = String(str.stringRange(fromIdx: index + 13,
667
+ toIdx: str.count))
668
+ if let oPar = stmt.firstIndex(of: "(") {
669
+ let idx: Int = stmt.distance(from: stmt.startIndex, to: oPar)
670
+ let tableName: String = String(stmt.stringRange(fromIdx: 0,
671
+ toIdx: idx))
672
+ .trimmingLeadingAndTrailingSpaces()
673
+ retRefs.append(tableName)
674
+ }
675
+ }
676
+
677
+ return retRefs
598
678
  }
599
679
 
600
680
  // MARK: - getReferencesTableName
601
681
 
602
- class func getReferencesTableName(value: [String: Any]) -> String {
682
+ class func getReferencesTableName(value: String) -> String {
603
683
 
604
684
  var tableName: String = ""
605
- if let refValue = value["sql"] as? String {
606
-
607
- if let range: Range<String.Index> = refValue
608
- .range(of: "CREATE TABLE", options: .caseInsensitive) {
609
- let index: Int = refValue
610
- .distance(from: refValue.startIndex, to: range.lowerBound)
611
- let stmt = String(refValue.stringRange(fromIdx: index + 13,
612
- toIdx: refValue.count))
613
- if let oPar = stmt.firstIndex(of: "(") {
614
- let idx: Int = stmt.distance(from: stmt.startIndex, to: oPar)
615
- tableName = String(stmt.stringRange(fromIdx: 0, toIdx: idx))
616
- .trimmingLeadingAndTrailingSpaces()
617
- }
685
+ if value.isEmpty {
686
+ return tableName
687
+ }
688
+ let indicesRef: [Int] = value.indicesOf(string: "REFERENCES")
689
+ if indicesRef.count > 0 {
690
+ let val: String = String(value.stringRange(
691
+ fromIdx: indicesRef[0] + 10,
692
+ toIdx: value.count))
693
+ if let oPar = val.firstIndex(of: "(") {
694
+ let idx: Int = val.distance(from: val.startIndex, to: oPar)
695
+ tableName = String(val.stringRange(fromIdx: 0,
696
+ toIdx: idx))
697
+ .trimmingLeadingAndTrailingSpaces()
618
698
  }
619
699
  }
620
700
  return tableName
621
701
  }
622
702
 
623
- // MARK: - getReferencesColumnName
703
+ // MARK: - getWithRefColumnName
624
704
 
625
- class func getReferencesColumnName(value: [String: Any]) -> String {
626
-
627
- var colName: String = ""
628
- if let refValue = value["sql"] as? String {
629
-
630
- if let range: Range<String.Index> = refValue
631
- .range(of: "FOREIGN KEY", options: .caseInsensitive) {
632
- let index: Int = refValue
633
- .distance(from: refValue.startIndex, to: range.lowerBound)
634
- let stmt = String(refValue.stringRange(fromIdx: index + 12,
635
- toIdx: refValue.count))
636
- if let oPar = stmt.firstIndex(of: "(") {
637
- let idxOPar: Int = stmt.distance(from: stmt.startIndex,
638
- to: oPar) + 1
639
- if let cPar = stmt.firstIndex(of: ")") {
640
- let idxCPar: Int = stmt
641
- .distance(from: stmt.startIndex,
642
- to: cPar)
643
- colName = String(stmt.stringRange(fromIdx: idxOPar,
644
- toIdx: idxCPar))
645
- .trimmingLeadingAndTrailingSpaces()
705
+ class func getWithRefsColumnName(value: String) -> [String] {
646
706
 
647
- }
707
+ var colNames: [String] = []
708
+ if value.isEmpty {
709
+ return colNames
710
+ }
711
+ let indicesRef: [Int] = value.indicesOf(string: "REFERENCES")
712
+ if indicesRef.count > 0 {
713
+ let val: String = String(value.stringRange(
714
+ fromIdx: 0,
715
+ toIdx: indicesRef[0] - 1))
716
+ if let oPar = val.firstIndex(of: "(") {
717
+ let idxOPar: Int = val.distance(from: val.startIndex, to: oPar)
718
+ if let cPar = val.firstIndex(of: ")") {
719
+ let idxCPar: Int = val.distance(from: val.startIndex,
720
+ to: cPar)
721
+
722
+ let colStr: String = String(val
723
+ .stringRange(fromIdx: idxOPar + 1,
724
+ toIdx: idxCPar))
725
+ .trimmingLeadingAndTrailingSpaces()
726
+ colNames = colStr.split(separator: ",").map(String.init)
648
727
  }
649
728
  }
650
729
  }
730
+ return colNames
731
+ }
732
+ // MARK: - getReferencesColumnName
651
733
 
652
- return colName
734
+ class func getReferencesColumnName(value: String) -> [String] {
735
+
736
+ var colNames: [String] = []
737
+ if value.isEmpty {
738
+ return colNames
739
+ }
740
+ let indicesRef: [Int] = value.indicesOf(string: "REFERENCES")
741
+ if indicesRef.count > 0 {
742
+ let val: String = String(value.stringRange(
743
+ fromIdx: indicesRef[0] + 10,
744
+ toIdx: value.count))
745
+ if let oPar = val.firstIndex(of: "(") {
746
+ let idxOPar: Int = val.distance(from: val.startIndex, to: oPar)
747
+ if let cPar = val.firstIndex(of: ")") {
748
+ let idxCPar: Int = val.distance(from: val.startIndex,
749
+ to: cPar)
750
+
751
+ let colStr: String = String(val
752
+ .stringRange(fromIdx: idxOPar + 1,
753
+ toIdx: idxCPar))
754
+ .trimmingLeadingAndTrailingSpaces()
755
+ colNames = colStr.split(separator: ",").map(String.init)
756
+
757
+ }
758
+ }
759
+ }
760
+ return colNames
653
761
  }
654
762
 
655
- class func updateWhere(whStmt: String, colName: String) -> String {
763
+ // swiftlint:disable function_body_length
764
+ class func updateWhere(whStmt: String, withRefs: [String],
765
+ colNames: [String]) -> String {
656
766
  var whereStmt = ""
657
- if let range: Range<String.Index> = whStmt
658
- .range(of: "WHERE", options: .caseInsensitive) {
659
- let index: Int = whStmt
660
- .distance(from: whStmt.startIndex, to: range.lowerBound)
661
- let stmt = String(whStmt.stringRange(fromIdx: index + 6,
662
- toIdx: whStmt.count))
663
- if let fEqual = stmt.firstIndex(of: "=") {
664
- let idxfEqual: Int = stmt.distance(from: stmt.startIndex,
665
- to: fEqual)
666
- let whereColName = String(stmt.stringRange(fromIdx: 0,
667
- toIdx: idxfEqual))
668
- .trimmingLeadingAndTrailingSpaces()
669
- whereStmt = whStmt.replacingOccurrences(of: whereColName, with: colName)
767
+ if whStmt.count > 0 {
768
+ let indicesWhere: [Int] = whStmt.indicesOf(string: "WHERE")
769
+ if indicesWhere.count == 0 {
770
+ return whereStmt
771
+ }
772
+ var stmt: String = String(whStmt.stringRange(
773
+ fromIdx: indicesWhere[0] + 6,
774
+ toIdx: whStmt.count))
775
+ if withRefs.count == colNames.count {
776
+ for (idx, wRf) in withRefs.enumerated() {
777
+ var colType: String = "withRefsNames"
778
+ var idxs: [Int] = stmt.indicesOf(string: wRf)
779
+ if idxs.count == 0 {
780
+ idxs = stmt.indicesOf(string: colNames[idx])
781
+ colType = "colNames"
782
+ }
783
+ if idxs.count > 0 {
784
+ var valStr: String = ""
785
+ let indicesEqual: [Int] = stmt
786
+ .indicesOf(string: "=",
787
+ fromIdx: idxs[0])
788
+
789
+ if indicesEqual.count > 0 {
790
+ let indicesAnd: [Int] = stmt
791
+ .indicesOf(string: "AND",
792
+ fromIdx: indicesEqual[0])
793
+ if indicesAnd.count > 0 {
794
+ valStr = String(stmt.stringRange(
795
+ fromIdx: indicesEqual[0] + 1,
796
+ toIdx: indicesAnd[0] - 1))
797
+ stmt = String(stmt.stringRange(
798
+ fromIdx: indicesAnd[0] + 3,
799
+ toIdx: stmt.count))
800
+ } else {
801
+ valStr = String(stmt.stringRange(
802
+ fromIdx: indicesEqual[0] + 1,
803
+ toIdx: stmt.count))
804
+ }
805
+ if idx > 0 {
806
+ whereStmt += " AND "
807
+ }
808
+ if colType == "withRefsNames" {
809
+ whereStmt += colNames[idx] + " = " + valStr
810
+ } else {
811
+ whereStmt += withRefs[idx] + " = " + valStr
812
+ }
813
+ }
814
+ }
670
815
 
816
+ }
817
+ whereStmt = "WHERE " + whereStmt
671
818
  }
672
819
  }
673
-
674
820
  return whereStmt
675
821
  }
822
+ // swiftlint:enable function_body_length
676
823
 
677
824
  // MARK: - querySQL
678
825
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor-community/sqlite",
3
- "version": "3.5.2-dev1",
3
+ "version": "4.0.0-0",
4
4
  "description": "Community plugin for native & electron SQLite databases",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -55,10 +55,10 @@
55
55
  "prepublishOnly": "npm run build && npm run build-electron && npm run docgen"
56
56
  },
57
57
  "devDependencies": {
58
- "@capacitor/android": "^3.5.1",
59
- "@capacitor/core": "^3.5.1",
58
+ "@capacitor/android": "^4.0.0",
59
+ "@capacitor/core": "^4.0.0",
60
60
  "@capacitor/docgen": "^0.0.17",
61
- "@capacitor/ios": "^3.5.1",
61
+ "@capacitor/ios": "^4.0.0",
62
62
  "@ionic/eslint-config": "^0.3.0",
63
63
  "@ionic/prettier-config": "^1.0.1",
64
64
  "@ionic/swiftlint-config": "^1.1.2",
@@ -66,15 +66,15 @@
66
66
  "@rollup/plugin-node-resolve": "^13.0.4",
67
67
  "electron": "^15.5.5",
68
68
  "eslint": "^7.11.0",
69
- "prettier": "~2.2.0",
70
- "prettier-plugin-java": "~1.0.0",
69
+ "prettier": "~2.3.0",
70
+ "prettier-plugin-java": "~1.0.2",
71
71
  "rimraf": "^3.0.2",
72
72
  "rollup": "^2.32.0",
73
73
  "swiftlint": "^1.0.1",
74
- "typescript": "~4.0.5"
74
+ "typescript": "~4.1.5"
75
75
  },
76
76
  "peerDependencies": {
77
- "@capacitor/core": "^3.0.0"
77
+ "@capacitor/core": "^4.0.0"
78
78
  },
79
79
  "prettier": "@ionic/prettier-config",
80
80
  "swiftlint": "@ionic/swiftlint-config",
@@ -93,6 +93,6 @@
93
93
  }
94
94
  },
95
95
  "dependencies": {
96
- "jeep-sqlite": "^1.5.4-dev1"
96
+ "jeep-sqlite": "^1.5.4"
97
97
  }
98
98
  }