react-native-bg-geolocation 0.2.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.
Files changed (142) hide show
  1. package/BgGeolocation.podspec +39 -0
  2. package/LICENSE +20 -0
  3. package/README.md +366 -0
  4. package/android/build.gradle +69 -0
  5. package/android/src/main/AndroidManifest.xml +53 -0
  6. package/android/src/main/java/com/bggeolocation/BgGeolocationActivityRecognitionReceiver.kt +116 -0
  7. package/android/src/main/java/com/bggeolocation/BgGeolocationBootReceiver.kt +44 -0
  8. package/android/src/main/java/com/bggeolocation/BgGeolocationForegroundService.kt +373 -0
  9. package/android/src/main/java/com/bggeolocation/BgGeolocationGeofenceReceiver.kt +55 -0
  10. package/android/src/main/java/com/bggeolocation/BgGeolocationHeadlessTask.kt +138 -0
  11. package/android/src/main/java/com/bggeolocation/BgGeolocationModule.kt +1030 -0
  12. package/android/src/main/java/com/bggeolocation/BgGeolocationMotionStateMachine.kt +159 -0
  13. package/android/src/main/java/com/bggeolocation/BgGeolocationPackage.kt +31 -0
  14. package/android/src/main/res/drawable/bg_geo_notification.xml +9 -0
  15. package/ios/BgGeolocation.h +14 -0
  16. package/ios/BgGeolocation.mm +709 -0
  17. package/ios/engine/AtomicBoolean.swift +48 -0
  18. package/ios/engine/BGActivityChangeEvent.swift +20 -0
  19. package/ios/engine/BGActivityConfig.swift +71 -0
  20. package/ios/engine/BGAppConfig.swift +92 -0
  21. package/ios/engine/BGAppState.swift +147 -0
  22. package/ios/engine/BGAuthorization.swift +85 -0
  23. package/ios/engine/BGAuthorizationAlertPresenter.swift +39 -0
  24. package/ios/engine/BGAuthorizationConfig.swift +50 -0
  25. package/ios/engine/BGAuthorizationEvent.swift +40 -0
  26. package/ios/engine/BGBackgroundTaskManager.swift +143 -0
  27. package/ios/engine/BGCLRouter.swift +101 -0
  28. package/ios/engine/BGCallback.swift +19 -0
  29. package/ios/engine/BGConfig.swift +440 -0
  30. package/ios/engine/BGConfigModuleBase.swift +180 -0
  31. package/ios/engine/BGConfigOLD.swift +582 -0
  32. package/ios/engine/BGConnectivityChangeEvent.swift +15 -0
  33. package/ios/engine/BGCrashDetector.swift +122 -0
  34. package/ios/engine/BGCurrentPositionRequest.swift +87 -0
  35. package/ios/engine/BGDataStore.swift +75 -0
  36. package/ios/engine/BGDatabase.swift +677 -0
  37. package/ios/engine/BGDatabasePool.swift +220 -0
  38. package/ios/engine/BGDatabaseQueue.swift +215 -0
  39. package/ios/engine/BGDateUtils.swift +26 -0
  40. package/ios/engine/BGDeviceInfo.swift +54 -0
  41. package/ios/engine/BGDeviceManager.swift +65 -0
  42. package/ios/engine/BGEnabledChangeEvent.swift +11 -0
  43. package/ios/engine/BGEnv.swift +17 -0
  44. package/ios/engine/BGEventBus.swift +83 -0
  45. package/ios/engine/BGEventManager.swift +169 -0
  46. package/ios/engine/BGEventNames.swift +51 -0
  47. package/ios/engine/BGGeofence.swift +233 -0
  48. package/ios/engine/BGGeofenceDAO.swift +152 -0
  49. package/ios/engine/BGGeofenceEvent.swift +42 -0
  50. package/ios/engine/BGGeofenceLocationRequest.swift +94 -0
  51. package/ios/engine/BGGeofenceManager.swift +315 -0
  52. package/ios/engine/BGGeofenceTransition.swift +97 -0
  53. package/ios/engine/BGGeofencesChangeEvent.swift +26 -0
  54. package/ios/engine/BGGeolocationConfig.swift +136 -0
  55. package/ios/engine/BGHeartbeatEvent.swift +31 -0
  56. package/ios/engine/BGHeartbeatService.swift +51 -0
  57. package/ios/engine/BGHttpConfig.swift +105 -0
  58. package/ios/engine/BGHttpErrorCodes.swift +63 -0
  59. package/ios/engine/BGHttpEvent.swift +34 -0
  60. package/ios/engine/BGHttpRequest.swift +126 -0
  61. package/ios/engine/BGHttpResponse.swift +93 -0
  62. package/ios/engine/BGHttpService.swift +428 -0
  63. package/ios/engine/BGKalmanFilter.swift +105 -0
  64. package/ios/engine/BGLMActionNames.swift +55 -0
  65. package/ios/engine/BGLicenseManager.swift +26 -0
  66. package/ios/engine/BGLiveActivityManager.swift +327 -0
  67. package/ios/engine/BGLocation.swift +311 -0
  68. package/ios/engine/BGLocationAuthorization.swift +427 -0
  69. package/ios/engine/BGLocationDAO.swift +252 -0
  70. package/ios/engine/BGLocationErrors.swift +28 -0
  71. package/ios/engine/BGLocationEvent.swift +43 -0
  72. package/ios/engine/BGLocationFilter.swift +82 -0
  73. package/ios/engine/BGLocationFilterConfig.swift +57 -0
  74. package/ios/engine/BGLocationHelper.swift +54 -0
  75. package/ios/engine/BGLocationManager.swift +662 -0
  76. package/ios/engine/BGLocationMetricsEngine.swift +116 -0
  77. package/ios/engine/BGLocationRequestService.swift +459 -0
  78. package/ios/engine/BGLocationSatisfier.swift +14 -0
  79. package/ios/engine/BGLocationStreamEvent.swift +27 -0
  80. package/ios/engine/BGLog.swift +337 -0
  81. package/ios/engine/BGLogLevel.swift +26 -0
  82. package/ios/engine/BGLoggerConfig.swift +60 -0
  83. package/ios/engine/BGMotionActivity.swift +31 -0
  84. package/ios/engine/BGMotionActivityClassifier.swift +108 -0
  85. package/ios/engine/BGMotionActivityManagerAdapter.swift +40 -0
  86. package/ios/engine/BGMotionActivitySource.swift +46 -0
  87. package/ios/engine/BGMotionDetector.swift +377 -0
  88. package/ios/engine/BGMotionPermissionManager.swift +50 -0
  89. package/ios/engine/BGNativeLogger.swift +48 -0
  90. package/ios/engine/BGNotificaitons.swift +37 -0
  91. package/ios/engine/BGOdometer.swift +66 -0
  92. package/ios/engine/BGPersistenceConfig.swift +29 -0
  93. package/ios/engine/BGPolygonStreamRequest.swift +48 -0
  94. package/ios/engine/BGPowerSaveChangeEvent.swift +12 -0
  95. package/ios/engine/BGPropertySpec.swift +29 -0
  96. package/ios/engine/BGProviderChangeEvent.swift +31 -0
  97. package/ios/engine/BGQueue.swift +50 -0
  98. package/ios/engine/BGRPC.swift +194 -0
  99. package/ios/engine/BGReachability.swift +58 -0
  100. package/ios/engine/BGResultSet.swift +157 -0
  101. package/ios/engine/BGSchedule.swift +228 -0
  102. package/ios/engine/BGScheduleEvent.swift +13 -0
  103. package/ios/engine/BGScheduler.swift +116 -0
  104. package/ios/engine/BGSingleLocationRequest.swift +49 -0
  105. package/ios/engine/BGStreamLocationRequest.swift +42 -0
  106. package/ios/engine/BGTemplate.swift +54 -0
  107. package/ios/engine/BGTimerService.swift +46 -0
  108. package/ios/engine/BGTrackingAudioManager.swift +286 -0
  109. package/ios/engine/BGTrackingService.swift +879 -0
  110. package/ios/engine/BGWatchPositionRequest.swift +63 -0
  111. package/ios/engine/DatabaseQueue.swift +47 -0
  112. package/ios/engine/LogQuery.swift +10 -0
  113. package/ios/engine/SQLQuery.swift +65 -0
  114. package/ios/engine/TransistorAuthorizationToken.swift +182 -0
  115. package/ios/liveactivity/BGLiveTrackingAttributes.swift +52 -0
  116. package/ios/locationpush/BGLocationPushDeliverer.swift +260 -0
  117. package/ios/locationpush/BGLocationPushService.swift +161 -0
  118. package/ios/locationpush/BGLocationPushShared.swift +98 -0
  119. package/ios/locationpush/BGLocationPushSocketClient.swift +198 -0
  120. package/lib/module/NativeBgGeolocation.js +5 -0
  121. package/lib/module/NativeBgGeolocation.js.map +1 -0
  122. package/lib/module/events.js +20 -0
  123. package/lib/module/events.js.map +1 -0
  124. package/lib/module/index.js +706 -0
  125. package/lib/module/index.js.map +1 -0
  126. package/lib/module/package.json +1 -0
  127. package/lib/module/types.js +2 -0
  128. package/lib/module/types.js.map +1 -0
  129. package/lib/typescript/package.json +1 -0
  130. package/lib/typescript/src/NativeBgGeolocation.d.ts +57 -0
  131. package/lib/typescript/src/NativeBgGeolocation.d.ts.map +1 -0
  132. package/lib/typescript/src/events.d.ts +18 -0
  133. package/lib/typescript/src/events.d.ts.map +1 -0
  134. package/lib/typescript/src/index.d.ts +238 -0
  135. package/lib/typescript/src/index.d.ts.map +1 -0
  136. package/lib/typescript/src/types.d.ts +229 -0
  137. package/lib/typescript/src/types.d.ts.map +1 -0
  138. package/package.json +141 -0
  139. package/src/NativeBgGeolocation.ts +236 -0
  140. package/src/events.ts +17 -0
  141. package/src/index.tsx +935 -0
  142. package/src/types.ts +254 -0
