本文已参与「新人创作礼」活动,一起开启掘金创作之路。
迁移
.sq文件总是会描述如果在空数据库中创建最新的schema. 如果数据库当前处于较早的版本, 迁移文件将使这些数据库保持最新.
如果驱动支持的话, 迁移将运行在事务中. 不要将迁移包围在BEGIN/END TRANSACTION中间, 因为这将引起某些驱动崩溃.
版本控制
Schema的首个版本是1. 迁移文件命名为<version to upgrade from>.sqm格式. 要迁移到版本2的话, 将迁移语句放入1.sqm文件中:
ALTER TABLE hockeyPlayer ADD COLUMN draft_year INTEGER;
ALTER TABLE hockeyPlayer ADD COLUMN draft_order INTEGER;
这些SQL语句被Database.Schema.migrate()运行. 迁移文件和.sq处于相同的源集.
验证迁移
可以在src/main/sqldelight文件夹下放置.db文件, 该文件格式和<version number>.db相同. 如果当前有.db, 那么新的verifySqlDelightMigration任务将添加到Gradle项目中, 而且它作为test任务的一部分运行, 这意味着将根据该.db文件验证迁移. 它确认迁移会产生具有最新schema的数据库.
要从最新schema中产生.db文件, 需要运行generateSqlDelightSchema任务, 一旦按照gradle.md描述的那样, 指定了schemaOutputDirectory, 文件就可用了. 应该在创建首次迁移之前这么做.
代码迁移
如果从代码中运行迁移, 并且想要执行数据迁移, 就要使用Database.Schema.migrateWithCallbacks:
Database.Schema.migrateWithCallbacks(
driver = database,
oldVersion = 0,
newVersion = Database.Schema.version,
AfterVersion(3) { database.execute(null, "INSERT INTO test (value) VALUES('hello')", 0) },
)
候选情况下, 接收SqlDriver参数通常很有用. 在这种情况下, 可以使用AfterVersionWithDriver类:
Database.Schema.migrateWithCallbacks(
driver = database,
oldVersion = 0,
newVersion = Database.Schema.version,
AfterVersionWithDriver(3) { it.execute(null, "INSERT INTO test (value) VALUES('hello')", 0) },
)
在接下来的例子中, 如果拥有1.sqm, 2.sqm, 3.sqm, 4.sqm, and 5.sqm用于迁移, 上面的回调会在数据库处于版本 4的时候, 在3.sqm完成之后触发. 回调执行之后, 它将恢复至4.sqm并且完成余下的迁移, 在这个事件中, 余下的迁移指的是4.sqm和5.sqm, 这意味着最终的版本是6.
如果在用AndroidSqliteDriver的话, 需要在驱动创建期间传递这些回调:
val driver: SqlDriver = AndroidSqliteDriver(
schema = Database.Schema,
context = context,
name = "test.db",
callback = AndroidSqliteDriver.Callback(
schema = Database.Schema,
AfterVersion(3) { database.execute(null, "INSERT INTO test (value) VALUES('hello')", 0) },
)
)
测试
在一些测试中(比如迁移验证), 你可能想要用JVM驱动 换掉Android驱动, 这使得测试数据库关联代码可以不需要Android模拟器或者物理设备. 要这么做的话, 需要使用jvm SQLite驱动:
dependencies {
testImplementation 'com.squareup.sqldelight:sqlite-driver:1.5.3'
}
// When your test needs a driver
@Before fun before() {
driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
Database.Schema.create(driver)
}
如果在用Android捆绑的SQLite(而不是安装的自己的), 你可以覆盖sqlite-jdbc到一个匹配自己的Android minSdkVersion, 比如API 23使用SQLite 3.8.10.2:
dependencies {
testImplementation('org.xerial:sqlite-jdbc:3.8.10.2') {
// Override the version of sqlite used by sqlite-driver to match Android API 23
force = true
}
}
IntelliJ插件
IntelliJ插件为.sq文件提供了语言级别的特性, 包括:
- 语法高亮
- 重构/找到使用
- 代码自动补全
- 编辑之后生成
Queries文件 - 右击作为合法SQLite复制
- IDE中的编译器错误点击文件
Gradle
想要更多的自定义的话, 需要使用Gradle DSL显式地声明数据库.
build.gradle:
sqldelight {
// Database name
MyDatabase {
// Package name used for the generated MyDatabase.kt
packageName = "com.example.db"
// An array of folders where the plugin will read your '.sq' and '.sqm'
// files. The folders are relative to the existing source set so if you
// specify ["db"], the plugin will look into 'src/main/db' or 'src/commonMain/db' for KMM.
// Defaults to ["sqldelight"]
sourceFolders = ["db"]
// The directory where to store '.db' schema files relative to the root
// of the project. These files are used to verify that migrations yield
// a database with the latest schema. Defaults to null so the verification
// tasks will not be created.
schemaOutputDirectory = file("src/main/sqldelight/databases")
// Optionally specify schema dependencies on other gradle projects
dependency project(':OtherProject')
// The dialect version you would like to target
// Defaults to "sqlite:3.18"
dialect = "sqlite:3.24"
// If set to true, migration files will fail during compilation if there are errors in them.
// Defaults to false
verifyMigrations = true
}
}
如果你在Gradle文件中使用Kotlin:
build.gradle.kts
sqldelight {
database("MyDatabase") {
packageName = "com.example.db"
sourceFolders = listOf("db")
schemaOutputDirectory = file("build/dbs")
dependency(project(":OtherProject"))
dialect = "sqlite:3.24"
verifyMigrations = true
}
}
依赖
可以指定schema依赖于别的模块:
sqldelight {
MyDatabase {
package = "com.example.projecta"
dependency project(":ProjectB")
}
}
这将在ProjectB中查找MyDatabase, 并在编译期导入模块的schema. 这些要想工作, ProjectB必须有相同名字的数据库(这个例子中是MyDatabase), 却在不同的包下生成, 所以ProjectB的gradle也许看起来像下面这样:
sqldelight {
MyDatabase {
package = "com.example.projectb"
}
}