@capgo/capacitor-data-storage-sqlite 6.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.
- package/CapacitorDataStorageSqlite.podspec +18 -0
- package/LICENSE +21 -0
- package/android/build.gradle +63 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/CapacitorDataStorageSqlite.java +387 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/CapacitorDataStorageSqlitePlugin.java +447 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/RetHandler.java +117 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/cdssUtils/Data.java +8 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/cdssUtils/Global.java +7 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/cdssUtils/ImportExportJson/JsonStore.java +131 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/cdssUtils/ImportExportJson/JsonTable.java +110 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/cdssUtils/ImportExportJson/JsonValue.java +89 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/cdssUtils/StorageDatabaseHelper.java +691 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitordatastoragesqlite/cdssUtils/UtilsSQLCipher.java +162 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +995 -0
- package/dist/esm/definitions.d.ts +296 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +9 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web-utils/Data.d.ts +5 -0
- package/dist/esm/web-utils/Data.js +3 -0
- package/dist/esm/web-utils/Data.js.map +1 -0
- package/dist/esm/web-utils/StorageDatabaseHelper.d.ts +23 -0
- package/dist/esm/web-utils/StorageDatabaseHelper.js +247 -0
- package/dist/esm/web-utils/StorageDatabaseHelper.js.map +1 -0
- package/dist/esm/web-utils/json-utils.d.ts +15 -0
- package/dist/esm/web-utils/json-utils.js +76 -0
- package/dist/esm/web-utils/json-utils.js.map +1 -0
- package/dist/esm/web.d.ts +27 -0
- package/dist/esm/web.js +295 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +633 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +635 -0
- package/dist/plugin.js.map +1 -0
- package/electron/dist/plugin.js +1044 -0
- package/electron/dist/plugin.js.map +1 -0
- package/electron/rollup.config.mjs +17 -0
- package/electron/tsconfig.json +19 -0
- package/ios/Plugin/CapacitorDataStorageSqlite.swift +550 -0
- package/ios/Plugin/CapacitorDataStorageSqlitePlugin.h +10 -0
- package/ios/Plugin/CapacitorDataStorageSqlitePlugin.m +29 -0
- package/ios/Plugin/CapacitorDataStorageSqlitePlugin.swift +550 -0
- package/ios/Plugin/Data.swift +16 -0
- package/ios/Plugin/Global.swift +13 -0
- package/ios/Plugin/ImportExportJson/JsonStore.swift +47 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/ReturnHandler.swift +85 -0
- package/ios/Plugin/StorageDatabaseHelper.swift +603 -0
- package/ios/Plugin/Utils/Blob.swift +41 -0
- package/ios/Plugin/Utils/UtilsBinding.swift +73 -0
- package/ios/Plugin/Utils/UtilsEncryption.swift +79 -0
- package/ios/Plugin/Utils/UtilsFile.swift +244 -0
- package/ios/Plugin/Utils/UtilsSQLCipher.swift +605 -0
- package/package.json +96 -0
- package/readme.md +203 -0
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
//
|
|
2
|
+
// UtilsSQLCipher.swift
|
|
3
|
+
// Plugin
|
|
4
|
+
//
|
|
5
|
+
// Created by Quéau Jean Pierre on 12/04/2021.
|
|
6
|
+
// Copyright © 2021 Max Lynch. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import SQLCipher
|
|
11
|
+
|
|
12
|
+
let TABLEINDEX: String = "sqlite_sequence"
|
|
13
|
+
let IDXCOLNAME: String = "name"
|
|
14
|
+
let IDXCOLSEQ: String = "seq"
|
|
15
|
+
let COLID: String = "id"
|
|
16
|
+
let COLNAME: String = "name"
|
|
17
|
+
let COLVALUE: String = "value"
|
|
18
|
+
|
|
19
|
+
enum UtilsSQLCipherError: Error {
|
|
20
|
+
case openOrCreateDatabase(message: String)
|
|
21
|
+
case bindFailed
|
|
22
|
+
case closeDB(message: String)
|
|
23
|
+
case close(message: String)
|
|
24
|
+
case changePassword(message: String)
|
|
25
|
+
case execute(message: String)
|
|
26
|
+
case prepareSQL(message: String)
|
|
27
|
+
case querySQL(message: String)
|
|
28
|
+
case fetchColumnInfo(message: String)
|
|
29
|
+
case deleteDB(message: String)
|
|
30
|
+
case insertData(message: String)
|
|
31
|
+
case updateData(message: String)
|
|
32
|
+
case creationTable(message: String)
|
|
33
|
+
case creationIndex(message: String)
|
|
34
|
+
case dropTable(message: String)
|
|
35
|
+
case getTables(message: String)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// swiftlint:disable file_length
|
|
39
|
+
// swiftlint:disable type_body_length
|
|
40
|
+
class UtilsSQLCipher {
|
|
41
|
+
|
|
42
|
+
// MARK: - OpenOrCreateDatabase
|
|
43
|
+
|
|
44
|
+
class func openOrCreateDatabase(filename: String,
|
|
45
|
+
password: String = "",
|
|
46
|
+
readonly: Bool = false
|
|
47
|
+
) throws -> OpaquePointer? {
|
|
48
|
+
|
|
49
|
+
let flags = readonly ? SQLITE_OPEN_READONLY :
|
|
50
|
+
SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE
|
|
51
|
+
var mDB: OpaquePointer?
|
|
52
|
+
if sqlite3_open_v2(filename, &mDB, flags |
|
|
53
|
+
SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK {
|
|
54
|
+
|
|
55
|
+
if password.count > 0 {
|
|
56
|
+
let keyStatementString = """
|
|
57
|
+
PRAGMA key = '\(password)';
|
|
58
|
+
"""
|
|
59
|
+
let msg: String = "Wrong Secret"
|
|
60
|
+
if sqlite3_exec(mDB, keyStatementString, nil, nil, nil)
|
|
61
|
+
== SQLITE_OK {
|
|
62
|
+
var stmt: String = "SELECT count(*) FROM "
|
|
63
|
+
stmt.append("sqlite_master;")
|
|
64
|
+
if sqlite3_exec(mDB, stmt, nil, nil, nil) !=
|
|
65
|
+
SQLITE_OK {
|
|
66
|
+
throw UtilsSQLCipherError
|
|
67
|
+
.openOrCreateDatabase(message: msg)
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
throw UtilsSQLCipherError
|
|
71
|
+
.openOrCreateDatabase(message: msg)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* this should work but doe not sqlite3_key_v2 is not known
|
|
76
|
+
if password.count > 0 {
|
|
77
|
+
let nKey:Int32 = Int32(password.count)
|
|
78
|
+
if sqlite3_key_v2(mDB!, filename, password, nKey) == SQLITE_OK {
|
|
79
|
+
var stmt: String = "SELECT count(*) FROM "
|
|
80
|
+
stmt.append("sqlite_master;")
|
|
81
|
+
if sqlite3_exec(mDB, stmt, nil, nil, nil) !=
|
|
82
|
+
SQLITE_OK {
|
|
83
|
+
print("Unable to open a database \(filename)")
|
|
84
|
+
throw UtilsSQLCipherError
|
|
85
|
+
.openOrCreateDatabase(message: msg)
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
print("Unable to open a database \(filename)")
|
|
89
|
+
throw UtilsSQLCipherError
|
|
90
|
+
.openOrCreateDatabase(message: msg)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
print("Successfully opened database \(filename)")
|
|
94
|
+
*/
|
|
95
|
+
return mDB
|
|
96
|
+
} else {
|
|
97
|
+
let message: String = "open_v2 failed"
|
|
98
|
+
throw UtilsSQLCipherError
|
|
99
|
+
.openOrCreateDatabase(message: message)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// MARK: - ChangePassword
|
|
104
|
+
|
|
105
|
+
class func changePassword(filename: String, password: String,
|
|
106
|
+
newpassword: String) throws {
|
|
107
|
+
do {
|
|
108
|
+
// open the db with password
|
|
109
|
+
let oDB: OpaquePointer? = try
|
|
110
|
+
openOrCreateDatabase(filename: filename,
|
|
111
|
+
password: password,
|
|
112
|
+
readonly: false)
|
|
113
|
+
// change password
|
|
114
|
+
let keyStatementString = """
|
|
115
|
+
PRAGMA rekey = '\(newpassword)';
|
|
116
|
+
"""
|
|
117
|
+
let returnCode: Int32 = sqlite3_exec(
|
|
118
|
+
oDB, keyStatementString, nil, nil, nil)
|
|
119
|
+
if returnCode != SQLITE_OK {
|
|
120
|
+
throw UtilsSQLCipherError
|
|
121
|
+
.changePassword(message: "change password")
|
|
122
|
+
}
|
|
123
|
+
// close the db
|
|
124
|
+
try UtilsSQLCipher.close(oDB: oDB)
|
|
125
|
+
|
|
126
|
+
} catch UtilsSQLCipherError.openOrCreateDatabase(let message) {
|
|
127
|
+
throw UtilsSQLCipherError
|
|
128
|
+
.changePassword(message: message)
|
|
129
|
+
} catch UtilsSQLCipherError.close(_) {
|
|
130
|
+
throw UtilsSQLCipherError
|
|
131
|
+
.changePassword(message: "close failed")
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// MARK: - CloseDB
|
|
136
|
+
|
|
137
|
+
class func closeDB(mDB: StorageDatabaseHelper) throws {
|
|
138
|
+
do {
|
|
139
|
+
try UtilsSQLCipher.close(oDB: mDB.mDB)
|
|
140
|
+
} catch UtilsSQLCipherError.close(let message) {
|
|
141
|
+
throw UtilsSQLCipherError.closeDB(message: message)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// MARK: - Close
|
|
146
|
+
|
|
147
|
+
class func close(oDB: OpaquePointer?) throws {
|
|
148
|
+
var message: String = ""
|
|
149
|
+
let returnCode: Int32 = sqlite3_close_v2(oDB)
|
|
150
|
+
if returnCode != SQLITE_OK {
|
|
151
|
+
let errmsg: String = String(
|
|
152
|
+
cString: sqlite3_errmsg(oDB))
|
|
153
|
+
message = "Error: closing the database rc: " +
|
|
154
|
+
"\(returnCode) message: \(errmsg)"
|
|
155
|
+
throw UtilsSQLCipherError.close(message: message)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// MARK: - PrepareSQL
|
|
160
|
+
|
|
161
|
+
// swiftlint:disable function_body_length
|
|
162
|
+
class func prepareSQL(mDB: StorageDatabaseHelper,
|
|
163
|
+
sql: String, values: [Any]) throws -> Int64 {
|
|
164
|
+
var msg: String = "Error prepareSQL: "
|
|
165
|
+
if !mDB.isOpen {
|
|
166
|
+
msg.append("Database not opened")
|
|
167
|
+
throw UtilsSQLCipherError.prepareSQL(message: msg)
|
|
168
|
+
}
|
|
169
|
+
var runSQLStatement: OpaquePointer?
|
|
170
|
+
var message: String = ""
|
|
171
|
+
var lastId: Int64 = -1
|
|
172
|
+
|
|
173
|
+
var returnCode: Int32 = sqlite3_prepare_v2(
|
|
174
|
+
mDB.mDB, sql, -1, &runSQLStatement, nil)
|
|
175
|
+
if returnCode == SQLITE_OK {
|
|
176
|
+
if !values.isEmpty {
|
|
177
|
+
// do the binding of values
|
|
178
|
+
var idx: Int = 1
|
|
179
|
+
for value in values {
|
|
180
|
+
do {
|
|
181
|
+
try UtilsBinding.bind(handle: runSQLStatement,
|
|
182
|
+
value: value, idx: idx)
|
|
183
|
+
idx += 1
|
|
184
|
+
} catch let error as NSError {
|
|
185
|
+
message = "Error: prepareSQL bind failed "
|
|
186
|
+
message.append(error.localizedDescription)
|
|
187
|
+
}
|
|
188
|
+
if message.count > 0 { break }
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
returnCode = sqlite3_step(runSQLStatement)
|
|
192
|
+
if returnCode != SQLITE_DONE {
|
|
193
|
+
let errmsg: String = String(
|
|
194
|
+
cString: sqlite3_errmsg(mDB.mDB))
|
|
195
|
+
message = "Error: prepareSQL step failed rc: "
|
|
196
|
+
message.append("\(returnCode) message: \(errmsg)")
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
let errmsg: String = String(
|
|
200
|
+
cString: sqlite3_errmsg(mDB.mDB))
|
|
201
|
+
message = "Error: prepareSQL prepare failed rc: "
|
|
202
|
+
message.append("\(returnCode) message: \(errmsg)")
|
|
203
|
+
}
|
|
204
|
+
returnCode = sqlite3_finalize(runSQLStatement)
|
|
205
|
+
if returnCode != SQLITE_OK {
|
|
206
|
+
let errmsg: String = String(
|
|
207
|
+
cString: sqlite3_errmsg(mDB.mDB))
|
|
208
|
+
message = "Error: prepareSQL finalize failed rc: "
|
|
209
|
+
message.append("\(returnCode) message: \(errmsg)")
|
|
210
|
+
}
|
|
211
|
+
if message.count > 0 {
|
|
212
|
+
throw UtilsSQLCipherError.prepareSQL(message: message)
|
|
213
|
+
} else {
|
|
214
|
+
lastId = Int64(sqlite3_last_insert_rowid(mDB.mDB))
|
|
215
|
+
return lastId
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// swiftlint:enable function_body_length
|
|
219
|
+
|
|
220
|
+
// MARK: - querySQL
|
|
221
|
+
|
|
222
|
+
class func querySQL(mDB: StorageDatabaseHelper, sql: String,
|
|
223
|
+
values: [String]) throws -> [[String: Any]] {
|
|
224
|
+
var msg: String = "Error querySQL: "
|
|
225
|
+
if !mDB.isOpen {
|
|
226
|
+
msg.append("Database not opened")
|
|
227
|
+
throw UtilsSQLCipherError.querySQL(message: msg)
|
|
228
|
+
}
|
|
229
|
+
var selectSQLStatement: OpaquePointer?
|
|
230
|
+
var result: [[String: Any]] = []
|
|
231
|
+
var message: String = ""
|
|
232
|
+
var returnCode: Int32 =
|
|
233
|
+
sqlite3_prepare_v2(mDB.mDB, sql, -1, &selectSQLStatement,
|
|
234
|
+
nil)
|
|
235
|
+
if returnCode == SQLITE_OK {
|
|
236
|
+
if !values.isEmpty {
|
|
237
|
+
// do the binding of values
|
|
238
|
+
message = UtilsBinding.bindValues(
|
|
239
|
+
handle: selectSQLStatement, values: values)
|
|
240
|
+
}
|
|
241
|
+
if message.count == 0 {
|
|
242
|
+
do {
|
|
243
|
+
result = try UtilsSQLCipher.fetchColumnInfo(
|
|
244
|
+
handle: selectSQLStatement)
|
|
245
|
+
} catch UtilsSQLCipherError
|
|
246
|
+
.fetchColumnInfo(let message) {
|
|
247
|
+
throw UtilsSQLCipherError.querySQL(message: message)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
let errmsg: String = String(
|
|
252
|
+
cString: sqlite3_errmsg(mDB.mDB))
|
|
253
|
+
message = "Error: querySQL prepare failed rc: "
|
|
254
|
+
message.append("\(returnCode) message: \(errmsg)")
|
|
255
|
+
}
|
|
256
|
+
returnCode = sqlite3_finalize(selectSQLStatement)
|
|
257
|
+
if returnCode != SQLITE_OK {
|
|
258
|
+
let errmsg: String = String(
|
|
259
|
+
cString: sqlite3_errmsg(mDB.mDB))
|
|
260
|
+
message = "Error: querySQL finalize failed rc: "
|
|
261
|
+
message.append("\(returnCode) message: \(errmsg)")
|
|
262
|
+
}
|
|
263
|
+
if message.count > 0 {
|
|
264
|
+
throw UtilsSQLCipherError.querySQL(message: message)
|
|
265
|
+
} else {
|
|
266
|
+
return result
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// MARK: - FetchColumnInfo
|
|
271
|
+
|
|
272
|
+
class func fetchColumnInfo(handle: OpaquePointer?)
|
|
273
|
+
throws -> [[String: Any]] {
|
|
274
|
+
var result: [[String: Any]] = []
|
|
275
|
+
var fetchColumnInfo = true
|
|
276
|
+
var columnCount: Int32 = 0
|
|
277
|
+
var columnNames = [String]()
|
|
278
|
+
var columnTypes = [Int32]()
|
|
279
|
+
|
|
280
|
+
while sqlite3_step(handle) == SQLITE_ROW {
|
|
281
|
+
if fetchColumnInfo {
|
|
282
|
+
columnCount = sqlite3_column_count(handle)
|
|
283
|
+
for index in 0..<columnCount {
|
|
284
|
+
guard let name = sqlite3_column_name(handle, index)
|
|
285
|
+
else {
|
|
286
|
+
var message = "Error: querySQL column_name "
|
|
287
|
+
message.append("failed")
|
|
288
|
+
throw UtilsSQLCipherError
|
|
289
|
+
.fetchColumnInfo(message: message)
|
|
290
|
+
}
|
|
291
|
+
columnNames.append(String(cString: name))
|
|
292
|
+
columnTypes.append(UtilsSQLCipher.getColumnType(
|
|
293
|
+
index: index, stmt: handle))
|
|
294
|
+
}
|
|
295
|
+
fetchColumnInfo = false
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
var rowData: [String: Any] = [:]
|
|
299
|
+
for index in 0..<columnCount {
|
|
300
|
+
let key = columnNames[Int(index)]
|
|
301
|
+
let type = columnTypes[Int(index)]
|
|
302
|
+
|
|
303
|
+
if let val = UtilsSQLCipher.getColumnValue(
|
|
304
|
+
index: index, type: type, stmt: handle) {
|
|
305
|
+
rowData[key] = val
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
result.append(rowData)
|
|
309
|
+
}
|
|
310
|
+
return result
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// MARK: - GetColumnType
|
|
314
|
+
|
|
315
|
+
class func getColumnType(index: Int32, stmt: OpaquePointer?)
|
|
316
|
+
-> Int32 {
|
|
317
|
+
var type: Int32 = 0
|
|
318
|
+
// Column types - http://www.sqlite.org/datatype3.html (section 2.2 table column 1)
|
|
319
|
+
let blobTypes = ["BINARY", "BLOB", "VARBINARY"]
|
|
320
|
+
var textTypes: [String] = ["CHAR", "CHARACTER", "CLOB",
|
|
321
|
+
"NATIONAL VARYING CHARACTER",
|
|
322
|
+
"NATIVE CHARACTER"]
|
|
323
|
+
let textTypes1: [String] = ["NCHAR", "NVARCHAR", "TEXT",
|
|
324
|
+
"VARCHAR", "VARIANT",
|
|
325
|
+
"VARYING CHARACTER"]
|
|
326
|
+
textTypes.append(contentsOf: textTypes1)
|
|
327
|
+
let dateTypes = ["DATE", "DATETIME", "TIME", "TIMESTAMP"]
|
|
328
|
+
var intTypes = ["BIGINT", "BIT", "BOOL", "BOOLEAN", "INT",
|
|
329
|
+
"INT2", "INT8", "INTEGER", "MEDIUMINT"]
|
|
330
|
+
let intTypes1: [String] = ["SMALLINT", "TINYINT"]
|
|
331
|
+
intTypes.append(contentsOf: intTypes1)
|
|
332
|
+
let nullTypes = ["NULL"]
|
|
333
|
+
let realTypes = ["DECIMAL", "DOUBLE", "DOUBLE PRECISION",
|
|
334
|
+
"FLOAT", "NUMERIC", "REAL"]
|
|
335
|
+
// Determine type of column -
|
|
336
|
+
// http://www.sqlite.org/c3ref/c_blob.html
|
|
337
|
+
let declaredType = sqlite3_column_decltype(stmt, index)
|
|
338
|
+
if let dclType = declaredType {
|
|
339
|
+
var declaredType = String(cString: dclType).uppercased()
|
|
340
|
+
if let index = declaredType.firstIndex(of: "(" ) {
|
|
341
|
+
declaredType = String(declaredType[..<index])
|
|
342
|
+
}
|
|
343
|
+
if intTypes.contains(declaredType) {
|
|
344
|
+
return SQLITE_INTEGER
|
|
345
|
+
}
|
|
346
|
+
if realTypes.contains(declaredType) {
|
|
347
|
+
return SQLITE_FLOAT
|
|
348
|
+
}
|
|
349
|
+
if textTypes.contains(declaredType) {
|
|
350
|
+
return SQLITE_TEXT
|
|
351
|
+
}
|
|
352
|
+
if blobTypes.contains(declaredType) {
|
|
353
|
+
return SQLITE_BLOB
|
|
354
|
+
}
|
|
355
|
+
if dateTypes.contains(declaredType) {
|
|
356
|
+
return SQLITE_FLOAT
|
|
357
|
+
}
|
|
358
|
+
if nullTypes.contains(declaredType) {
|
|
359
|
+
return SQLITE_NULL
|
|
360
|
+
}
|
|
361
|
+
return SQLITE_NULL
|
|
362
|
+
} else {
|
|
363
|
+
type = sqlite3_column_type(stmt, index)
|
|
364
|
+
return type
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// MARK: - GetColumnValue
|
|
369
|
+
|
|
370
|
+
class func getColumnValue(index: Int32, type: Int32,
|
|
371
|
+
stmt: OpaquePointer?) -> Any? {
|
|
372
|
+
if sqlite3_column_type(stmt, index) == SQLITE_NULL {
|
|
373
|
+
return "NULL"
|
|
374
|
+
} else {
|
|
375
|
+
switch type {
|
|
376
|
+
case SQLITE_INTEGER:
|
|
377
|
+
let val = sqlite3_column_int64(stmt, index)
|
|
378
|
+
return Int64(val)
|
|
379
|
+
case SQLITE_FLOAT:
|
|
380
|
+
let val = sqlite3_column_double(stmt, index)
|
|
381
|
+
return Double(val)
|
|
382
|
+
case SQLITE_BLOB:
|
|
383
|
+
let data = sqlite3_column_blob(stmt, index)
|
|
384
|
+
let size = sqlite3_column_bytes(stmt, index)
|
|
385
|
+
let val = NSData(bytes: data, length: Int(size))
|
|
386
|
+
// Convert to string
|
|
387
|
+
let strVal: String = String(decoding: val,
|
|
388
|
+
as: UTF8.self)
|
|
389
|
+
return strVal
|
|
390
|
+
case SQLITE_TEXT:
|
|
391
|
+
let buffer = sqlite3_column_text(stmt, index)
|
|
392
|
+
var val: String
|
|
393
|
+
if let mBuffer = buffer {
|
|
394
|
+
val = String(cString: mBuffer)
|
|
395
|
+
} else {
|
|
396
|
+
val = "NULL"
|
|
397
|
+
}
|
|
398
|
+
return val
|
|
399
|
+
case SQLITE_NULL:
|
|
400
|
+
return "NULL"
|
|
401
|
+
default:
|
|
402
|
+
return "NULL"
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// MARK: - Execute
|
|
408
|
+
|
|
409
|
+
class func execute(mDB: StorageDatabaseHelper, sql: String) throws {
|
|
410
|
+
var msg: String = "Error execute: "
|
|
411
|
+
if !mDB.isOpen {
|
|
412
|
+
msg.append("Database not opened")
|
|
413
|
+
throw UtilsSQLCipherError.execute(message: msg)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
let returnCode: Int32 = sqlite3_exec(mDB.mDB, sql, nil,
|
|
417
|
+
nil, nil)
|
|
418
|
+
if returnCode != SQLITE_OK {
|
|
419
|
+
let errmsg: String = String(
|
|
420
|
+
cString: sqlite3_errmsg(mDB.mDB))
|
|
421
|
+
var msg: String = "Error: execute failed rc: \(returnCode)"
|
|
422
|
+
msg.append(" message: \(errmsg)")
|
|
423
|
+
throw UtilsSQLCipherError.execute(message: msg)
|
|
424
|
+
}
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// MARK: - DeleteDB
|
|
429
|
+
|
|
430
|
+
class func deleteDB(databaseName: String) throws {
|
|
431
|
+
if let dir = FileManager.default.urls(
|
|
432
|
+
for: .documentDirectory,
|
|
433
|
+
in: .userDomainMask).first {
|
|
434
|
+
let fileURL = dir.appendingPathComponent(databaseName)
|
|
435
|
+
let isFileExists = FileManager.default.fileExists(
|
|
436
|
+
atPath: fileURL.path)
|
|
437
|
+
if isFileExists {
|
|
438
|
+
do {
|
|
439
|
+
try FileManager.default.removeItem(at: fileURL)
|
|
440
|
+
print("Database \(databaseName) deleted")
|
|
441
|
+
} catch let error {
|
|
442
|
+
var msg: String = "Error: deleteDB: "
|
|
443
|
+
msg.append(" \(error.localizedDescription)")
|
|
444
|
+
throw UtilsSQLCipherError.deleteDB(
|
|
445
|
+
message: msg)
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// MARK: - CreateTable
|
|
453
|
+
|
|
454
|
+
class func createTable (mDB: StorageDatabaseHelper, tableName: String,
|
|
455
|
+
ifNotExists: Bool) throws {
|
|
456
|
+
let exist: String = ifNotExists ? "IF NOT EXISTS" : ""
|
|
457
|
+
let crTable: String = "CREATE TABLE \(exist) \(tableName) (" +
|
|
458
|
+
"\(COLID) INTEGER PRIMARY KEY AUTOINCREMENT," +
|
|
459
|
+
"\(COLNAME) TEXT NOT NULL UNIQUE,\(COLVALUE) TEXT);"
|
|
460
|
+
do {
|
|
461
|
+
try UtilsSQLCipher.execute(mDB: mDB, sql: crTable)
|
|
462
|
+
return
|
|
463
|
+
} catch UtilsSQLCipherError.execute(let message) {
|
|
464
|
+
throw UtilsSQLCipherError.creationTable(message: message)
|
|
465
|
+
} catch let error {
|
|
466
|
+
let msg = error.localizedDescription
|
|
467
|
+
throw UtilsSQLCipherError.creationTable(message: msg)
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// MARK: - CreateIndex
|
|
472
|
+
|
|
473
|
+
class func createIndex(mDB: StorageDatabaseHelper, tableName: String,
|
|
474
|
+
ifNotExists: Bool) throws {
|
|
475
|
+
let exist: String = ifNotExists ? "IF NOT EXISTS" : ""
|
|
476
|
+
let idx: String = "index_\(tableName)_on_\(COLNAME)"
|
|
477
|
+
let crIndex: String = "CREATE INDEX \(exist) '\(idx)' " +
|
|
478
|
+
"ON '\(tableName)' ('\(IDXCOLNAME)');"
|
|
479
|
+
|
|
480
|
+
do {
|
|
481
|
+
try UtilsSQLCipher.execute(mDB: mDB, sql: crIndex)
|
|
482
|
+
return
|
|
483
|
+
} catch UtilsSQLCipherError.execute(let message) {
|
|
484
|
+
throw UtilsSQLCipherError.creationIndex(message: message)
|
|
485
|
+
} catch let error {
|
|
486
|
+
let msg = error.localizedDescription
|
|
487
|
+
throw UtilsSQLCipherError.creationIndex(message: msg)
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// MARK: - InsertData
|
|
492
|
+
|
|
493
|
+
class func insertData(mDB: StorageDatabaseHelper, tableName: String,
|
|
494
|
+
data: Data) throws {
|
|
495
|
+
|
|
496
|
+
let insertStatementString = "INSERT INTO " +
|
|
497
|
+
"\(tableName) (\(COLNAME), \(COLVALUE)) " + "VALUES (?, ?);"
|
|
498
|
+
guard let name: String = data.name else {
|
|
499
|
+
let msg = "no data.name given"
|
|
500
|
+
throw UtilsSQLCipherError.insertData(message: msg)
|
|
501
|
+
}
|
|
502
|
+
guard let value: String = data.value else {
|
|
503
|
+
let msg = "no data.value given"
|
|
504
|
+
throw UtilsSQLCipherError.insertData(message: msg)
|
|
505
|
+
}
|
|
506
|
+
let values: [Any] = [name as Any, value as Any]
|
|
507
|
+
do {
|
|
508
|
+
let lastId: Int64 = try UtilsSQLCipher
|
|
509
|
+
.prepareSQL(mDB: mDB,
|
|
510
|
+
sql: insertStatementString,
|
|
511
|
+
values: values)
|
|
512
|
+
if lastId <= 0 {
|
|
513
|
+
let msg: String = "No data inserted"
|
|
514
|
+
throw UtilsSQLCipherError.insertData(message: msg)
|
|
515
|
+
}
|
|
516
|
+
return
|
|
517
|
+
} catch UtilsSQLCipherError.prepareSQL(let message) {
|
|
518
|
+
throw UtilsSQLCipherError.insertData(message: message)
|
|
519
|
+
} catch let error {
|
|
520
|
+
let msg = error.localizedDescription
|
|
521
|
+
throw UtilsSQLCipherError.insertData(message: msg)
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// MARK: - UpdateData
|
|
526
|
+
|
|
527
|
+
class func updateData(mDB: StorageDatabaseHelper, tableName: String,
|
|
528
|
+
data: Data) throws {
|
|
529
|
+
let updateStatementString = "UPDATE \(tableName) SET " +
|
|
530
|
+
"\(COLVALUE) = ? WHERE \(COLNAME) = ?;"
|
|
531
|
+
guard let name: String = data.name else {
|
|
532
|
+
let msg = "no data.name given"
|
|
533
|
+
throw UtilsSQLCipherError.updateData(message: msg)
|
|
534
|
+
}
|
|
535
|
+
guard let value: String = data.value else {
|
|
536
|
+
let msg = "no data.value given"
|
|
537
|
+
throw UtilsSQLCipherError.updateData(message: msg)
|
|
538
|
+
}
|
|
539
|
+
let values: [Any] = [value as Any, name as Any]
|
|
540
|
+
do {
|
|
541
|
+
let lastId: Int64 = try UtilsSQLCipher
|
|
542
|
+
.prepareSQL(mDB: mDB,
|
|
543
|
+
sql: updateStatementString,
|
|
544
|
+
values: values)
|
|
545
|
+
if lastId < 0 {
|
|
546
|
+
let msg: String = "No data updated"
|
|
547
|
+
throw UtilsSQLCipherError.updateData(message: msg)
|
|
548
|
+
}
|
|
549
|
+
return
|
|
550
|
+
} catch UtilsSQLCipherError.prepareSQL(let message) {
|
|
551
|
+
throw UtilsSQLCipherError.updateData(message: message)
|
|
552
|
+
} catch let error {
|
|
553
|
+
let msg = error.localizedDescription
|
|
554
|
+
throw UtilsSQLCipherError.updateData(message: msg)
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// MARK: - DropTable
|
|
559
|
+
|
|
560
|
+
class func dropTable (mDB: StorageDatabaseHelper, tableName: String) throws {
|
|
561
|
+
let dropStatement: String = "DROP TABLE IF EXISTS \(tableName)"
|
|
562
|
+
do {
|
|
563
|
+
try UtilsSQLCipher.execute(mDB: mDB, sql: dropStatement)
|
|
564
|
+
return
|
|
565
|
+
} catch UtilsSQLCipherError.execute(let message) {
|
|
566
|
+
throw UtilsSQLCipherError.dropTable(message: message)
|
|
567
|
+
} catch let error {
|
|
568
|
+
let msg = error.localizedDescription
|
|
569
|
+
throw UtilsSQLCipherError.dropTable(message: msg)
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// MARK: - GetTables
|
|
574
|
+
|
|
575
|
+
class func getTables(mDB: StorageDatabaseHelper) throws -> [String] {
|
|
576
|
+
var retArray: [String] = [String]()
|
|
577
|
+
|
|
578
|
+
let getStmt: String = "SELECT name FROM sqlite_master " +
|
|
579
|
+
"WHERE TYPE='table' ORDER BY name;"
|
|
580
|
+
do {
|
|
581
|
+
let results = try querySQL(mDB: mDB, sql: getStmt, values: [])
|
|
582
|
+
if results.count > 0 {
|
|
583
|
+
for res in results {
|
|
584
|
+
guard let name = res["name"] as? String else {
|
|
585
|
+
let msg = "no returned key"
|
|
586
|
+
throw UtilsSQLCipherError.getTables(message: msg)
|
|
587
|
+
}
|
|
588
|
+
if name != "sqlite_sequence" {
|
|
589
|
+
retArray.append(name)
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return retArray
|
|
594
|
+
} catch UtilsSQLCipherError.querySQL(let message) {
|
|
595
|
+
throw UtilsSQLCipherError.getTables(message: message)
|
|
596
|
+
} catch let error {
|
|
597
|
+
let msg = error.localizedDescription
|
|
598
|
+
throw UtilsSQLCipherError.getTables(message: msg)
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
}
|
|
604
|
+
// swiftlint:enable type_body_length
|
|
605
|
+
// swiftlint:enable file_length
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@capgo/capacitor-data-storage-sqlite",
|
|
3
|
+
"version": "6.0.0",
|
|
4
|
+
"description": "SQLite Storage of key/value strings pair",
|
|
5
|
+
"main": "dist/plugin.cjs.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"unpkg": "dist/plugin.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"android/src/main/",
|
|
11
|
+
"android/build.gradle",
|
|
12
|
+
"dist/",
|
|
13
|
+
"ios/Plugin/",
|
|
14
|
+
"electron/",
|
|
15
|
+
"CapacitorDataStorageSqlite.podspec"
|
|
16
|
+
],
|
|
17
|
+
"author": "Martin Donadieu",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/Cap-go/capacitor-data-storage-sqlite.git.git"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/Cap-go/capacitor-data-storage-sqlite.git/issues"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"capacitor",
|
|
28
|
+
"plugin",
|
|
29
|
+
"native",
|
|
30
|
+
"sqlite",
|
|
31
|
+
"storage",
|
|
32
|
+
"data"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
36
|
+
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
|
|
37
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
38
|
+
"verify:web": "npm run build",
|
|
39
|
+
"verify:electron": "npm run build-electron",
|
|
40
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
41
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --autocorrect --format",
|
|
42
|
+
"eslint": "eslint .",
|
|
43
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
|
44
|
+
"swiftlint": "node-swiftlint",
|
|
45
|
+
"docgen": "docgen --api CapacitorDataStorageSqlitePlugin --output-readme docs/API.md --output-json dist/docs.json",
|
|
46
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs && npm run build-electron",
|
|
47
|
+
"build-electron": "tsc --project electron/tsconfig.json && rollup -c electron/rollup.config.mjs && rimraf ./electron/build",
|
|
48
|
+
"clean": "rimraf ./dist",
|
|
49
|
+
"watch": "tsc --watch",
|
|
50
|
+
"test": "echo \"No test specified\"",
|
|
51
|
+
"prepublishOnly": "npm run build"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@capacitor/android": "^6.0.0",
|
|
55
|
+
"@capacitor/core": "^6.0.0",
|
|
56
|
+
"@capacitor/docgen": "^0.2.2",
|
|
57
|
+
"@capacitor/ios": "^6.0.0",
|
|
58
|
+
"@ionic/eslint-config": "^0.4.0",
|
|
59
|
+
"@ionic/prettier-config": "^2.0.0",
|
|
60
|
+
"@ionic/swiftlint-config": "^1.1.2",
|
|
61
|
+
"@rollup/plugin-commonjs": "^26.0.1",
|
|
62
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
63
|
+
"@types/node": "^20.14.15",
|
|
64
|
+
"@typescript-eslint/eslint-plugin": "^8.1.0",
|
|
65
|
+
"@typescript-eslint/parser": "^8.1.0",
|
|
66
|
+
"electron": "^22.2.0",
|
|
67
|
+
"eslint": "^8.57.0",
|
|
68
|
+
"eslint-plugin-import": "^2.29.1",
|
|
69
|
+
"prettier": "~3.3.3",
|
|
70
|
+
"prettier-plugin-java": "~2.6.4",
|
|
71
|
+
"rimraf": "^3.0.2",
|
|
72
|
+
"rollup": "^4.20.0",
|
|
73
|
+
"swiftlint": "^1.0.2",
|
|
74
|
+
"typescript": "~5.5.4"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"@capacitor/core": "^6.0.0",
|
|
78
|
+
"localforage": "^1.10.0"
|
|
79
|
+
},
|
|
80
|
+
"swiftlint": "@ionic/swiftlint-config",
|
|
81
|
+
"capacitor": {
|
|
82
|
+
"ios": {
|
|
83
|
+
"src": "ios"
|
|
84
|
+
},
|
|
85
|
+
"android": {
|
|
86
|
+
"src": "android"
|
|
87
|
+
},
|
|
88
|
+
"electron": {
|
|
89
|
+
"src": "electron"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"dependencies": {
|
|
93
|
+
"localforage": "^1.10.0"
|
|
94
|
+
},
|
|
95
|
+
"packageManager": "pnpm@9.7.0+sha512.dc09430156b427f5ecfc79888899e1c39d2d690f004be70e05230b72cb173d96839587545d09429b55ac3c429c801b4dc3c0e002f653830a420fa2dd4e3cf9cf"
|
|
96
|
+
}
|