需要实现两个功能:
提供绑定数据方法提供一个类,封装整个SQL的管理:绑定、转换,包括swift到数据库及其方向的 *** 作。
//作用:封装SQL,同时绑定数据(类型映射)
public final class Statement {
//第一步:提供构造方法->执行创建表SQL语句
fileprivate var handle: OpaquePointer? = nil
fileprivate let connection: Connection
//提供构造方法
init(_ connection: Connection, _ SQL: String) throws {
self.connection = connection
//执行创建表 *** 作
try connection.check(sqlite3_prepare_v2(connection.handle, SQL, -1, &handle, nil))
}
//析构函数
deinit {
sqlite3_finalize(handle)
}
第二步:绑定数据 =>提供原始绑定方法
//1、原始方法->绑定数据
//Swift属性值->绑定到->数据库
//为什么搞了一个Binding?
//父类引用指向子类实例对象(多态)
fileprivate func bind(_ value: Binding?, atIndex idx: Int) {
if value == nil {
//一一对应
//绑定的是nil空值->"NULL"
sqlite3_bind_null(handle, Int32(idx))
} else if let value = value as? String {
sqlite3_bind_text(handle, Int32(idx), value, -1, SQLITE_TRANSIENT)
} else if let value = value {
fatalError("tried to bind unexpected value \(value)")
}
}
绑定方法重载=>循环遍历
//重置(重新赋值)
fileprivate func reset(clearBindings shouldClear: Bool = true) {
sqlite3_reset(handle)
if (shouldClear) {
sqlite3_clear_bindings(handle)
}
}
//参数:字典
public func bind(_ values: [String: Binding?]) -> Statement {
//绑定之前->先重置
reset()
//循环遍历字段名称和字段值
for (name, value) in values {
//根据字段名称->获取字段在数据库里面的下标
//例如:create table t_user (name TEXT, sex TEXT)
//这个表中字段下标
//name->0
//sex->1
//...
let idx = sqlite3_bind_parameter_index(handle, name)
//如果不存在抛异常即可,不允许绑定
guard idx > 0 else {
fatalError("parameter not found: \(name)")
}
//绑定
bind(value, atIndex: Int(idx))
}
return self
}
绑定方法重载->提供默认方法(抽象公共功能)
//参数:数组
public func bind(_ values: [Binding?]) -> Statement {
if values.isEmpty {
return self
}
reset()
guard values.count == Int(sqlite3_bind_parameter_count(handle)) else {
fatalError("\(sqlite3_bind_parameter_count(handle)) values expected, \(values.count) passed")
}
for idx in 1...values.count {
bind(values[idx - 1], atIndex: idx)
}
return self
}
public func bind(_ values: Binding?...) -> Statement {
return bind(values)
}
执行SQL语句
//检测数据库
public func step() throws -> Bool {
return try connection.sync {
try self.connection.check(sqlite3_step(self.handle)) == SQLITE_ROW
}
}
//参数列表不同
//参数列表:数组
//discardableResult方法返回值->可以不接受(去除方法返回值警告)
@discardableResult public func run(_ bindings: [Binding?]) throws -> Statement {
return try bind(bindings).run()
}
//参数列表:字典
@discardableResult public func run(_ bindings: [String: Binding?]) throws -> Statement {
return try bind(bindings).run()
}
//参数列表:可变参数->具体实现
@discardableResult public func run(_ bindings: Binding?...) throws -> Statement {
//guard语法->不为空->绑定
guard bindings.isEmpty else {
//存在->绑定
return try run(bindings)
}
//不存在(必需调用)->避免缓存->给下一次 *** 作
reset(clearBindings: false)
repeat {} while
try step()
return self
}
为Connection提供接口
为了方便客户端调用,对已有的一些接口集中到Connection重载:
prepare重载 //重载一:prepare参数列表
//参数一:statement语句
//参数二:bindings->可变参数类型
public func prepare(_ statement: String, _ bindings: Binding?...) throws -> Statement {
if !bindings.isEmpty {
return try prepare(statement, bindings)
}
return try Statement(self, statement)
}
//重载二:prepare参数列表
//参数一:statement语句
//参数二:bindings->数组类型
public func prepare(_ statement: String, _ bindings: [Binding?]) throws -> Statement {
return try prepare(statement).bind(bindings)
}
//重载三:prepare参数列表
//参数一:statement语句
//参数二:bindings->字典类型
public func prepare(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement {
return try prepare(statement).bind(bindings)
}
//----------------------------------------
run重载
//重载一:run参数列表
//参数一:statement语句
//参数二:bindings->可变参数类型
@discardableResult public func run(_ statement: String, _ bindings: Binding?...) throws -> Statement {
return try run(statement, bindings)
}
//重载二:run参数列表
//参数一:statement语句
//参数二:bindings->数组类型
@discardableResult public func run(_ statement: String, _ bindings: [Binding?]) throws -> Statement {
return try prepare(statement).run(bindings)
}
//重载三:run参数列表
//参数一:statement语句
//参数二:bindings->字典类型
@discardableResult public func run(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement {
return try prepare(statement).run(bindings)
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)