@capacitor-community/sqlite 3.4.0 → 3.4.1-3
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 +7 -0
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/CapacitorSQLite.java +134 -89
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/CapacitorSQLitePlugin.java +449 -264
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/Database.java +41 -27
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/ExportToJson.java +5 -0
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/ImportFromJson.java +24 -15
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/JsonSQLite.java +4 -1
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/UtilsJson.java +23 -0
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/SqliteConfig.java +9 -0
- package/dist/esm/definitions.js +1 -1
- package/dist/esm/definitions.js.map +1 -1
- package/dist/plugin.cjs.js +1 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +1 -1
- package/dist/plugin.js.map +1 -1
- package/electron/dist/plugin.js +228 -176
- package/electron/dist/plugin.js.map +1 -1
- package/ios/Plugin/CapacitorSQLite.swift +150 -109
- package/ios/Plugin/CapacitorSQLitePlugin.swift +17 -10
- package/ios/Plugin/Database.swift +50 -20
- package/ios/Plugin/ImportExportJson/ExportToJson.swift +8 -0
- package/ios/Plugin/ImportExportJson/ImportFromJson.swift +20 -14
- package/ios/Plugin/SqliteConfig.swift +1 -0
- package/ios/Plugin/Utils/UtilsJson.swift +28 -0
- package/package.json +9 -6
|
@@ -12,6 +12,7 @@ enum CapacitorSQLiteError: Error {
|
|
|
12
12
|
private var databaseLocation: String = "Documents"
|
|
13
13
|
private var initMessage: String = ""
|
|
14
14
|
private var isInit: Bool = false
|
|
15
|
+
private var isEncryption: Bool = true
|
|
15
16
|
private var isBiometricAuth: Bool = false
|
|
16
17
|
private var biometricTitle: String = ""
|
|
17
18
|
private var bioIdAuth: BiometricIDAuthentication =
|
|
@@ -28,45 +29,53 @@ enum CapacitorSQLiteError: Error {
|
|
|
28
29
|
init(config: SqliteConfig) {
|
|
29
30
|
self.config = config
|
|
30
31
|
super.init()
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
|
|
33
|
+
if let isEncrypt = config.iosIsEncryption {
|
|
34
|
+
if isEncrypt == 0 {
|
|
35
|
+
isEncryption = false
|
|
36
|
+
}
|
|
34
37
|
}
|
|
35
|
-
if
|
|
36
|
-
if
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
let
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
38
|
+
if isEncryption {
|
|
39
|
+
if let kcPrefix: String = config.iosKeychainPrefix {
|
|
40
|
+
account = "\(kcPrefix)_\(oldAccount)"
|
|
41
|
+
prefixKeychain = kcPrefix
|
|
42
|
+
}
|
|
43
|
+
if let isBioAuth = config.biometricAuth {
|
|
44
|
+
if isBioAuth == 1 {
|
|
45
|
+
if let bTitle = config.biometricTitle {
|
|
46
|
+
biometricTitle = bTitle
|
|
47
|
+
bioIdAuth.biometricTitle = bTitle
|
|
48
|
+
}
|
|
49
|
+
do {
|
|
50
|
+
let bioType: BiometricType = try
|
|
51
|
+
bioIdAuth.biometricType()
|
|
52
|
+
if bioType == BiometricType.faceID ||
|
|
53
|
+
bioType == BiometricType.touchID {
|
|
54
|
+
isBiometricAuth = true
|
|
55
|
+
isInit = true
|
|
56
|
+
bioIdAuth.authenticateUser { [weak self] message in
|
|
57
|
+
if let message = message {
|
|
58
|
+
self?.notifyBiometricEvents(name: .biometricEvent,
|
|
59
|
+
result: false,
|
|
60
|
+
msg: message)
|
|
61
|
+
} else {
|
|
62
|
+
self?.notifyBiometricEvents(name: .biometricEvent,
|
|
63
|
+
result: true,
|
|
64
|
+
msg: "")
|
|
65
|
+
}
|
|
57
66
|
}
|
|
67
|
+
} else {
|
|
68
|
+
self.notifyBiometricEvents(name: .biometricEvent,
|
|
69
|
+
result: false,
|
|
70
|
+
msg: "Biometric not set-up")
|
|
58
71
|
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
} catch BiometricIDAuthenticationError
|
|
73
|
+
.biometricType(let message) {
|
|
74
|
+
initMessage = message
|
|
75
|
+
} catch let error {
|
|
76
|
+
initMessage = "Init Plugin failed :"
|
|
77
|
+
initMessage.append(" \(error.localizedDescription)")
|
|
63
78
|
}
|
|
64
|
-
} catch BiometricIDAuthenticationError
|
|
65
|
-
.biometricType(let message) {
|
|
66
|
-
initMessage = message
|
|
67
|
-
} catch let error {
|
|
68
|
-
initMessage = "Init Plugin failed :"
|
|
69
|
-
initMessage.append(" \(error.localizedDescription)")
|
|
70
79
|
}
|
|
71
80
|
}
|
|
72
81
|
}
|
|
@@ -101,18 +110,21 @@ enum CapacitorSQLiteError: Error {
|
|
|
101
110
|
|
|
102
111
|
@objc public func isSecretStored() throws -> NSNumber {
|
|
103
112
|
if isInit {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
if isEncryption {
|
|
114
|
+
do {
|
|
115
|
+
let isSecretExists: Bool = try UtilsSecret.isPassphrase(
|
|
116
|
+
account: account)
|
|
117
|
+
if isSecretExists {
|
|
118
|
+
return 1
|
|
119
|
+
} else {
|
|
120
|
+
return 0
|
|
121
|
+
}
|
|
122
|
+
} catch UtilsSecretError.prefixPassphrase(let message) {
|
|
123
|
+
throw CapacitorSQLiteError.failed(message: message)
|
|
111
124
|
}
|
|
112
|
-
}
|
|
113
|
-
throw CapacitorSQLiteError.failed(message:
|
|
125
|
+
} else {
|
|
126
|
+
throw CapacitorSQLiteError.failed(message: "No Encryption set in capacitor.config")
|
|
114
127
|
}
|
|
115
|
-
|
|
116
128
|
} else {
|
|
117
129
|
throw CapacitorSQLiteError.failed(message: initMessage)
|
|
118
130
|
}
|
|
@@ -122,19 +134,23 @@ enum CapacitorSQLiteError: Error {
|
|
|
122
134
|
|
|
123
135
|
@objc public func setEncryptionSecret(passphrase: String) throws {
|
|
124
136
|
if isInit {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
if isEncryption {
|
|
138
|
+
do {
|
|
139
|
+
// close all connections
|
|
140
|
+
try closeAllConnections()
|
|
141
|
+
// set encryption secret
|
|
142
|
+
try UtilsSecret
|
|
143
|
+
.setEncryptionSecret(prefix: prefixKeychain,
|
|
144
|
+
passphrase: passphrase,
|
|
145
|
+
databaseLocation: databaseLocation)
|
|
146
|
+
return
|
|
147
|
+
} catch UtilsSecretError.setEncryptionSecret(let message) {
|
|
148
|
+
throw CapacitorSQLiteError.failed(message: message)
|
|
149
|
+
} catch let error {
|
|
150
|
+
throw CapacitorSQLiteError.failed(message: "\(error)")
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
throw CapacitorSQLiteError.failed(message: "No Encryption set in capacitor.config")
|
|
138
154
|
}
|
|
139
155
|
} else {
|
|
140
156
|
throw CapacitorSQLiteError.failed(message: initMessage)
|
|
@@ -147,58 +163,62 @@ enum CapacitorSQLiteError: Error {
|
|
|
147
163
|
@objc public func changeEncryptionSecret(call: CAPPluginCall, passphrase: String,
|
|
148
164
|
oldPassphrase: String) throws {
|
|
149
165
|
if isInit {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
} else {
|
|
163
|
-
do {
|
|
164
|
-
try UtilsSecret.changeEncryptionSecret(
|
|
165
|
-
prefix: mPrefixKeychain,
|
|
166
|
-
passphrase: passphrase,
|
|
167
|
-
oldPassphrase: oldPassphrase,
|
|
168
|
-
databaseLocation: dbLocation)
|
|
169
|
-
retHandler.rResult(call: call)
|
|
170
|
-
return
|
|
171
|
-
} catch UtilsSecretError.changeEncryptionSecret(let message) {
|
|
172
|
-
let msg = "ChangeEncryptionSecret: \(message)"
|
|
173
|
-
retHandler.rResult(call: call, message: msg)
|
|
174
|
-
return
|
|
175
|
-
} catch let error {
|
|
176
|
-
retHandler.rResult(
|
|
177
|
-
call: call,
|
|
178
|
-
message: "ChangeEncryptionSecret: \(error.localizedDescription)")
|
|
166
|
+
if isEncryption {
|
|
167
|
+
self.call = call
|
|
168
|
+
let retHandler: ReturnHandler = ReturnHandler()
|
|
169
|
+
do {
|
|
170
|
+
// close all connections
|
|
171
|
+
try closeAllConnections()
|
|
172
|
+
if isBiometricAuth {
|
|
173
|
+
let dbLocation = databaseLocation
|
|
174
|
+
let mPrefixKeychain = prefixKeychain
|
|
175
|
+
bioIdAuth.authenticateUser { [weak self] message in
|
|
176
|
+
if let message = message {
|
|
177
|
+
self?.intBioMessage = message
|
|
179
178
|
return
|
|
179
|
+
} else {
|
|
180
|
+
do {
|
|
181
|
+
try UtilsSecret.changeEncryptionSecret(
|
|
182
|
+
prefix: mPrefixKeychain,
|
|
183
|
+
passphrase: passphrase,
|
|
184
|
+
oldPassphrase: oldPassphrase,
|
|
185
|
+
databaseLocation: dbLocation)
|
|
186
|
+
retHandler.rResult(call: call)
|
|
187
|
+
return
|
|
188
|
+
} catch UtilsSecretError.changeEncryptionSecret(let message) {
|
|
189
|
+
let msg = "ChangeEncryptionSecret: \(message)"
|
|
190
|
+
retHandler.rResult(call: call, message: msg)
|
|
191
|
+
return
|
|
192
|
+
} catch let error {
|
|
193
|
+
retHandler.rResult(
|
|
194
|
+
call: call,
|
|
195
|
+
message: "ChangeEncryptionSecret: \(error.localizedDescription)")
|
|
196
|
+
return
|
|
197
|
+
}
|
|
180
198
|
}
|
|
181
199
|
}
|
|
200
|
+
} else {
|
|
201
|
+
// set encryption secret
|
|
202
|
+
try UtilsSecret
|
|
203
|
+
.changeEncryptionSecret(prefix: prefixKeychain,
|
|
204
|
+
passphrase: passphrase,
|
|
205
|
+
oldPassphrase: oldPassphrase,
|
|
206
|
+
databaseLocation: databaseLocation)
|
|
207
|
+
retHandler.rResult(call: call)
|
|
208
|
+
return
|
|
182
209
|
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
210
|
+
} catch UtilsSecretError.changeEncryptionSecret(let message) {
|
|
211
|
+
let msg = "ChangeEncryptionSecret: \(message)"
|
|
212
|
+
retHandler.rResult(call: call, message: msg)
|
|
213
|
+
return
|
|
214
|
+
} catch let error {
|
|
215
|
+
retHandler.rResult(
|
|
216
|
+
call: call,
|
|
217
|
+
message: "ChangeEncryptionSecret: \(error.localizedDescription)")
|
|
191
218
|
return
|
|
192
219
|
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
retHandler.rResult(call: call, message: msg)
|
|
196
|
-
return
|
|
197
|
-
} catch let error {
|
|
198
|
-
retHandler.rResult(
|
|
199
|
-
call: call,
|
|
200
|
-
message: "ChangeEncryptionSecret: \(error.localizedDescription)")
|
|
201
|
-
return
|
|
220
|
+
} else {
|
|
221
|
+
throw CapacitorSQLiteError.failed(message: "No Encryption set in capacitor.config")
|
|
202
222
|
}
|
|
203
223
|
} else {
|
|
204
224
|
throw CapacitorSQLiteError.failed(message: initMessage)
|
|
@@ -247,7 +267,7 @@ enum CapacitorSQLiteError: Error {
|
|
|
247
267
|
let mDb: Database = try Database(
|
|
248
268
|
databaseLocation: databaseLocation,
|
|
249
269
|
databaseName: databasePath,
|
|
250
|
-
encrypted: false, account: account,
|
|
270
|
+
encrypted: false, isEncryption: isEncryption, account: account,
|
|
251
271
|
mode: "no-encryption", version: version,
|
|
252
272
|
vUpgDict: [:])
|
|
253
273
|
dbDict[databasePath] = mDb
|
|
@@ -297,12 +317,15 @@ enum CapacitorSQLiteError: Error {
|
|
|
297
317
|
let msg = "Connection \(mDbName) already exists"
|
|
298
318
|
throw CapacitorSQLiteError.failed(message: msg)
|
|
299
319
|
}
|
|
300
|
-
|
|
320
|
+
if encrypted && !isEncryption {
|
|
321
|
+
let msg = "Database cannot be encrypted as 'No Encryption' set in capacitor.config"
|
|
322
|
+
throw CapacitorSQLiteError.failed(message: msg)
|
|
323
|
+
}
|
|
301
324
|
do {
|
|
302
325
|
let mDb: Database = try Database(
|
|
303
326
|
databaseLocation: databaseLocation,
|
|
304
327
|
databaseName: "\(mDbName)SQLite.db",
|
|
305
|
-
encrypted: encrypted, account: account,
|
|
328
|
+
encrypted: encrypted, isEncryption: isEncryption, account: account,
|
|
306
329
|
mode: mode, version: version,
|
|
307
330
|
vUpgDict: vUpgDict)
|
|
308
331
|
dbDict[mDbName] = mDb
|
|
@@ -738,7 +761,25 @@ enum CapacitorSQLiteError: Error {
|
|
|
738
761
|
|
|
739
762
|
do {
|
|
740
763
|
if !mDb.isDBOpen() {
|
|
741
|
-
|
|
764
|
+
// check the state of the DB
|
|
765
|
+
let state: State = UtilsSQLCipher.getDatabaseState(databaseLocation: databaseLocation, databaseName: "\(mDbName)SQLite.db", account: account)
|
|
766
|
+
if !isEncryption && (state.rawValue == "ENCRYPTEDGLOBALSECRET" ||
|
|
767
|
+
state.rawValue == "ENCRYPTEDSECRET") {
|
|
768
|
+
var msg = "Cannot delete an Encrypted database with "
|
|
769
|
+
msg += "No Encryption set in capacitor.config"
|
|
770
|
+
throw CapacitorSQLiteError.failed(message: msg)
|
|
771
|
+
} else if state.rawValue == "UNENCRYPTED" {
|
|
772
|
+
do {
|
|
773
|
+
try UtilsSQLCipher.deleteDB(databaseLocation: databaseLocation,
|
|
774
|
+
databaseName: "\(mDbName)SQLite.db")
|
|
775
|
+
return
|
|
776
|
+
} catch UtilsSQLCipherError.deleteDB(let message ) {
|
|
777
|
+
throw CapacitorSQLiteError.failed(message: message)
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
} else {
|
|
781
|
+
try mDb.open()
|
|
782
|
+
}
|
|
742
783
|
}
|
|
743
784
|
let res: Bool = try mDb.deleteDB(databaseName: "\(mDbName)SQLite.db")
|
|
744
785
|
if res {
|
|
@@ -809,7 +850,7 @@ enum CapacitorSQLiteError: Error {
|
|
|
809
850
|
do {
|
|
810
851
|
mDb = try Database(
|
|
811
852
|
databaseLocation: databaseLocation, databaseName: dbName,
|
|
812
|
-
encrypted: encrypted, account: account,
|
|
853
|
+
encrypted: encrypted, isEncryption: isEncryption, account: account,
|
|
813
854
|
mode: inMode, version: version, vUpgDict: [:])
|
|
814
855
|
try mDb.open()
|
|
815
856
|
} catch DatabaseError.open(let message) {
|
|
@@ -1215,6 +1215,7 @@ public class CapacitorSQLitePlugin: CAPPlugin {
|
|
|
1215
1215
|
}
|
|
1216
1216
|
private func sqliteConfig() -> SqliteConfig {
|
|
1217
1217
|
var config = SqliteConfig()
|
|
1218
|
+
config.iosIsEncryption = 1
|
|
1218
1219
|
config.biometricAuth = 0
|
|
1219
1220
|
config.iosKeychainPrefix = ""
|
|
1220
1221
|
if let keychainPrefix = getConfigValue("iosKeychainPrefix") as? String {
|
|
@@ -1224,19 +1225,25 @@ public class CapacitorSQLitePlugin: CAPPlugin {
|
|
|
1224
1225
|
as? String {
|
|
1225
1226
|
config.iosDatabaseLocation = iosDatabaseLocation
|
|
1226
1227
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1228
|
+
if let isEncryption = getConfigValue("iosIsEncryption") as? Bool {
|
|
1229
|
+
if !isEncryption {
|
|
1230
|
+
config.iosIsEncryption = 0
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
if config.iosIsEncryption == 1 {
|
|
1234
|
+
if let iosBiometric = getConfigValue("iosBiometric") as? [String: Any] {
|
|
1235
|
+
if let bioAuth = iosBiometric["biometricAuth"] as? Bool {
|
|
1236
|
+
if bioAuth {
|
|
1237
|
+
config.biometricAuth = 1
|
|
1238
|
+
if let bioTitle = iosBiometric["biometricTitle"] as? String {
|
|
1239
|
+
config.biometricTitle = bioTitle.count > 0
|
|
1240
|
+
? bioTitle
|
|
1241
|
+
: "Biometric login for capacitor sqlite"
|
|
1242
|
+
}
|
|
1236
1243
|
}
|
|
1237
1244
|
}
|
|
1238
|
-
}
|
|
1239
1245
|
|
|
1246
|
+
}
|
|
1240
1247
|
}
|
|
1241
1248
|
return config
|
|
1242
1249
|
}
|
|
@@ -31,6 +31,7 @@ class Database {
|
|
|
31
31
|
var dbName: String
|
|
32
32
|
var dbVersion: Int
|
|
33
33
|
var encrypted: Bool
|
|
34
|
+
var isEncryption: Bool
|
|
34
35
|
var mode: String
|
|
35
36
|
var vUpgDict: [Int: [String: Any]]
|
|
36
37
|
var databaseLocation: String
|
|
@@ -44,10 +45,11 @@ class Database {
|
|
|
44
45
|
|
|
45
46
|
// MARK: - Init
|
|
46
47
|
init(databaseLocation: String, databaseName: String, encrypted: Bool,
|
|
47
|
-
account: String, mode: String, version: Int,
|
|
48
|
+
isEncryption: Bool, account: String, mode: String, version: Int,
|
|
48
49
|
vUpgDict: [Int: [String: Any]] = [:]) throws {
|
|
49
50
|
self.dbVersion = version
|
|
50
51
|
self.encrypted = encrypted
|
|
52
|
+
self.isEncryption = isEncryption
|
|
51
53
|
self.account = account
|
|
52
54
|
self.dbName = databaseName
|
|
53
55
|
self.mode = mode
|
|
@@ -95,23 +97,28 @@ class Database {
|
|
|
95
97
|
// swiftlint:disable function_body_length
|
|
96
98
|
func open () throws {
|
|
97
99
|
var password: String = ""
|
|
98
|
-
if encrypted && (mode == "secret" || mode == "encryption") {
|
|
100
|
+
if isEncryption && encrypted && (mode == "secret" || mode == "encryption") {
|
|
99
101
|
password = UtilsSecret.getPassphrase(account: account)
|
|
100
102
|
}
|
|
101
103
|
if mode == "encryption" {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
if isEncryption {
|
|
105
|
+
do {
|
|
106
|
+
let ret: Bool = try UtilsEncryption
|
|
107
|
+
.encryptDatabase(databaseLocation: databaseLocation,
|
|
108
|
+
filePath: path, password: password)
|
|
109
|
+
if !ret {
|
|
110
|
+
let msg: String = "Failed in encryption"
|
|
111
|
+
throw DatabaseError.open(message: msg)
|
|
112
|
+
}
|
|
113
|
+
} catch UtilsEncryptionError.encryptionFailed(let message) {
|
|
114
|
+
let msg: String = "Failed in encryption \(message)"
|
|
108
115
|
throw DatabaseError.open(message: msg)
|
|
109
116
|
}
|
|
110
|
-
}
|
|
111
|
-
let msg: String = "
|
|
117
|
+
} else {
|
|
118
|
+
let msg: String = "No Encryption set in capacitor.config"
|
|
112
119
|
throw DatabaseError.open(message: msg)
|
|
113
|
-
|
|
114
120
|
}
|
|
121
|
+
|
|
115
122
|
}
|
|
116
123
|
|
|
117
124
|
do {
|
|
@@ -446,18 +453,27 @@ class Database {
|
|
|
446
453
|
let isExists: Bool = try UtilsJson.isTableExists(
|
|
447
454
|
mDB: self, tableName: "sync_table")
|
|
448
455
|
if !isExists {
|
|
449
|
-
|
|
450
|
-
let
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
456
|
+
// check if there are tables with last_modified column
|
|
457
|
+
let isLastModified: Bool = try UtilsJson.isLastModified(mDB: self)
|
|
458
|
+
if isLastModified {
|
|
459
|
+
let date = Date()
|
|
460
|
+
let syncTime: Int = Int(date.timeIntervalSince1970)
|
|
461
|
+
var stmt: String = "CREATE TABLE IF NOT EXISTS "
|
|
462
|
+
stmt.append("sync_table (")
|
|
463
|
+
stmt.append("id INTEGER PRIMARY KEY NOT NULL,")
|
|
464
|
+
stmt.append("sync_date INTEGER);")
|
|
465
|
+
stmt.append("INSERT INTO sync_table (sync_date) ")
|
|
466
|
+
stmt.append("VALUES ('\(syncTime)');")
|
|
467
|
+
retObj = try executeSQL(sql: stmt)
|
|
468
|
+
} else {
|
|
469
|
+
let msg = "No last_modified column in tables"
|
|
470
|
+
throw DatabaseError.createSyncTable(message: msg)
|
|
471
|
+
}
|
|
458
472
|
} else {
|
|
459
473
|
retObj = 0
|
|
460
474
|
}
|
|
475
|
+
} catch UtilsJsonError.isLastModified(let message) {
|
|
476
|
+
throw DatabaseError.createSyncTable(message: message)
|
|
461
477
|
} catch UtilsJsonError.tableNotExists(let message) {
|
|
462
478
|
throw DatabaseError.createSyncTable(message: message)
|
|
463
479
|
} catch DatabaseError.executeSQL(let message) {
|
|
@@ -471,6 +487,11 @@ class Database {
|
|
|
471
487
|
func setSyncDate(syncDate: String ) throws -> Bool {
|
|
472
488
|
var retBool: Bool = false
|
|
473
489
|
do {
|
|
490
|
+
let isExists: Bool = try UtilsJson.isTableExists(
|
|
491
|
+
mDB: self, tableName: "sync_table")
|
|
492
|
+
if !isExists {
|
|
493
|
+
throw DatabaseError.createSyncDate(message: "No sync_table available")
|
|
494
|
+
}
|
|
474
495
|
let dateFormatter = DateFormatter()
|
|
475
496
|
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
|
476
497
|
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
|
|
@@ -487,6 +508,8 @@ class Database {
|
|
|
487
508
|
} else {
|
|
488
509
|
throw DatabaseError.createSyncDate(message: "wrong syncDate")
|
|
489
510
|
}
|
|
511
|
+
} catch UtilsJsonError.tableNotExists(let message) {
|
|
512
|
+
throw DatabaseError.createSyncDate(message: message)
|
|
490
513
|
} catch DatabaseError.runSQL(let message) {
|
|
491
514
|
throw DatabaseError.createSyncDate(message: message)
|
|
492
515
|
}
|
|
@@ -498,7 +521,14 @@ class Database {
|
|
|
498
521
|
func getSyncDate( ) throws -> Int64 {
|
|
499
522
|
var syncDate: Int64 = 0
|
|
500
523
|
do {
|
|
524
|
+
let isExists: Bool = try UtilsJson.isTableExists(
|
|
525
|
+
mDB: self, tableName: "sync_table")
|
|
526
|
+
if !isExists {
|
|
527
|
+
throw DatabaseError.getSyncDate(message: "No sync_table available")
|
|
528
|
+
}
|
|
501
529
|
syncDate = try ExportToJson.getSyncDate(mDB: self)
|
|
530
|
+
} catch UtilsJsonError.tableNotExists(let message) {
|
|
531
|
+
throw DatabaseError.getSyncDate(message: message)
|
|
502
532
|
} catch ExportToJsonError.getSyncDate(let message) {
|
|
503
533
|
throw DatabaseError.getSyncDate(message: message)
|
|
504
534
|
}
|
|
@@ -88,6 +88,12 @@ class ExportToJson {
|
|
|
88
88
|
let resTables = try UtilsSQLCipher.querySQL(
|
|
89
89
|
mDB: mDB, sql: query, values: [])
|
|
90
90
|
if resTables.count > 0 {
|
|
91
|
+
let isExists: Bool = try UtilsJson.isTableExists(
|
|
92
|
+
mDB: mDB, tableName: "sync_table")
|
|
93
|
+
if !isExists && expMode == "partial" {
|
|
94
|
+
throw ExportToJsonError.createExportObject(message: "No sync_table available")
|
|
95
|
+
}
|
|
96
|
+
|
|
91
97
|
switch expMode {
|
|
92
98
|
case "partial" :
|
|
93
99
|
tables = try ExportToJson
|
|
@@ -102,6 +108,8 @@ class ExportToJson {
|
|
|
102
108
|
message: "expMode \(expMode) not defined")
|
|
103
109
|
}
|
|
104
110
|
}
|
|
111
|
+
} catch UtilsJsonError.tableNotExists(let message) {
|
|
112
|
+
throw ExportToJsonError.createExportObject(message: message)
|
|
105
113
|
} catch UtilsSQLCipherError.querySQL(let message) {
|
|
106
114
|
throw ExportToJsonError.createExportObject(
|
|
107
115
|
message: "Error get table's names failed : \(message)")
|
|
@@ -194,12 +194,16 @@ class ImportFromJson {
|
|
|
194
194
|
-> [String] {
|
|
195
195
|
var statements: [String] = []
|
|
196
196
|
var stmt: String
|
|
197
|
+
var isLastModified: Bool = false
|
|
197
198
|
stmt = "CREATE TABLE IF NOT EXISTS "
|
|
198
199
|
stmt.append(tableName)
|
|
199
200
|
stmt.append(" (")
|
|
200
201
|
for jpos in 0..<mSchema.count {
|
|
201
202
|
if let jSchColumn = mSchema[jpos].column {
|
|
202
203
|
if jSchColumn.count > 0 {
|
|
204
|
+
if jSchColumn == "last_modified" {
|
|
205
|
+
isLastModified = true
|
|
206
|
+
}
|
|
203
207
|
stmt.append(jSchColumn)
|
|
204
208
|
}
|
|
205
209
|
}
|
|
@@ -221,20 +225,22 @@ class ImportFromJson {
|
|
|
221
225
|
}
|
|
222
226
|
stmt.append(");")
|
|
223
227
|
statements.append(stmt)
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
228
|
+
if isLastModified {
|
|
229
|
+
// create trigger last_modified associated with the table
|
|
230
|
+
let triggerName: String = tableName + "_trigger_last_modified"
|
|
231
|
+
stmt = "CREATE TRIGGER IF NOT EXISTS "
|
|
232
|
+
stmt.append(triggerName)
|
|
233
|
+
stmt.append(" AFTER UPDATE ON ")
|
|
234
|
+
stmt.append(tableName)
|
|
235
|
+
stmt.append(" FOR EACH ROW ")
|
|
236
|
+
stmt.append("WHEN NEW.last_modified <= OLD.last_modified ")
|
|
237
|
+
stmt.append("BEGIN UPDATE ")
|
|
238
|
+
stmt.append(tableName)
|
|
239
|
+
stmt.append(" SET last_modified = (strftime('%s','now')) ")
|
|
240
|
+
stmt.append("WHERE id=OLD.id; ")
|
|
241
|
+
stmt.append("END;")
|
|
242
|
+
statements.append(stmt)
|
|
243
|
+
}
|
|
238
244
|
return statements
|
|
239
245
|
}
|
|
240
246
|
|
|
@@ -17,6 +17,7 @@ enum UtilsJsonError: Error {
|
|
|
17
17
|
case validateIndexes(message: String)
|
|
18
18
|
case validateTriggers(message: String)
|
|
19
19
|
case validateViews(message: String)
|
|
20
|
+
case isLastModified(message: String)
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
// swiftlint:disable type_body_length
|
|
@@ -46,6 +47,33 @@ class UtilsJson {
|
|
|
46
47
|
return ret
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
// MARK: - ImportFromJson - IsLastModified
|
|
51
|
+
|
|
52
|
+
class func isLastModified(mDB: Database) throws -> Bool {
|
|
53
|
+
var msg: String = "Error LastModified: "
|
|
54
|
+
if !mDB.isDBOpen() {
|
|
55
|
+
msg.append("Database not opened")
|
|
56
|
+
throw UtilsJsonError.isLastModified(message: msg)
|
|
57
|
+
}
|
|
58
|
+
var ret: Bool = false
|
|
59
|
+
do {
|
|
60
|
+
let tableList: [String] = try UtilsDrop.getTablesNames(mDB: mDB)
|
|
61
|
+
for table in tableList {
|
|
62
|
+
let namesTypes: JsonNamesTypes = try getTableColumnNamesTypes(mDB: mDB,
|
|
63
|
+
tableName: table)
|
|
64
|
+
if namesTypes.names.contains("last_modified") {
|
|
65
|
+
ret = true
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} catch UtilsJsonError.getTableColumnNamesTypes(let message) {
|
|
70
|
+
throw UtilsJsonError.isLastModified(message: message)
|
|
71
|
+
} catch UtilsDropError.getTablesNamesFailed(let message) {
|
|
72
|
+
throw UtilsJsonError.isLastModified(message: message)
|
|
73
|
+
}
|
|
74
|
+
return ret
|
|
75
|
+
}
|
|
76
|
+
|
|
49
77
|
// MARK: - ImportFromJson - IsViewExists
|
|
50
78
|
|
|
51
79
|
class func isViewExists(mDB: Database, viewName: String)
|