swift 簡易操做sqlite3 之 通用查詢

上篇文章咱們寫了關於SQLite的簡單操做和一些基本常識,對此陌生的童鞋能夠參考以前的文章(swift簡易操做sqlite3),今天咱們在此基礎上進一步加工處理,寫出通用查詢操做方法sql

關於查詢語句中的通用常識:swift

select * from t where age > :agebash

對於這條語句咱們咱們要有個共識::age 是進行SQLite內部prepare中的一個須要綁定的參數名(內部定義的格式)。咱們再來看幾個例子app

select * from \(t) where age>:age or name =:namefetch

其中 :age :name是後續SQLite進行prepare的bind參數名ui

有了上面的共識咱們接着進行咱們通用方法操做的過程,根據須要咱們一共提供兩種建議的操做spa

func exec(query q:String, values: SQLiteDataType ... ) -> [SQLiteRow]? 複製代碼


咱們先來看看怎麼使用:code


    exec(query: "select * from \(t) where age>:age or name =:name",                    values: Int32(1), "XX")複製代碼

    上述中咱們實例中看到:age :name 是提供給SQLite進行prepare的形參,Int32(1), "xx"是提供的數據條件(須要注意的是形參和數據條件的順序要一一對應)。cdn

    有了大概的認識以後咱們看看內部是如何實現的sqlite

    func exec(query q:String, values: SQLiteDataType ... ) -> [SQLiteRow]? {        var stmt: OpaquePointer?        var tail: UnsafePointer<Int8>?        let  h = handle        var  result =  sqlite3_prepare(h, q, -1, &stmt, &tail)                let parmmeterCount = sqlite3_bind_parameter_count(stmt)        var tmpValues = [SQLiteDataType]()                for value in values{            tmpValues.append(value)        }        for index in 0 ..< parmmeterCount {            let bindedParameterName: UnsafePointer<Int8>! =    sqlite3_bind_parameter_name(stmt, index + 1)            let bindResult =   bind(tmpValues[Int(index)], for: stmt!, at: index+1)            if bindResult == false{                break            }        }            let  targets =  fetchData(from: stmt)                sqlite3_finalize(stmt)        return targets            }複製代碼

    內部邏輯十分清晰:

    1 獲取到SQL中佔位參數的數量

    2遍歷形參和數據參數進行數據的bind

    上述代碼很簡單,咱們具體來看看內部的數據bind

    extension SQLiteStatement{    func bind(_ value: SQLiteDataType, `for` stmt: OpaquePointer, at index:Int32) -> Bool{        var result = SQLITE_OK        switch value {        case   is Int32:            result =    sqlite3_bind_int(stmt, index, value as! Int32)            break        case is String:            result = sqlite3_bind_text(stmt, index, value as! String, -2, { (ret:UnsafeMutableRawPointer?) in            })            break        case is Double:            result = sqlite3_bind_double(stmt, index, value as! Double)            break        default:            return false        }        return result == SQLITE_OK    }}複製代碼

    數據bind思路很悠閒,根據獲取多應column的數據類型和index進行數據綁定。

    接下來咱們看看另一個通用的方法…


      func exec(query q: String, values:Dictionary<String, SQLiteDataType>) -> [SQLiteRow]?{        var stmt: OpaquePointer?        var tail: UnsafePointer<Int8>?        // select a,b,c from T t where                let  h = handle        let   result =  sqlite3_prepare(h, q, -1, &stmt, &tail)                if result != SQLITE_OK {            return nil        }        let parmmeterCount = sqlite3_bind_parameter_count(stmt)                for index in 0 ..< parmmeterCount {            let bindedParameterName: UnsafePointer<Int8>! =    sqlite3_bind_parameter_name(stmt, index + 1)            let strBindedParameterName = String(cString: bindedParameterName)            let  key =   (strBindedParameterName as NSString).substring(from: 1)            let value = values[key]                        let bindResult =   bind(value as! SQLiteDataType, for: stmt!, at: index+1)            if bindResult == false{                break            }        }                return fetchData(from: stmt)    }複製代碼

      思路與以前的方法大體相仿,不一樣的是須要將對應占位參數轉換爲Dictionary的key,而後根據key取出數據value,最後拿着 index value進行數據bind拿到咱們須要的Statement……

      兩種通用的方法咱們拿到了,接下來咱們須要的就是如何拿到查詢出來的數據啦

      extension SQLiteStatement {    func fetchData( from stmt: OpaquePointer?)-> [SQLiteRow]?{        let     result = sqlite3_step(stmt)        if (result == SQLITE_ROW || result == SQLITE_DONE || result == SQLITE_OK ) == false {            return nil        }        let colCount = sqlite3_column_count(stmt)        let rowCount = sqlite3_data_count(stmt)        var next = true        next = (next ) || (result == SQLITE_ROW)        var queryResult: Array<SQLiteRow> = Array<SQLiteRow>.init()        while next  && (rowCount > 0 ) {            var rowDataItems:[SQLiteColumnData] = [SQLiteColumnData]()            for i in 0 ..< colCount {                let type = sqlite3_column_type(stmt, i)                var value: Optional<SQLiteDataType> = NSNull()                switch type{                case SQLITE_INTEGER:                    value =   sqlite3_column_int(stmt, i)                case SQLITE_TEXT:                    let tmpValue = sqlite3_column_text(stmt, i)                    value =   String.init(cString: tmpValue!)                case SQLITE_NULL: break                                    case SQLITE_FLOAT:                    value =  sqlite3_column_double(stmt, i)                case SQLITE_BLOB:                    let tmpValue = sqlite3_column_blob(stmt, i)                    let point = tmpValue?.assumingMemoryBound(to: UInt8.self)                    let text = String.init(cString: point!)                    value = text                case SQLITE_ANY:                    let tmpValue:OpaquePointer =    sqlite3_column_value(stmt, i)                                    default: break                                    }                let name:UnsafePointer<Int8>  =                    sqlite3_column_name(stmt, i)                let table = sqlite3_column_table_name(stmt, i)!                let db = sqlite3_column_database_name(stmt, i)                let columnName = String.init(cString: name)                let tableName = String.init(cString: table)                _   = String.init(cString: db!)                                let item: SQLiteColumnData =   SQLiteColumnData(table: tableName, column: columnName, value: value, dataType: type)                                rowDataItems.append(item)            }            let row =     SQLiteRow.init(items: rowDataItems)            queryResult.append(row)            next = (sqlite3_step(stmt) == SQLITE_ROW )        }                return queryResult    }    }複製代碼

      對於statement來講內部存儲的是查詢多行查詢數據,咱們須要按照step進行按行遍歷取到數據便可。

      好了,通用的查詢方法就基本完成,後續接着出通用數據插入方法,慢慢的把基本的CURD寫完,以後會結合起來擼一個簡易的SQLite操做庫到時候但願你們多多支持…

      相關文章
      相關標籤/搜索