@@ -0,0 +1,677 @@
1
+ import Foundation
2
+ import SQLite3
3
+
4
+ private let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
5
+
6
+ @objc public class BGStatement: NSObject {
7
+
8
+ @objc public var query: String = ""
9
+ @objc public var useCount: Int = 0
10
+ @objc public var inUse: Bool = false
11
+ var statement: OpaquePointer?
12
+
13
+ @objc public func reset() {
14
+ if let stmt = statement {
15
+ sqlite3_reset(stmt)
16
+ }
17
+ inUse = false
18
+ }
19
+
20
+ @objc public func close() {
21
+ if let stmt = statement {
22
+ sqlite3_finalize(stmt)
23
+ statement = nil
24
+ }
25
+ }
26
+
27
+ @objc public override var description: String {
28
+ return "<BGStatement query=\(query) useCount=\(useCount)>"
29
+ }
30
+
31
+ deinit {
32
+ close()
33
+ }
34
+ }
35
+
36
+ @objc public class BGDatabase: NSObject {
37
+
38
+ @objc public var databasePath: String?
39
+ @objc public var databaseURL: URL?
40
+ @objc public var logsErrors: Bool = true
41
+ @objc public var crashOnErrors: Bool = false
42
+ @objc public var traceExecution: Bool = false
43
+ @objc public var shouldCacheStatements: Bool = false
44
+ @objc public var isOpen: Bool = false
45
+ @objc public var inTransaction: Bool = false
46
+ @objc public var checkedOut: Bool = false
47
+ @objc public var maxBusyRetryTimeInterval: TimeInterval = 2.0
48
+ @objc public var busyRetryTimeout: Int = 0
49
+
50
+ var db: OpaquePointer?
51
+ var cachedStatements: [String: BGStatement] = [:]
52
+ var openResultSets: NSMutableSet = NSMutableSet()
53
+ var dateFormat: DateFormatter?
54
+
55
+ @objc public class func database(withPath path: String) -> BGDatabase {
56
+ return BGDatabase(path: path)
57
+ }
58
+
59
+ @objc public class func database(withURL url: URL) -> BGDatabase {
60
+ return BGDatabase(url: url)
61
+ }
62
+
63
+ @objc public class func isSQLiteThreadSafe() -> Bool {
64
+ return sqlite3_threadsafe() != 0
65
+ }
66
+
67
+ @objc public class func sqliteLibVersion() -> String {
68
+ return String(cString: sqlite3_libversion())
69
+ }
70
+
71
+ @objc public class func BGDBVersion() -> Int32 {
72
+ return sqlite3_libversion_number()
73
+ }
74
+
75
+ @objc public class func BGDBUserVersion() -> Int32 {
76
+ return 0
77
+ }
78
+
79
+ @objc public class func storeableDate(format: String) -> DateFormatter {
80
+ let fmt = DateFormatter()
81
+ fmt.dateFormat = format
82
+ fmt.locale = Locale(identifier: "en_US_POSIX")
83
+ fmt.timeZone = TimeZone(abbreviation: "UTC")
84
+ return fmt
85
+ }
86
+
87
+ @objc public init(path: String) {
88
+ self.databasePath = path
89
+ self.databaseURL = URL(fileURLWithPath: path)
90
+ super.init()
91
+ }
92
+
93
+ @objc public init(url: URL) {
94
+ self.databaseURL = url
95
+ self.databasePath = url.path
96
+ super.init()
97
+ }
98
+
99
+ @objc public override init() {
100
+ super.init()
101
+ }
102
+
103
+ @objc public func open() -> Bool {
104
+ if isOpen { return true }
105
+ let path = databasePath ?? ":memory:"
106
+ let flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
107
+ let rc = sqlite3_open_v2(path, &db, flags, nil)
108
+ if rc == SQLITE_OK {
109
+ isOpen = true
110
+ return true
111
+ }
112
+ return false
113
+ }
114
+
115
+ @objc public func open(withFlags flags: Int32) -> Bool {
116
+ if isOpen { return true }
117
+ let path = databasePath ?? ":memory:"
118
+ let rc = sqlite3_open_v2(path, &db, flags, nil)
119
+ if rc == SQLITE_OK {
120
+ isOpen = true
121
+ return true
122
+ }
123
+ return false
124
+ }
125
+
126
+ @objc public func open(withFlags flags: Int32, vfs: String?) -> Bool {
127
+ if isOpen { return true }
128
+ let path = databasePath ?? ":memory:"
129
+ let rc = sqlite3_open_v2(path, &db, flags, vfs)
130
+ if rc == SQLITE_OK {
131
+ isOpen = true
132
+ return true
133
+ }
134
+ return false
135
+ }
136
+
137
+ @objc public func close() -> Bool {
138
+ clearCachedStatements()
139
+ closeOpenResultSets()
140
+ if db != nil {
141
+ sqlite3_close(db)
142
+ db = nil
143
+ }
144
+ isOpen = false
145
+ return true
146
+ }
147
+
148
+ @objc public func goodConnection() -> Bool {
149
+ if !isOpen { return false }
150
+ let rs = executeQuery("SELECT name FROM sqlite_master WHERE type='table'")
151
+ rs?.close()
152
+ return rs != nil
153
+ }
154
+
155
+ @objc public func databaseExists() -> Bool {
156
+ guard let path = databasePath else { return false }
157
+ return FileManager.default.fileExists(atPath: path)
158
+ }
159
+
160
+ @objc public func sqliteHandle() -> OpaquePointer? {
161
+ return db
162
+ }
163
+
164
+ @objc public func sqlitePath() -> String {
165
+ return databasePath ?? ""
166
+ }
167
+
168
+ @objc public func lastInsertRowId() -> Int64 {
169
+ return sqlite3_last_insert_rowid(db)
170
+ }
171
+
172
+ @objc public func changes() -> Int32 {
173
+ return sqlite3_changes(db)
174
+ }
175
+
176
+ @objc public func hadError() -> Bool {
177
+ return lastErrorCode() != SQLITE_OK
178
+ }
179
+
180
+ @objc public func lastError() -> Error {
181
+ return NSError(domain: "BGDatabase", code: Int(lastErrorCode()), userInfo: [NSLocalizedDescriptionKey: lastErrorMessage()])
182
+ }
183
+
184
+ @objc public func lastErrorCode() -> Int32 {
185
+ return sqlite3_errcode(db)
186
+ }
187
+
188
+ @objc public func lastExtendedErrorCode() -> Int32 {
189
+ return sqlite3_extended_errcode(db)
190
+ }
191
+
192
+ @objc public func lastErrorMessage() -> String {
193
+ return String(cString: sqlite3_errmsg(db))
194
+ }
195
+
196
+ @objc public func error(withMessage message: String) -> NSError {
197
+ return NSError(domain: "BGDatabase", code: Int(lastErrorCode()), userInfo: [NSLocalizedDescriptionKey: message])
198
+ }
199
+
200
+ @objc public func interrupt() {
201
+ sqlite3_interrupt(db)
202
+ }
203
+
204
+ @objc public func warnInUse() {
205
+ if logsErrors {
206
+ print("[BGDatabase] Warning: database in use")
207
+ }
208
+ }
209
+
210
+ // MARK: - Statements
211
+
212
+ @objc public func cachedStatement(forQuery query: String) -> BGStatement? {
213
+ return cachedStatements[query]
214
+ }
215
+
216
+ @objc public func setCachedStatement(_ stmt: BGStatement, forQuery query: String) {
217
+ cachedStatements[query] = stmt
218
+ }
219
+
220
+ @objc public func clearCachedStatements() {
221
+ for (_, stmt) in cachedStatements {
222
+ stmt.close()
223
+ }
224
+ cachedStatements.removeAll()
225
+ }
226
+
227
+ @objc public func closeOpenResultSets() {
228
+ let sets = openResultSets.copy() as! NSSet
229
+ for obj in sets {
230
+ if let rs = obj as? BGResultSet {
231
+ rs.close()
232
+ }
233
+ }
234
+ }
235
+
236
+ @objc public func hasOpenResultSets() -> Bool {
237
+ return openResultSets.count > 0
238
+ }
239
+
240
+ @objc public func resultSetDidClose(_ rs: BGResultSet) {
241
+ openResultSets.remove(rs)
242
+ }
243
+
244
+ // MARK: - Execute
245
+
246
+ @objc public func executeUpdate(_ sql: String) -> Bool {
247
+ return executeUpdate(sql, withArgumentsInArray: [])
248
+ }
249
+
250
+ @objc public func executeUpdate(_ sql: String, withArgumentsInArray args: [Any]) -> Bool {
251
+ var stmt: OpaquePointer?
252
+ var rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nil)
253
+ if rc != SQLITE_OK {
254
+ if logsErrors { print("[BGDatabase] executeUpdate prepare error: \(lastErrorMessage())") }
255
+ return false
256
+ }
257
+ defer { sqlite3_finalize(stmt) }
258
+ for (i, arg) in args.enumerated() {
259
+ bind(object: arg, toColumn: Int32(i + 1), inStatement: stmt!)
260
+ }
261
+ rc = sqlite3_step(stmt)
262
+ if rc != SQLITE_DONE && rc != SQLITE_ROW {
263
+ if logsErrors { print("[BGDatabase] executeUpdate step error: \(lastErrorMessage())") }
264
+ return false
265
+ }
266
+ return true
267
+ }
268
+
269
+ @objc public func executeUpdate(_ sql: String, withParameterDictionary params: [String: Any]) -> Bool {
270
+ return executeUpdate(sql, withArgumentsInArray: Array(params.values))
271
+ }
272
+
273
+ public func executeUpdate(_ sql: String, values: [Any], error: UnsafeMutablePointer<NSError?>?) throws -> Bool {
274
+ return executeUpdate(sql, withArgumentsInArray: values)
275
+ }
276
+
277
+ public func executeUpdate(withFormat sql: String, _ args: CVarArg...) -> Bool {
278
+ return executeUpdate(String(format: sql, args))
279
+ }
280
+
281
+ public func executeUpdate(_ sql: String, error: UnsafeMutablePointer<NSError?>?, withArgumentsInArray args: [Any]?, orDictionary dict: [String: Any]?, orVAList valist: CVaListPointer) -> Bool {
282
+ if let a = args { return executeUpdate(sql, withArgumentsInArray: a) }
283
+ if let d = dict { return executeUpdate(sql, withParameterDictionary: d) }
284
+ return executeUpdate(sql)
285
+ }
286
+
287
+ @objc public func update(_ sql: String, withErrorAndBindings bindings: [Any]) -> Bool {
288
+ return executeUpdate(sql, withArgumentsInArray: bindings)
289
+ }
290
+
291
+ @objc public func executeUpdate(_ sql: String, withErrorAndBindings bindings: [Any]) -> Bool {
292
+ return executeUpdate(sql, withArgumentsInArray: bindings)
293
+ }
294
+
295
+ @objc public func executeStatements(_ sql: String) -> Bool {
296
+ var errMsg: UnsafeMutablePointer<Int8>?
297
+ let rc = sqlite3_exec(db, sql, nil, nil, &errMsg)
298
+ if rc != SQLITE_OK {
299
+ if logsErrors {
300
+ let msg = errMsg.map { String(cString: $0) } ?? "unknown error"
301
+ print("[BGDatabase] executeStatements error: \(msg)")
302
+ }
303
+ sqlite3_free(errMsg)
304
+ return false
305
+ }
306
+ return true
307
+ }
308
+
309
+ @objc public func executeStatements(_ sql: String, withResultBlock block: ((NSDictionary) -> Int32)?) -> Bool {
310
+ return executeStatements(sql)
311
+ }
312
+
313
+ @objc public func executeQuery(_ sql: String) -> BGResultSet? {
314
+ return executeQuery(sql, withArgumentsInArray: [])
315
+ }
316
+
317
+ @objc public func executeQuery(_ sql: String, withArgumentsInArray args: [Any]) -> BGResultSet? {
318
+ var stmt: OpaquePointer?
319
+ let rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nil)
320
+ if rc != SQLITE_OK {
321
+ if logsErrors { print("[BGDatabase] executeQuery prepare error: \(lastErrorMessage())") }
322
+ return nil
323
+ }
324
+ for (i, arg) in args.enumerated() {
325
+ bind(object: arg, toColumn: Int32(i + 1), inStatement: stmt!)
326
+ }
327
+ let rs = BGResultSet()
328
+ rs.statement = BGStatement()
329
+ rs.statement?.statement = stmt
330
+ rs.statement?.query = sql
331
+ rs.parentDB = self
332
+ openResultSets.add(rs)
333
+ return rs
334
+ }
335
+
336
+ public func executeQuery(_ sql: String, values: [Any], error: UnsafeMutablePointer<NSError?>?) throws -> BGResultSet? {
337
+ return executeQuery(sql, withArgumentsInArray: values)
338
+ }
339
+
340
+ @objc public func executeQuery(_ sql: String, withParameterDictionary params: [String: Any]) -> BGResultSet? {
341
+ return executeQuery(sql, withArgumentsInArray: Array(params.values))
342
+ }
343
+
344
+ public func executeQuery(_ sql: String, withVAList valist: CVaListPointer) -> BGResultSet? {
345
+ return executeQuery(sql)
346
+ }
347
+
348
+ public func executeQuery(withFormat sql: String, _ args: CVarArg...) -> BGResultSet? {
349
+ return executeQuery(String(format: sql, args))
350
+ }
351
+
352
+ public func executeQuery(_ sql: String, withArgumentsInArray args: [Any]?, orDictionary dict: [String: Any]?, orVAList valist: CVaListPointer) -> BGResultSet? {
353
+ if let a = args { return executeQuery(sql, withArgumentsInArray: a) }
354
+ if let d = dict { return executeQuery(sql, withParameterDictionary: d) }
355
+ return executeQuery(sql)
356
+ }
357
+
358
+ // MARK: - Transactions
359
+
360
+ @objc public func beginTransaction() -> Bool {
361
+ let ok = executeUpdate("BEGIN EXCLUSIVE TRANSACTION")
362
+ if ok { inTransaction = true }
363
+ return ok
364
+ }
365
+
366
+ @objc public func beginDeferredTransaction() -> Bool {
367
+ let ok = executeUpdate("BEGIN DEFERRED TRANSACTION")
368
+ if ok { inTransaction = true }
369
+ return ok
370
+ }
371
+
372
+ @objc public func beginImmediateTransaction() -> Bool {
373
+ let ok = executeUpdate("BEGIN IMMEDIATE TRANSACTION")
374
+ if ok { inTransaction = true }
375
+ return ok
376
+ }
377
+
378
+ @objc public func beginExclusiveTransaction() -> Bool {
379
+ let ok = executeUpdate("BEGIN EXCLUSIVE TRANSACTION")
380
+ if ok { inTransaction = true }
381
+ return ok
382
+ }
383
+
384
+ @objc public func commit() -> Bool {
385
+ let ok = executeUpdate("COMMIT TRANSACTION")
386
+ if ok { inTransaction = false }
387
+ return ok
388
+ }
389
+
390
+ @objc public func rollback() -> Bool {
391
+ let ok = executeUpdate("ROLLBACK TRANSACTION")
392
+ if ok { inTransaction = false }
393
+ return ok
394
+ }
395
+
396
+ @objc public func isInTransaction() -> Bool {
397
+ return inTransaction
398
+ }
399
+
400
+ @objc public func startSavePoint(withName name: String, error: UnsafeMutablePointer<NSError?>?) -> Bool {
401
+ return executeUpdate("SAVEPOINT \(name)")
402
+ }
403
+
404
+ @objc public func releaseSavePoint(withName name: String, error: UnsafeMutablePointer<NSError?>?) -> Bool {
405
+ return executeUpdate("RELEASE SAVEPOINT \(name)")
406
+ }
407
+
408
+ @objc public func rollbackToSavePoint(withName name: String, error: UnsafeMutablePointer<NSError?>?) -> Bool {
409
+ return executeUpdate("ROLLBACK TO SAVEPOINT \(name)")
410
+ }
411
+
412
+ @objc public func inSavePoint(_ block: (UnsafeMutablePointer<ObjCBool>) -> Void) -> Error? {
413
+ let savepointName = "FMDB_\(arc4random())"
414
+ var shouldRollback = ObjCBool(false)
415
+ _ = startSavePoint(withName: savepointName, error: nil)
416
+ block(&shouldRollback)
417
+ if shouldRollback.boolValue {
418
+ _ = rollbackToSavePoint(withName: savepointName, error: nil)
419
+ } else {
420
+ _ = releaseSavePoint(withName: savepointName, error: nil)
421
+ }
422
+ return nil
423
+ }
424
+
425
+ // MARK: - Checkpoint
426
+
427
+ @objc public func checkpoint(_ checkpointMode: Int32, error: UnsafeMutablePointer<NSError?>?) -> Bool {
428
+ return sqlite3_wal_checkpoint_v2(db, nil, checkpointMode, nil, nil) == SQLITE_OK
429
+ }
430
+
431
+ @objc public func checkpoint(_ checkpointMode: Int32, name: String?, error: UnsafeMutablePointer<NSError?>?) -> Bool {
432
+ return sqlite3_wal_checkpoint_v2(db, name, checkpointMode, nil, nil) == SQLITE_OK
433
+ }
434
+
435
+ @objc public func checkpoint(_ checkpointMode: Int32, name: String?, logFrameCount: UnsafeMutablePointer<Int32>?, checkpointCount: UnsafeMutablePointer<Int32>?, error: UnsafeMutablePointer<NSError?>?) -> Bool {
436
+ return sqlite3_wal_checkpoint_v2(db, name, checkpointMode, logFrameCount, checkpointCount) == SQLITE_OK
437
+ }
438
+
439
+ // MARK: - Key management
440
+
441
+ @objc public func setKey(_ key: String) -> Bool { return true }
442
+ @objc public func setKey(withData keyData: Data) -> Bool { return true }
443
+ @objc public func rekey(_ key: String) -> Bool { return true }
444
+ @objc public func rekey(withData keyData: Data) -> Bool { return true }
445
+
446
+ // MARK: - Date helpers
447
+
448
+ @objc public func hasDateFormatter() -> Bool {
449
+ return dateFormat != nil
450
+ }
451
+
452
+ @objc public func setDateFormat(_ fmt: DateFormatter) {
453
+ dateFormat = fmt
454
+ }
455
+
456
+ @objc public func date(fromString dateString: String) -> Date? {
457
+ return dateFormat?.date(from: dateString)
458
+ }
459
+
460
+ @objc public func string(fromDate date: Date) -> String {
461
+ return dateFormat?.string(from: date) ?? ""
462
+ }
463
+
464
+ // MARK: - Custom functions
465
+
466
+ @objc public func makeFunctionNamed(_ name: String, arguments nArgs: Int32, block: @escaping ([AnyObject]) -> AnyObject?) {
467
+ }
468
+
469
+ @objc public func makeFunctionNamed(_ name: String, maximumArguments nArgs: Int32, with block: @escaping ([AnyObject]) -> Void) {
470
+ }
471
+
472
+ @objc public func resultInt(_ value: Int32, context: OpaquePointer) {
473
+ sqlite3_result_int(context, value)
474
+ }
475
+
476
+ @objc public func resultLong(_ value: Int64, context: OpaquePointer) {
477
+ sqlite3_result_int64(context, value)
478
+ }
479
+
480
+ @objc public func resultDouble(_ value: Double, context: OpaquePointer) {
481
+ sqlite3_result_double(context, value)
482
+ }
483
+
484
+ @objc public func resultString(_ value: String, context: OpaquePointer) {
485
+ sqlite3_result_text(context, value, -1, SQLITE_TRANSIENT)
486
+ }
487
+
488
+ @objc public func resultData(_ value: Data, context: OpaquePointer) {
489
+ value.withUnsafeBytes { bytes in
490
+ sqlite3_result_blob(context, bytes.baseAddress, Int32(value.count), SQLITE_TRANSIENT)
491
+ }
492
+ }
493
+
494
+ @objc public func resultNull(inContext context: OpaquePointer) {
495
+ sqlite3_result_null(context)
496
+ }
497
+
498
+ @objc public func resultError(_ value: String, context: OpaquePointer) {
499
+ sqlite3_result_error(context, value, -1)
500
+ }
501
+
502
+ @objc public func resultErrorCode(_ value: Int32, context: OpaquePointer) {
503
+ sqlite3_result_error_code(context, value)
504
+ }
505
+
506
+ @objc public func resultErrorNoMemory(inContext context: OpaquePointer) {
507
+ sqlite3_result_error_nomem(context)
508
+ }
509
+
510
+ @objc public func resultErrorTooBig(inContext context: OpaquePointer) {
511
+ sqlite3_result_error_toobig(context)
512
+ }
513
+
514
+ @objc public func valueString(_ value: OpaquePointer) -> String? {
515
+ return sqlite3_value_text(value).map { String(cString: $0) }
516
+ }
517
+
518
+ @objc public func valueData(_ value: OpaquePointer) -> Data? {
519
+ guard let bytes = sqlite3_value_blob(value) else { return nil }
520
+ let len = sqlite3_value_bytes(value)
521
+ return Data(bytes: bytes, count: Int(len))
522
+ }
523
+
524
+ @objc public func valueInt(_ value: OpaquePointer) -> Int32 {
525
+ return sqlite3_value_int(value)
526
+ }
527
+
528
+ @objc public func valueLong(_ value: OpaquePointer) -> Int64 {
529
+ return sqlite3_value_int64(value)
530
+ }
531
+
532
+ @objc public func valueDouble(_ value: OpaquePointer) -> Double {
533
+ return sqlite3_value_double(value)
534
+ }
535
+
536
+ @objc public func valueType(_ value: OpaquePointer) -> Int32 {
537
+ return sqlite3_value_type(value)
538
+ }
539
+
540
+ // MARK: - Bind helpers
541
+
542
+ func bind(object obj: Any, toColumn idx: Int32, inStatement stmt: OpaquePointer) {
543
+ if let num = obj as? NSNumber {
544
+ let type = String(cString: num.objCType)
545
+ if type == "d" || type == "f" {
546
+ sqlite3_bind_double(stmt, idx, num.doubleValue)
547
+ } else if type == "q" || type == "Q" {
548
+ sqlite3_bind_int64(stmt, idx, num.int64Value)
549
+ } else {
550
+ sqlite3_bind_int(stmt, idx, num.int32Value)
551
+ }
552
+ } else if let str = obj as? String {
553
+ sqlite3_bind_text(stmt, idx, str, -1, SQLITE_TRANSIENT)
554
+ } else if let data = obj as? Data {
555
+ data.withUnsafeBytes { bytes in
556
+ sqlite3_bind_blob(stmt, idx, bytes.baseAddress, Int32(data.count), SQLITE_TRANSIENT)
557
+ }
558
+ } else if let date = obj as? Date {
559
+ let str = String(date.timeIntervalSince1970)
560
+ sqlite3_bind_text(stmt, idx, str, -1, SQLITE_TRANSIENT)
561
+ } else {
562
+ sqlite3_bind_null(stmt, idx)
563
+ }
564
+ }
565
+
566
+ public func extractSQL(_ sql: String, argumentsList args: CVaListPointer, into outSQL: UnsafeMutablePointer<NSString?>, arguments: NSMutableArray) -> Bool {
567
+ return true
568
+ }
569
+ }
570
+
571
+ // MARK: - BGDatabaseAdditions
572
+
573
+ extension BGDatabase {
574
+
575
+ public func string(forQuery query: String, _ args: Any...) -> String? {
576
+ guard let rs = executeQuery(query, withArgumentsInArray: args), rs.next() else { return nil }
577
+ defer { rs.close() }
578
+ return rs.string(forColumn: 0)
579
+ }
580
+
581
+ public func int(forQuery query: String, _ args: Any...) -> Int32 {
582
+ guard let rs = executeQuery(query, withArgumentsInArray: args), rs.next() else { return 0 }
583
+ defer { rs.close() }
584
+ return rs.int(forColumn: 0)
585
+ }
586
+
587
+ public func long(forQuery query: String, _ args: Any...) -> Int64 {
588
+ guard let rs = executeQuery(query, withArgumentsInArray: args), rs.next() else { return 0 }
589
+ defer { rs.close() }
590
+ return rs.long(forColumn: 0)
591
+ }
592
+
593
+ public func bool(forQuery query: String, _ args: Any...) -> Bool {
594
+ guard let rs = executeQuery(query, withArgumentsInArray: args), rs.next() else { return false }
595
+ defer { rs.close() }
596
+ return rs.bool(forColumn: 0)
597
+ }
598
+
599
+ public func double(forQuery query: String, _ args: Any...) -> Double {
600
+ guard let rs = executeQuery(query, withArgumentsInArray: args), rs.next() else { return 0 }
601
+ defer { rs.close() }
602
+ return rs.double(forColumn: 0)
603
+ }
604
+
605
+ public func data(forQuery query: String, _ args: Any...) -> Data? {
606
+ guard let rs = executeQuery(query, withArgumentsInArray: args), rs.next() else { return nil }
607
+ defer { rs.close() }
608
+ return rs.data(forColumn: 0)
609
+ }
610
+
611
+ public func date(forQuery query: String, _ args: Any...) -> Date? {
612
+ guard let rs = executeQuery(query, withArgumentsInArray: args), rs.next() else { return nil }
613
+ defer { rs.close() }
614
+ return rs.date(forColumn: 0)
615
+ }
616
+
617
+ @objc public func tableExists(_ tableName: String) -> Bool {
618
+ guard let rs = executeQuery("SELECT [sql] FROM (SELECT [sql] FROM sqlite_master UNION ALL SELECT [sql] FROM sqlite_temp_master) WHERE type != 'meta' AND name LIKE ?", withArgumentsInArray: [tableName]), rs.next() else { return false }
619
+ rs.close()
620
+ return true
621
+ }
622
+
623
+ @objc public func columnExists(_ column: String, inTableWithName table: String) -> Bool {
624
+ var exists = false
625
+ if let rs = executeQuery("PRAGMA table_info('\(table)')") {
626
+ while rs.next() {
627
+ if let name = rs.string(forColumn: "name"), name.lowercased() == column.lowercased() {
628
+ exists = true
629
+ break
630
+ }
631
+ }
632
+ rs.close()
633
+ }
634
+ return exists
635
+ }
636
+
637
+ @objc public func columnExists(_ column: String, columnName: String) -> Bool {
638
+ return columnExists(column, inTableWithName: columnName)
639
+ }
640
+
641
+ @objc public func getSchema() -> BGResultSet? {
642
+ return executeQuery("SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name")
643
+ }
644
+
645
+ @objc public func getTableSchema(_ tableName: String) -> BGResultSet? {
646
+ return executeQuery("PRAGMA table_info('\(tableName)')")
647
+ }
648
+
649
+ @objc public func userVersion() -> UInt32 {
650
+ guard let rs = executeQuery("PRAGMA user_version"), rs.next() else { return 0 }
651
+ let v = UInt32(bitPattern: rs.int(forColumn: 0))
652
+ rs.close()
653
+ return v
654
+ }
655
+
656
+ @objc public func setUserVersion(_ version: UInt32) {
657
+ _ = executeUpdate("PRAGMA user_version = \(version)")
658
+ }
659
+
660
+ @objc public func applicationID() -> UInt32 {
661
+ guard let rs = executeQuery("PRAGMA application_id"), rs.next() else { return 0 }
662
+ let v = UInt32(bitPattern: rs.int(forColumn: 0))
663
+ rs.close()
664
+ return v
665
+ }
666
+
667
+ @objc public func setApplicationID(_ appID: UInt32) {
668
+ _ = executeUpdate("PRAGMA application_id = \(appID)")
669
+ }
670
+
671
+ @objc public func validateSQL(_ sql: String, error: UnsafeMutablePointer<NSError?>?) -> Bool {
672
+ var stmt: OpaquePointer?
673
+ let rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nil)
674
+ if stmt != nil { sqlite3_finalize(stmt) }
675
+ return rc == SQLITE_OK
676
+ }
677
+ }