Lighter 是一套技术,它应用代码生成来从 SQLite3 数据库访问 Swift,例如在 iOS 应用程序中或在服务器上。类似于 SwiftGen,但针对的是 SQLite3。
Lighter 主要适用于两种场景
SQLite 数据库是一种非常节省资源的方式来发布和访问少量和大量数据。作为捆绑 JSON 资源文件的替代方案,这些文件很大并且每次启动时都必须完全解析到内存中。
使用 SQLite 数据库,只需要加载所需的数据,并且数据库文件非常紧凑(例如,没有重复的键)。
SQLite 数据库对于从网络下载数据也非常高效和有用!
如果需求比像 ORM 这样的完整对象关系映射器 (CoreData) 更简单,Lighter 可以成为为本地缓存或数据库生成简洁且类型安全的 API 的绝佳方式。它很简单但使用方便,并且非常非常快,因为根本不需要运行时映射或解析。代码直接将生成的结构绑定到 SQLite API。
数据库可以动态创建,也可以从作为应用程序资源一部分发布的预填充数据库文件创建。
也支持 Linux,Lighter 可以成为主要访问只读集或在单个主机上运行的简单服务器的绝佳选择。
Lighter 的工作方式与其他“映射”工具或 SQLite 包装器相反。Lighter 不是编写动态生成 SQLite 表的 Swift 代码,而是为 SQLite 数据库生成 Swift 代码。可以直接从 SQLite 数据库文件生成,也可以从创建 SQLite 数据库的 SQL 文件生成。
CREATE TABLE person (
person_id INTEGER PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
title TEXT NULL
);
CREATE TABLE address (
address_id INTEGER PRIMARY KEY NOT NULL,
street VARCHAR NULL,
city VARCHAR NULL,
person_id INTEGER,
FOREIGN KEY(person_id) REFERENCES person(person_id) ON DELETE CASCADE DEFERRABLE
);
可以转换为这样的结构(以高度可配置的方式)
struct ContactsDB {
struct Person: Identifiable, Hashable {
var id : Int
var name : String
var title : String?
}
struct Address: Identifiable, Hashable {
var id : Int
var street : String?
var city : String?
var personId : Int?
}
}
代码生成器可以生成仅使用原始 SQLite3 API 的无依赖代码,也可以生成使用 Lighter 库的代码。Lighter 库不是 ORM,而只是一组允许类型安全查询的 Swift 协议(它仅用于支持代码生成器,而不是作为独立的库)。
该设置旨在与 Swift Package Manager 的新 Swift Package Plugins 功能一起使用,该功能自 Swift 5.6 起可用(并在 Xcode 14+ 中公开)。如果尚无法使用 SPM 插件,也可以直接调用 sqlite2swift 工具。
如果您想支持该项目,Mac AppStore 上还有一个 Code for SQLite3 应用程序。它以稍微更交互的方式执行与此 FOSS 项目相同的代码生成。
Lighter 包带有一个名为 Enlighter 的“构建工具插件”,该插件自动将代码生成结果集成到构建过程中。如果将其添加到目标,它将扫描数据库和 SQL 文件,并为其创建 Swift 访问器
.target(name: "ContactsDB", dependencies: [ "Lighter" ],
resources: [ .copy("ContactsDB.sqlite3") ],
plugins: [ "Enlighter" ]) // <== tell SPM to use Enlighter on this target
此变体是完全自动的,即 ContactsDB
目标中的其他代码可以直接访问数据库类型(例如,上面的 Person
结构)。
作为手动替代方案,提供了 Generate Code for SQLite “命令插件”。此插件执行与 Enlighter 相同的生成,但由开发人员使用 Xcode “File / Packages”菜单显式运行。它将生成的代码放置在应用程序的“Sources”文件夹中(可以在其中检查或修改)。
// Open a SQLite database embedded in the module resources:
let db = ContactsDB.module!
// Fetch the number of records:
print("Total number of people stored:",
try db.people.fetchCount())
// There are various ways to filter, including a plain Swift closure:
let people = try db.people.filter { person in
person.title == nil
}
// Primary & foreign keys are directly supported:
let person = try db.people.find(1)
let addresses = try db.addresses.fetch(for: person)
// Updates can be done one-shot or, better, using a transaction:
try await db.transaction { tx in
var person = try tx.people.find(2)!
// Update a record.
person.title = "ZEO"
try tx.update(person)
// Delete a record.
try tx.delete(person)
// Reinsert the same record
let newPerson = try tx.insert(person) // gets new ID!
}
SQL 的优点之一是可以选择和更新单个列,以获得最高的效率。只需要获取需要的内容(而不是完整记录)
// Fetch just the `id` and `name` columns:
let people = try await db.select(from: \.people, \.id, \.name) {
$0.id > 2 && $0.title == nil
}
// Bulk update a specific column:
try db.update(\.people, set: \.title, to: nil, where: { record in
record.name.hasPrefix("Duck")
})
这些引用是完全类型安全的,直至模式,只能指定 person
表中包含的列。
该工具包也适用于不希望额外依赖 Lighter 的情况。对于这种情况,生成器可以生成与常规 SQLite API 并行的特定于数据库的 Swift API。
// Open the database, can also just use `sqlite3_open_v2`:
var db : OpaquePointer!
sqlite3_open_contacts("contacts.db", &db)
defer { sqlite3_close(db) }
// Fetch a person by primary key:
let person = sqlite3_person_find(db, 2)
// Fetch and filter people:
let people = sqlite3_people_fetch(db) {
$0.name.hasPrefix("Ja")
}
// Insert a record
var person = Person(id: 0, name: "Jason Bourne")
sqlite3_person_insert(db, &person)
代码生成器可以生成另一种风格的代码,它将相同的功能附加到生成的类型,例如:
let people = Person.fetch(in: db) { $0.name.hasPrefix("So") }
var person = Person.find(2, in: db)
person.name = "Bourne"
person.update(in: db)
person.delete(in: db)
person.insert(into: db)
使用原始 API 的主要优点是不需要任何额外的依赖项。生成的函数是完全独立的,可以真正地复制 & 粘贴到需要的地方。
感兴趣?👉 入门。
Lighter 由 Helge Heß / ZeeZide 带给您。我们喜欢反馈,GitHub 星星,酷的合同工作,大概任何你能想到的赞扬形式。
想要支持我的工作?购买一个 应用程序:Code for SQLite3, Past for iChat, SVG Shaper, HMScriptEditor。你不一定要用它! 😀