Last active
October 26, 2021 18:33
-
-
Save tadija/21d56c68bf06a5cea48e6c597e399bf6 to your computer and use it in GitHub Desktop.
AESQLite
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* https://gist.github.com/tadija/21d56c68bf06a5cea48e6c597e399bf6 | |
* Revision 3 | |
* Copyright © 2018-2021 Marko Tadić | |
* Licensed under the MIT license | |
*/ | |
import Foundation | |
import SQLite3 | |
public final class AESQLite { | |
// MARK: Properties | |
private var db: OpaquePointer? | |
private var statement: OpaquePointer? | |
// MARK: Init | |
public init(path: String) { | |
openDatabase(atPath: path) | |
} | |
deinit { | |
closeDatabase() | |
} | |
// MARK: API | |
public func selectQuery(sql: String, rowHandler: (OpaquePointer?) -> Void) { | |
prepareStatement(sql: sql) | |
while sqlite3_step(statement) == SQLITE_ROW { | |
rowHandler(statement) | |
} | |
finalizeStatement() | |
} | |
// MARK: Helpers | |
private func openDatabase(atPath path: String) { | |
guard sqlite3_open(path, &db) == SQLITE_OK else { | |
print("Failed to open connection to database at: \(path)") | |
return | |
} | |
print("Opened connection to database at: \(path)") | |
} | |
private func closeDatabase() { | |
guard sqlite3_close(db) == SQLITE_OK else { | |
print("Failed to close connection to database") | |
return | |
} | |
db = nil | |
print("Closed connection to database.") | |
} | |
private func prepareStatement(sql: String) { | |
guard sqlite3_prepare_v2(db, sql, -1, &statement, nil) == SQLITE_OK else { | |
let errorMessage = String(cString: sqlite3_errmsg(db)) | |
print("Failed to prepare statement: \(errorMessage)") | |
return | |
} | |
} | |
private func finalizeStatement() { | |
guard sqlite3_finalize(statement) == SQLITE_OK else { | |
let errorMessage = String(cString: sqlite3_errmsg(db)) | |
print("Failed to finalize statement: \(errorMessage)") | |
return | |
} | |
statement = nil | |
} | |
} | |
public extension OpaquePointer { | |
func bool(at columnIndex: Int32) -> Bool? { | |
guard hasValue(at: columnIndex) else { | |
return nil | |
} | |
return Bool(truncating: Int32(sqlite3_column_int(self, columnIndex)) as NSNumber) | |
} | |
func int16(at columnIndex: Int32) -> Int16? { | |
guard hasValue(at: columnIndex) else { | |
return nil | |
} | |
return Int16(sqlite3_column_int(self, columnIndex)) | |
} | |
func int32(at columnIndex: Int32) -> Int32? { | |
guard hasValue(at: columnIndex) else { | |
return nil | |
} | |
return Int32(sqlite3_column_int(self, columnIndex)) | |
} | |
func int64(at columnIndex: Int32) -> Int64? { | |
guard hasValue(at: columnIndex) else { | |
return nil | |
} | |
return Int64(sqlite3_column_int64(self, columnIndex)) | |
} | |
func string(at columnIndex: Int32) -> String? { | |
guard hasValue(at: columnIndex) else { | |
return nil | |
} | |
guard let cString = sqlite3_column_text(self, columnIndex) else { | |
return nil | |
} | |
return String(cString: cString) | |
} | |
func data(at columnIndex: Int32) -> Data? { | |
guard hasValue(at: columnIndex) else { | |
return nil | |
} | |
let data = sqlite3_column_blob(self, columnIndex) | |
let size = sqlite3_column_bytes(self, columnIndex) | |
let value = NSData(bytes: data, length: Int(size)) as Data | |
return value | |
} | |
private func hasValue(at columnIndex: Int32) -> Bool { | |
sqlite3_column_type(self, columnIndex) != SQLITE_NULL | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment