
后端ORM【免费下载链接】sqldelightSQLDelight - Generates typesafe Kotlin APIs from SQL项目地址https://gitcode.com/gh_mirrors/sq/sqldelight点击查看免费下载SQLDelight 的迁移文件.sqm在引入自定义 Kotlin 类型后会失去纯 SQL 合法性无法被 Flyway 等外部数据库迁移工具直接读取。本文围绕migrations_server.md文档讲解如何通过 Gradle 配置将.sqm文件还原为标准 SQL 并输出到指定目录再借助任务依赖让迁移产物进入类路径classpath从而打通 SQLDelight 与外部迁移服务之间的数据通道。读完本文你将掌握migrationOutputDirectory、migrationOutputFileFormat两个配置项的完整用法、生成任务generateMainDatabaseMigrations的命名与触发机制以及其底层的任务实现原理。为什么迁移文件会失去 SQL 合法性SQLDelight 允许在迁移文件中使用自定义 Kotlin 类型custom column types来映射数据库列。一旦.sqm文件中出现AS kotlin.Type之类的自定义类型标记这些文件就不再是标准的 SQL 文本——外部工具如 Flyway、Liquibase 或其他服务无法解析、执行这些文件。也就是说.sqm文件是面向 SQLDelight 编译器的中间产物它既要描述数据库变更语句又要携带类型映射等额外语义。而需要把迁移文件交给其他服务读取时就必须把语义层剥离开只输出干净、可执行的标准 SQL。docs/common/migrations_server.md明确指出了这一点Using custom kotlin types in migration files means those files are no longer valid SQL。这正是本文要解决的问题场景。核心配置migrationOutputDirectory 与 migrationOutputFileFormat在sqldelight的 Gradle 配置块中为指定数据库声明两个属性即可开启迁移导出功能。文档给出的完整配置如下sqldelight { databases { Database { migrationOutputDirectory layout.buildDirectory.dir(resources/main/migrations) migrationOutputFileFormat .sql // Defaults to .sql } }配置项说明配置项类型默认值作用migrationOutputDirectoryDirectoryProperty未设置不生成迁移文件输出的目标目录只有显式赋值后导出任务才会被注册migrationOutputFileFormatPropertyString.sql输出文件的扩展名决定生成文件的后缀从源码sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/SqlDelightDatabase.kt第 4449 行可以看到这两个属性的真实定义val deriveSchemaFromMigrations: PropertyBoolean project.objects.property(Boolean::class.java).convention(false) val verifyMigrations: PropertyBoolean project.objects.property(Boolean::class.java).convention(false) abstract val migrationOutputDirectory: DirectoryProperty val migrationOutputFileFormat: PropertyString project.objects.property(String::class.java).convention(.sql)几点细节migrationOutputDirectory是abstract 的DirectoryProperty由 Gradle 延迟求值因此可以安全地引用layout.buildDirectory.dir(...)这类构建目录属性migrationOutputFileFormat通过convention(.sql)设置了默认值不写也默认为.sqlmigrationOutputDirectory是否存在直接决定了导出任务是否注册源码第 234236 行显示只有当migrationOutputDirectory.isPresent为真时才会调用addMigrationOutputTasks(...)注册对应任务。仓库内的测试夹具sqldelight-gradle-plugin/src/test/schema-output/build.gradle给出了一个可实际运行的完整示例其中使用了 MySQL 方言plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.sqldelight) } sqldelight { databases { MyDatabase { packageName app.cash.sqldelight.mysql.integration dialect(app.cash.sqldelight:mysql-dialect:${app.cash.sqldelight.VersionKt.VERSION}) migrationOutputDirectory layout.buildDirectory.dir(resources/migrations) migrationOutputFileFormat .sql } } } dependencies { implementation libs.truth }注意配置项位于databases内每个数据库各自的配置块中即每个数据库可以拥有独立的输出目录与格式。生成任务generateMainDatabaseMigrations 的命名与注册一旦配置了migrationOutputDirectorySQLDelight 插件就会为每个 source set × 每个数据库注册一个导出任务任务命名规则为generateSourceSet名大写数据库名Migrations文档示例中的generateMainDatabaseMigrations即由main source set与名为Database的数据库组合而来。如果数据库命名为MyDatabase在mainsource set 下任务名就是generateMainMyDatabaseMigrations。任务注册逻辑位于SqlDelightDatabase.kt的addMigrationOutputTasks方法第 283299 行private fun addMigrationOutputTasks( sourceSet: FileCollection, source: Source, ) { project.tasks.register(generate${source.name.capitalize()}${name}Migrations, GenerateMigrationOutputTask::class.java) { it.projectName.set(project.name) it.compilationUnit.set(sourceCollector.compilationUnits().map { units - units.single { unit - unit.name source.name } }) it.source(sourceSet) it.include(**${File.separatorChar}*.$MIGRATION_EXTENSION) it.migrationOutputExtension.set(migrationOutputFileFormat) it.outputDirectory.set(migrationOutputDirectory) it.group SqlDelightPlugin.GROUP it.description Generate valid sql migration files for ${source.name} $name. it.options.set(sourceCollector.databaseOptions(source)) it.classpath.setFrom(intellijEnv, configuration) } }从中可以提取出三条关键信息输入范围任务的源文件集合通过it.include(**${File.separatorChar}*.$MIGRATION_EXTENSION)限定只处理MIGRATION_EXTENSION即.sqm文件普通.sq文件不参与导出输出格式it.migrationOutputExtension.set(migrationOutputFileFormat)将用户配置的扩展名传入任务it.outputDirectory.set(migrationOutputDirectory)指定输出位置任务属性任务属于SqlDelightPlugin.GROUP分组描述文本为 Generate valid sql migration files for ...便于在gradle tasks中识别。该导出任务默认不会自动执行需要显式调用或通过任务依赖挂到既有构建链上见下文。底层实现GenerateMigrationOutputTask 如何产出有效 SQLGenerateMigrationOutputTask位于sqldelight-gradle-plugin/src/main/kotlin/app/cash/sqldelight/gradle/GenerateMigrationOutputTask.kt是一个标准的 GradleWorkerTask实现并标注了CacheableTask支持构建缓存与增量构建。任务输入输出声明CacheableTask abstract class GenerateMigrationOutputTask : SqlDelightWorkerTask() { get:OutputDirectory abstract val outputDirectory: DirectoryProperty get:Input abstract val projectName: PropertyString get:Input abstract val migrationOutputExtension: PropertyString ... }outputDirectory标注为OutputDirectory即migrationOutputDirectory配置项对应的目录projectName模块名与migrationOutputExtension扩展名作为Input参与任务缓存键计算扩展名或模块名变化会触发重新生成。核心生成逻辑任务的WorkAction第 6695 行展示了产出的完整流程override fun execute() { val properties parameters.properties.get() val environment SqlDelightEnvironment( sourceFolders sourceFolders.filter { it.exists() }, dependencyFolders emptyList(), moduleName parameters.moduleName.get(), properties properties, verifyMigrations false, compilationUnit parameters.compilationUnit.get(), dialect ServiceLoader.load(SqlDelightDialect::class.java).first(), ) val outputDirectory parameters.outputDirectory.get().asFile val migrationExtension parameters.migrationExtension.get() // Clear out the output directory. outputDirectory.listFiles()?.forEach { it.delete() } // Generate the new files. environment.forMigrationFiles { migrationFile - val output File( outputDirectory, ${migrationFile.virtualFile!!.nameWithoutExtension}$migrationExtension, ) output.writeText( migrationFile.sqlStmtList?.stmtList.orEmpty() .filterNotNull().joinToString(separator \n\n) { ${it.rawSqlText()}; }, ) } }这里有几个值得深入理解的实现细节环境构建任务内部创建了一个SqlDelightEnvironment并显式设置verifyMigrations false——导出任务只负责文本还原不进行迁移校验方言加载通过ServiceLoader.load(SqlDelightDialect::class.java)加载方言实现这意味着导出行为与所选方言SQLite、MySQL、PostgreSQL 等保持一致输出目录清理每次执行前会清空outputDirectory下的旧文件避免残留过期产物文件命名输出文件名为原.sqm文件的nameWithoutExtension 配置的扩展名。例如1.sqm默认输出为1.sql这保证了迁移的版本号文件命名体系version to upgrade from.sqm被原样保留到导出产物中语句还原关键一步是调用rawSqlText()方法获取每个语句的原始 SQL 文本该工具函数定义于sqldelight-compiler/src/main/kotlin/app/cash/sqldelight/core/lang/util/TreeUtil.kt第 250 行将语句列表用\n\n分隔拼接并逐条追加;作为语句结束符。这正是自定义 Kotlin 类型被剥离、恢复为纯 SQL的底层原理。集成测试验证DialectIntegrationTests.ktsqldelight-gradle-plugin/src/test/kotlin/app/cash/sqldelight/dialect/DialectIntegrationTests.kt第 17 行直接以命令行方式验证了该任务的存在与可运行性.withArguments(clean, generateMainMyDatabaseMigrations, --stacktrace)结合schema-output测试夹具可以确认配置migrationOutputDirectory后任务确实被注册且能通过clean 任务名的组合正常执行产出。与编译任务联动让产物进入 Flyway 的类路径导出任务本身不会自动执行文档给出的典型做法是把它挂到compileKotlin上让迁移产物在编译期之前生成并出现在类路径中供 Flyway 等工具在启动时扫描compileKotlin.configure { dependsOn generateMainDatabaseMigrations }这一做法的实际效果是构建 Kotlin 源码前先执行迁移导出任务migrationOutputDirectory指向layout.buildDirectory.dir(resources/main/migrations)即build/resources/main/migrations该目录属于mainsource set 的资源输出位置因此会被打包进最终产物并出现在运行时类路径中Flyway 通过其 SQL 迁移扫描机制默认查找classpath:db/migration等路径也可按需配置为上述资源路径即可读取到这些*.sql文件并执行。需要强调的是类路径集成方式的最终落地效果取决于 Flyway 的路径扫描配置SQLDelight 只负责把有效 SQL 输出到指定目录具体目录是否被 Flyway 识别需要你在 Flyway 的迁移路径设置中指向migrationOutputDirectory对应的资源目录。实操要点与注意事项任务名随配置变化generateSourceSetDatabaseMigrations中的两个占位符来自你的实际 source set 与数据库名务必先运行gradle tasks --group sqldelight确认真实任务名文件扩展名可自定义migrationOutputFileFormat默认.sql如需其他后缀如.migration.sql直接覆盖即可扩展名是任务Input变更后会自动失效缓存并重新生成输出目录会被清空任务每次执行都会先删除输出目录下的既有文件因此不要在该目录放置手动维护的文件每个数据库独立输出配置写在数据库块内多数据库项目可为每个数据库配置不同的目录与格式互不干扰导出与校验相互独立导出任务内部verifyMigrations false迁移的合法性校验由独立的verifySqlDelightMigration/check链路负责详见 docs/common/migrations.md两者职责分离不要手动提交产物输出目录指向build下的生成目录属于构建产物不应纳入版本控制。小结migrationOutputDirectorymigrationOutputFileFormat为 SQLDelight 打开了一条通往外部迁移服务如 Flyway的标准 SQL 通道。其实现本质是插件为每个 source set × 数据库注册一个可缓存的GenerateMigrationOutputTask该任务通过SqlDelightEnvironment解析.sqm文件剥离自定义 Kotlin 类型语义调用rawSqlText()将语句还原为标准 SQL 文本并按\n\n拼接、逐条补;最终写入配置的输出目录。配合compileKotlin.dependsOn(...)的任务依赖即可让这些产物进入类路径供服务消费。相关参考docs/common/migrations_server.md本文主题文档docs/common/migrations.md迁移版本化与校验机制GenerateMigrationOutputTask.kt导出任务实现SqlDelightDatabase.kt配置属性与任务注册逻辑schema-output 测试夹具可运行配置示例赞分享后端ORM【免费下载链接】sqldelightSQLDelight - Generates typesafe Kotlin APIs from SQL项目地址https://gitcode.com/gh_mirrors/sq/sqldelight点击查看免费下载相关推荐飞书文档批量导出实战指南3步完成500文件迁移的高效方案飞书文档批量导出实战指南3步完成500文件迁移的高效方案 当你面临办公平台切换或需要备份重要文档时飞书文档的批量导出往往成为棘手难题。传统的手动下载方式不CLI企业应用oneTBB parallel_scan 算法详解并行前缀和原理、API 规范与 mold 链接器实战应用oneTBB parallel_scan 算法详解并行前缀和原理、API 规范与 mold 链接器实战应用 本文以 oneTBB 官方规范文档 paralleORM后端数据存储终极指南如何用OpenCore Legacy Patcher让老Mac焕发新生终极指南如何用OpenCore Legacy Patcher让老Mac焕发新生 还在为老Mac无法升级最新macOS而烦恼吗你的2011款MacBook P操作系统固件驱动开发上一篇vcpkg-tool 常见问题解决方案下一篇【亲测免费】 **PyOneDark_Qt_Widgets_Modern_GUI安装与配置完全指南**创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考