ActiveSQLite 是一个 SQLite.Swift 的封装和扩展。 目的是让你使用SQLite.swift更加简单。
使用ActiveSQLite的一个例子是Reed downloader。
- 支持 SQLite.swift 的所有特性。
- 自动创建表. 自动创建 id , created_at 和 updated_at 列。
- 自动把SQL查询的数据赋值给数据库模型ASModel的属性。
- 自定义表名和模型名之间的映射,列名和模型的属性名之间的映射。
- 支持事务和异步。
- 提供可扩展,链式,延迟执行的查询接口。
- 通过属性名字符串,字典,或SQLite.swift的表达式Expression查询和修改数据。
- 日志级别
- 由Runtime编码改为Codable编码
- 完全的面向协议编程
- 表关联
- 缓存和惰值
执行 ActiveSQLiteTests target.
import ActiveSQLite
//定义model和table
class Product:ASModel{
var name:String = ""
var price:NSNumber = NSNumber(value:0.0)
var desc:String?
var publish_date:NSDate?
}
//保存
let product = Product()
product.name = "iPhone 7"
product.price = NSNumber(value:599)
try! product.save()
//查询
let p = Product.findFirst("name",value:"iPhone")
//or
let name = Expression<String>("name")
let p = Product.findAll(name == "iPhone").first
//id = 1, name = iPhone 7, price = 599, desc = nil, publish_date = nil, created_at = 1498616987587.237, updated_at = 1498616987587.237,
//更新
p.name = "iPad"
try! p.update()
//删除
p.delete()
在你的工程的target使用ActiveSQLite, 需要首先导入 ActiveSQLite
模块.
import ActiveSQLite
ASConfigration.setDefaultDB(path:"db file path", name: "default db name")
//If you want a other db
ASConfigration.setDB(path: "other db file path", name: "other db name")
必须设置 setDefaultDB 。
ActiveSQLite Swift Type |
SQLite.swift Swift Type |
SQLite SQLite Type |
表字段默认值 模型属性不用可选类型的情况下 |
---|---|---|---|
NSNumber |
Int64 |
INTEGER |
0 |
NSNumber |
Double |
REAL |
0.0 |
String |
String |
TEXT |
"" |
nil |
nil |
NULL |
NULL |
SQLite.Blob |
BLOB |
||
NSDate |
Int64 |
INTEGER |
0 |
NSNumber类型对应SQLite.swift的两种类型(Int64和Double)。NSNumber默认的映射类型是Int64。重写ASModel的doubleTypes()方法能标记属性为Double类型。
class Product:ASModel{
var name:String = ""
var price:NSNumber = NSNumber(value:0.0)
var desc:String?
var publish_date:NSDate?
override func doubleTypes() -> [String]{
return ["price"]
}
}
ActiviteSQLite映射NSDate类型到SQLite.swift的Int64类型。 你可以通过查找SQLite.swift的文档Custom Types of Documentaion映射NSDate到String。
ActiveSQLite自动创建表并且添加"id", "created_at"和 "updated_at"字段。"id"字段是主键。 创建的代码类似于下面这样:
try db.run(products.create { t in
t.column(id, primaryKey: true)
t.column(Expression<NSDate>("created_at"), defaultValue: NSDate(timeIntervalSince1970: 0))
t.column(Expression<NSDate>("updated_at"), defaultValue: NSDate(timeIntervalSince1970: 0))
t.column(...)
})
// CREATE TABLE "Products" (
// "id" INTEGER PRIMARY KEY NOT NULL,
// created_at INTEGER DEFAULT (0),
// created_at INTEGER DEFAULT (0),
// ...
// )
"created_at"和"updated_at"字段的单位是毫秒ms。
ActiveSQLite0.4.0 用3种类型定义属性: T, T!, T?.
ActiveSQLite0.4.1 用两种类型定义属性: T, T?.
类型 | 0.4.0 | 0.4.1 |
---|---|---|
T |
不为空 |
不为空 |
T! |
不为空 |
可为空。使用T?替换 |
T? |
可为空 |
可为空 |
主键 id |
是 T! 类型 |
是 T? 类型 |
【数据库字段的默认值参考本文档第一张表】。
你可以自定义表的名字, 列的名字,还可以设置瞬时属性不存在数据库中。
如果你只用了一个数据库,那么设置完 setDefaultDB(path:name:) 就可以了,不需要做额外的操作。如果你用了多个数据库,设置表在特定的数据库,只需要写model的时候,重写dbName。
ASConfigration.setDefaultDB(path:"db file path", name: "default db name")
ASConfigration.setDB(path: "other db file path", name: "other db name")
override class var dbName:String?{
return "other db name"
}
默认的表名和类名相同。设置其他表名的时候,只需要在model定义中重写nameOfTable。
//设置表名为 "ProductTable"
override class var nameOfTable: String{
return "ProductTable"
}
默认的列名和属性名相同,不需要做额外的操作。如果要使属性名和列名不同,需要重写mapper()
override func mapper() -> [String:String]{
return ["property_name":"column_name"];
}
如果要设置主键对应的列名,需要重写 PRIMARY_KEY 和 mapper()。
override class var PRIMARY_KEY:String{
return "_id"
}
override func mapper() -> [String:String]{
return ["id":"_id"]
}
瞬时属性不会被存在数据库中。
override class func transientTypess() -> [String]{
return ["isSelected"]
}
ActiveSQLite 仅仅保存三种属性类型 (String,NSNumber,NSDate)到数据库。 如果属性不是这三种类型,那么不会被存入数据库,它们被当做瞬时属性看待。
只需要重写 isSaveDefaulttimestamp, 不需要做任何其他事情, 父类 ASModel 已经定义了 "created_at" 和 "updated_at" 属性。
override class var isSaveDefaulttimestamp:Bool{
return true
}
如果你要自定义列, 你仅需要实现CreateColumnsProtocol协议的createColumns方法,那么ActiveSQLite就不会自动创建列。写自己的建列语句,要注意列名和属性名必须一致,否则不能自动从查询sql封装数据库模型对象。
class Users:ASModel,CreateColumnsProtocol{
var name:String = ""
var email:String = ""
var age:Int?
func createColumns(t: TableBuilder) {
t.column(Expression<NSNumber>("id"), primaryKey: true)
t.column(Expression<String>("name"),defaultValue:"Anonymous")
t.column(Expression<String>("email"), , check: email.like("%@%"))
}
}
更多信息查考SQLite.swift的文档table constraints document。
有三个方法用来插入记录。
插入一条。
func insert()throws ;
插入多条。
class func insertBatch(models:[ASModel])throws ;
保存方法。
如果数据库模型对象的 id == nil,那么执行插入。如果id != nil那么执行更新语句。
func save() throws;
例如:
let u = Users()
u.name = "Kevin"
try! u.save()
var products = [Product]()
for i in 1 ..< 8 {
let p = Product()
p.name = "iPhone-\(i)"
p.price = NSNumber(value:i)
products.append(p)
}
try! Product.insertBatch(models: products)
更多信息可以看ActiveSQLite的源码和例子, 也可以查阅SQLite.swift的文档Inserting Rows document。
有三种更新策略。
首先修改属性的值,然后执行save() 或者 update() 或者 updateBatch()。
p.name = "zhoukai"
p.save()
//更新一条
u.update("name",value:"3ds")
u.update(["name":"3ds","price":NSNumber(value:199)])
//更新多条
Product.update(["name": "3ds","price":NSNumber(value:199)], where: ["id": NSNumber(1)])
//更新一条记录
p.update([Product.price <- NSNumber(value:199))
//更新多条
Product.update([Product.price <- NSNumber(value:199), where: Product.name == "3ds")
了解更多请看ActiveSQLite的源码和例子, 查看SQLite.swift的文档Updating Rows document , Setters document。
使用findFirst方法查询一条记录,使用findAll方法查询多条记录。
方法名前缀是"find"的是类方法,这种方法一次性查询出结果。
let p = Product.findFirst("name",value:"iWatch")
let ps = Product.findAll("name",value:"iWatch",orders:["price",false])
let id = Expression<NSNumber>("id")
let name = Expression<String>("name")
let arr = Product.findAll(name == "iWatch")
let ps = Product.findAll(id > NSNumber(value:100), orders: [Product.id.asc])
链式查询方法是属性方法。
let products = Product().where(Expression<NSNumber>("code") > 3)
.order(Product.code)
.limit(5)
.run()
不要忘记执行run()。
更多复杂的查询参考ActiveSQLite的源码和例子。和SQLite.swift的文档Building Complex Queries。
SQLite.swift再更新update和查询select操作中,使用表达式Expression转换成SQL的'where'判断,。更多复杂的表达式用法,参考文档filtering-rows。
//1. 删除一条
try? product.delete()
//2. 删除所有
try? Product.deleteAll()
//3. 通过表达式Expression链式删除。
try? Product().where(Expression<NSNumber>("code") > 3)
.runDelete()
建议把所有的insert,update,delete操作和alter表的代码全部放在ActiveSQLite.save代码块中。一个块中的sql操作在同一个事务当中。
ActiveSQLite.save({
var products = [Product]()
for i in 0 ..< 3 {
let p = Product()
p.name = "iPhone-\(i)"
p.price = NSNumber(value:i)
products.append(p)
}
try Product.insertBatch(models: products)
let u = Users()
u.name = "Kevin"
try u.save()
}, completion: { (error) in
if error != nil {
debugPrint("transtion fails \(error)")
}else{
debugPrint("transtion success")
}
})
ActiveSQLite.saveAsync是一个异步的操作,当然代码块中的sql也在同一个事务当中。
ActiveSQLite.saveAsync({
.......
}, completion: { (error) in
......
})
class Product{
var name:String!
var newColumn:String!
override class var nameOfTable: String{
return "newTableName"
}
}
let db = DBConnection.sharedConnection.db
if db.userVersion == 0 {
ActiveSQLite.saveAsync({
try Product.renameTable(oldName:"oldTableName",newName:"newTableName")
try Product.addColumn(["newColumn"])
}, completion: { (error) in
if error == nil {
db.userVersion = 1
}
})
}
更多SQLite.swift的修改表信息参看 Altering the Schema。
let name = Expression<String>("name")
Product.createIndex(name)
Product.dropIndex(name)
更多信息查看 Indexes of SQLite.swift Document。
Product.dropTable()
有四种日志级别,分别是: debug,info,warn,error。 默认的日志级别是info。像这样来设置日志级别:
//1. 设置日志级别
ASConfigration.logLevel = .debug
//2. 设置数据库路径
ASConfigration.dbPath = "..."
保证首先设置日志级别,后设置数据库路径。
- iOS 8.0+
- Xcode 10.2
- Swift 5
再Podfile文件中添加:
pod "ActiveSQLite"
Kevin Zhou
- 邮件: [email protected]
- Facebook: wumingapie
- 微信&QQ: 458545592
ActiveSQLite is available under the MIT license. See the LICENSE file for more info.