之前在Swift下使用SQLite很是麻烦(当然OC下也是挺麻烦的),苹果官方文档中,要使用原生的SQLite,要先导入framwork,然后建一个.h文件,还要做一次Swift与C语言的桥接(SQLite是基于C语言的),使用的时候还要写SQL语句,反正就是很麻烦,需要写很多胶水代码。
pod 'SQLite.swift', '~> 0.11.4'
import SQLite
//获取doc路径
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
//如果不存在的话,创建一个名为db.sqlite3的数据库,并且连接数据库
let db = try Connection("\(path)/db.sqlite3")
let path = Bundle.main.pathForResource("db", ofType: "sqlite3")
let db = try Connection(path, readonly: true)
//创建一个内存数据库
let db = try Connection()
db.busyTimeout = 5
db.busyHandler({ tries in
if tries >= 3 {
return false
}
return true
})
let id = Expression<Int64>("id")
let email = Expression<String>("email")
let balance = Expression<Double>("balance")
let verified = Expression<Bool>("verified")
let name = Expression("name")
let users = Table("users")
try db.run(users.create(ifNotExists: true) { t in // CREATE TABLE "users" (
t.column(id, primaryKey: true) // "id" INTEGER PRIMARY KEY NOT NULL,
t.column(email, unique: true) // "email" TEXT UNIQUE NOT NULL,
t.column(name) // "name" TEXT
})
t.column(id, primaryKey: true)
// "id" INTEGER PRIMARY KEY NOT NULL
t.column(id, primaryKey: .autoincrement)
// "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
t.column(email, unique: true)
// "email" TEXT UNIQUE NOT NULL
t.column(email, check: email.like("%@%"))
// "email" TEXT NOT NULL CHECK ("email" LIKE '%@%')
t.column(name, defaultValue: "Anonymous")
// "name" TEXT DEFAULT 'Anonymous'
t.column(email, collate: .nocase)
// "email" TEXT NOT NULL COLLATE "NOCASE"
t.column(name, collate: .rtrim)
// "name" TEXT COLLATE "RTRIM"
t.column(user_id, references: users, id)
// "user_id" INTEGER REFERENCES "users" ("id")
//不像上面的字段约束,它支持所有的数据库类型,升序和降序命令,和复合(多字段)键。
t.primaryKey(email.asc, name)
// PRIMARY KEY("email" ASC, "name")
//不像上面的字段约束,它支持复合(多字段)键。
t.unique(local, domain)
// UNIQUE("local", "domain")
t.check(balance >= 0)
// CHECK ("balance" >= 0.0)
//可以使用过滤器运算符和函数轻松地构造布尔表达式。
t.check(balance >= 0)
// CHECK ("balance" >= 0.0)
//和上面的引用约束不同的是,它支持SQLite的全部类型,比如更新、删除操作以及复合(多字段)键。
t.foreignKey(user_id, references: users, id, delete: .setNull)
// FOREIGN KEY("user_id") REFERENCES "users"("id") ON DELETE SET NULL
try db.run(users.insert(email <- "[email protected]", name <- "Alice"))
// INSERT INTO "users" ("email", "name") VALUES ('[email protected]', 'Alice')
try db.run(users.insert(or: .replace, email <- "[email protected]", name <- "Alice B."))
// INSERT OR REPLACE INTO "users" ("email", "name") VALUES ('[email protected]', 'Alice B.')
do {
let rowid = try db.run(users.insert(email <- "[email protected]"))
print("inserted id: \(rowid)")
} catch {
print("insertion failed: \(error)")
}
try db.run(users.delete())
// DELETE FROM "users"
let alice = users.filter(id == 1)
try db.run(alice.delete())
// DELETE FROM "users" WHERE ("id" = 1)
do {
if try db.run(alice.delete()) > 0 {
print("deleted alice")
} else {
print("alice not found")
}
} catch {
print("delete failed: \(error)")
}
在SQLite.swift中,可以直接使用 ‘<-’ 为字段赋值,由上文表达式一节可见端倪,同样,我们也可以在update,delete等语句中使用同样格式进行操作。比如,在更新语句中:
try db.run(users.update(balance-=10))
这条语句是指对表中全部数据的balance字段进行 -10 操作。
try db.run(users.update(email <- "[email protected]"))
// UPDATE "users" SET "email" = '[email protected]'
let alice = users.filter(id == 1)
try db.run(alice.update(email <- "[email protected]"))
// UPDATE "users" SET "email" = '[email protected]' WHERE ("id" = 1)
do {
if try db.run(alice.update(email <- "[email protected]")) > 0 {
print("updated alice")
} else {
print("alice not found")
}
} catch {
print("update failed: \(error)")
}
for user in try db.prepare(users) {
print("id: \(user[id]), email: \(user[email]), name: \(user[name])")
}
// SELECT * FROM "users"
for user in try db.prepare(users) {
do {
print("name: \(try user.get(name))")
} catch {
// handle
}
}
if let user = try db.pluck(users) { /* ... */ } // Row
// SELECT * FROM "users" LIMIT 1
let all = Array(try db.prepare(users))
// SELECT * FROM "users"
let query = users.select(email) // SELECT "email" FROM "users"
.filter(name != nil) // WHERE "name" IS NOT NULL
.order(email.desc, name) // ORDER BY "email" DESC, "name"
.limit(5, offset: 1) // LIMIT 5 OFFSET 1
for user in try db.prepare(users.select(id, email)) {
print("id: \(user[id]), email: \(user[email])")
// id: 1, email: [email protected]
}
// SELECT "id", "email" FROM "users"
users.join(posts, on: user_id == users[id])
// SELECT * FROM "users" INNER JOIN "posts" ON ("user_id" = "users"."id")
let managers = users.alias("managers")
let query = users.join(managers, on: managers[id] == users[managerId])
// SELECT * FROM "users"
// INNER JOIN ("users") AS "managers" ON ("managers"."id" = "users"."manager_id")
users.filter(id == 1)
// SELECT * FROM "users" WHERE ("id" = 1)
users.filter([1, 2, 3, 4, 5].contains(id))
// SELECT * FROM "users" WHERE ("id" IN (1, 2, 3, 4, 5))
users.filter(email.like("%@mac.com"))
// SELECT * FROM "users" WHERE ("email" LIKE '%@mac.com')
users.filter(verified && name.lowercaseString == "alice")
// SELECT * FROM "users" WHERE ("verified" AND (lower("name") == 'alice'))
users.filter(verified || balance >= 10_000)
// SELECT * FROM "users" WHERE ("verified" OR ("balance" >= 10000.0))
users.order(email, name)
// SELECT * FROM "users" ORDER BY "email", "name"
users.order(email.desc, name.asc)
// SELECT * FROM "users" ORDER BY "email" DESC, "name" ASC
users.limit(5)
// SELECT * FROM "users" LIMIT 5
users.limit(5, offset: 5)
// SELECT * FROM "users" LIMIT 5 OFFSET 5
let count = try db.scalar(users.count)
// SELECT count(*) FROM "users"
let count = try db.scalar(users.filter(name != nil).count)
// SELECT count(*) FROM "users" WHERE "name" IS NOT NULL
let count = try db.scalar(users.select(name.count)) // -> Int
// SELECT count("name") FROM "users"
let max = try db.scalar(users.select(id.max)) // -> Int64?
// SELECT max("id") FROM "users"
let min = try db.scalar(users.select(id.min)) // -> Int64?
// SELECT min("id") FROM "users"
let average = try db.scalar(users.select(balance.average)) // -> Double?
// SELECT avg("balance") FROM "users"
let sum = try db.scalar(users.select(balance.sum)) // -> Double?
// SELECT sum("balance") FROM "users"
let total = try db.scalar(users.select(balance.total)) // -> Double
// SELECT total("balance") FROM "users"
do {
try db.run(users.insert(email <- "[email protected]"))
try db.run(users.insert(email <- "[email protected]"))
} catch let Result.error(message, code, statement) where code == SQLITE_CONSTRAINT {
print("constraint failed: \(message), in \(statement)")
} catch let error {
print("insertion failed: \(error)")
}