后端ORM【免费下载链接】sqldelightSQLDelight - Generates typesafe Kotlin APIs from SQL项目地址https://gitcode.com/gh_mirrors/sq/sqldelight点击查看免费下载导读本文以 SQLDelight 官方文档中的 SQLite 类型章节为核心系统讲解 SQLDelight 中从 SQL 类型到 Kotlin 类型的映射规则、AS扩展列约束语法、原始类型适配器primitive-adapters、自定义列类型ColumnAdapter、枚举存储与 Value 类型包装。读完本文你将掌握如何为任意 SQLite 列声明所需的 Kotlin 类型并能在创建Database时为自定义类型注入编解码适配器从而让生成的数据访问层直接暴露类型安全的领域对象。本文内容同时适用于 SQLDelight 的 JS/SQLiteWebAssembly、sql.js以及各 JVM 方言环境核心语法与 API 完全一致。SQLite 默认类型映射SQLDelight 的列定义与标准 SQLite 列定义完全一致唯一的差别是你可以通过一个**额外的列约束extra column constraint**为列指定生成接口中所使用的 Kotlin 类型这就是本文后续要重点讲解的AS子句。若不使用该扩展SQLDelight 会按照 SQLite 的类型亲和性type affinity采用以下默认映射CREATE TABLE some_types ( some_long INTEGER, -- 数据库中存为 INTEGER读取为 Long some_double REAL, -- 数据库中存为 REAL读取为 Double some_string TEXT, -- 数据库中存为 TEXT读取为 String some_blob BLOB -- 数据库中存为 BLOB读取为 ByteArray );对应的类型对照关系如下SQLite 存储类型SQLDelight 生成的 Kotlin 类型说明INTEGERLong有符号 64 位整数REALDoubleIEEE 754 浮点数TEXTStringUTF-8/UTF-16 文本BLOBByteArray二进制字节数组这也是ColumnAdapter接口中数据库侧类型仅限四种的原因运行时把Long、Double、String、ByteArray视为 SQLite 的四种基础存储类型见 ColumnAdapter.kt 的接口注释。当某一列的 Kotlin 类型与上述四种默认类型不一致时就需要适配器在这两者之间做转换。扩展列约束的语法规则AS子句并不是魔法它由 SQLDelight 的 ANTLR 语法文件明确定义。在 sqldelight.bnf 中列类型的产生式如下column_type :: {type_name} [ AS ( VALUE | LOCK | ( annotation) * java_type_name ) ]也就是说任何合法 SQLite 类型名type_name后面都可以追加AS扩展其后允许出现三种形态VALUE让 SQLDelight 为该列生成一个包装底层数据库类型的 Value 类型见下文LOCK锁定列的值类型配合 value 类型使用一个或多个注解之后跟随的 Java/Kotlin 类型名java_type_name支持泛型参数例如AS ListString、AS HockeyPlayer.Position。类型名解析规则同样定义在 sqldelight.bnf支持嵌套泛型如ListListString。这意味着AS语法本身由编译器负责解析而数据库表结构中并不存在AS列——它纯粹是 SQLDelight 的编译期扩展用来告诉代码生成器该列在 Kotlin 侧应该是什么类型。原始类型适配器primitive-adaptersSQLite 底层只有INTEGER、REAL、TEXT、BLOB四种存储类型因此Long、Double、String、ByteArray之外的其他 Kotlin 原始类型如Int、Float、Short无法直接映射。为此 SQLDelight 提供了独立的primitive-adapters模块其中预置了三个开箱即用的适配器。添加依赖 Kotlin DSLkotlin dependencies { implementation(app.cash.sqldelight:primitive-adapters:{{ versions.sqldelight }}) } Groovy DSLgroovy dependencies { implementation app.cash.sqldelight:primitive-adapters:{{ versions.sqldelight }} }{{ versions.sqldelight }}是文档中的版本占位符实际使用时请替换为你所采用的 SQLDelight 版本号。预置的三种适配器模块提供以下适配器源码位于 adapters/primitive-adaptersFloatColumnAdapter— 将隐式以Double存储的 SQL 类型读取为kotlin.FloatIntColumnAdapter— 将隐式以Long存储的 SQL 类型读取为kotlin.IntShortColumnAdapter— 将隐式以Long存储的 SQL 类型读取为kotlin.Short。以IntColumnAdapter为例它的实现就是一个纯粹的Long与Int互转的ColumnAdapter// adapters/primitive-adapters/src/commonMain/kotlin/app/cash/sqldelight/adapter/primitive/IntColumnAdapter.kt object IntColumnAdapter : ColumnAdapterInt, Long { override fun decode(databaseValue: Long): Int databaseValue.toInt() override fun encode(value: Int): Long value.toLong() }该模块的每个适配器都带有对应的跨平台单元测试如 IntColumnAdapterTest.kt可验证其编解码行为。由于这些适配器以object单例实现它们无状态、可复用适合在多处重复注入。使用方式与自定义适配器一致在创建Database时把对应列的 adapter 传入生成表的Adapter构造器即可见下一节。自定义列类型Custom Column Types当预置适配器无法满足需求时你可以让任意一列以自定义 Kotlin 类型出现。做法分两步先在.sq文件中用AS声明目标类型再在创建Database时提供对应的ColumnAdapter。第一步在 SQL 中声明 Kotlin 类型import kotlin.String; import kotlin.collections.List; CREATE TABLE hockeyPlayer ( cup_wins TEXT AS ListString NOT NULL );注意 SQL 文件顶部的import语句自定义类型必须是可解析的完整类型名泛型类型如ListString同样支持。声明后生成的HockeyPlayer数据类中cup_wins字段的类型即为ListString而非String。第二步实现 ColumnAdapter 并注入 Database创建Database时SQLDelight 会要求你为所有使用了自定义类型的列提供适配器。ColumnAdapterT, S只有两个方法需要实现decode(databaseValue: S): T— 把数据库侧值S解码为自定义类型T读路径encode(value: T): S— 把自定义类型T编码回数据库侧值S写路径。以把逗号分隔的TEXT映射为ListString为例val listOfStringsAdapter object : ColumnAdapterListString, String { override fun decode(databaseValue: String) if (databaseValue.isEmpty()) { listOf() } else { databaseValue.split(,) } override fun encode(value: ListString) value.joinToString(separator ,) } val queryWrapper: Database Database( driver driver, hockeyPlayerAdapter hockeyPlayer.Adapter( cup_winsAdapter listOfStringsAdapter ) )Database构造函数中的hockeyPlayerAdapter参数接收代码生成器为每张表生成的Adapter类其命名规则为「表名 .Adapter」而cup_winsAdapter正是AS声明对应的那一列。此后所有对该列的读写都会自动经过listOfStringsAdapter完成双向转换——对上层代码完全透明。ColumnAdapter接口的完整定义见 ColumnAdapter.ktdecode与encode互为逆操作接口注释明确要求数据库侧类型S必须是Long、Double、String、ByteArray之一这保证了适配器可以安全地接入 SQLite 驱动层。枚举类型Enums把枚举以字符串形式存库是常见需求。SQLDelight 运行时为此内置了EnumColumnAdapter它本质上是一个把枚举映射为String的ColumnAdapter无需你手动实现。声明与注入import com.example.hockey.HockeyPlayer; CREATE TABLE hockeyPlayer ( position TEXT AS HockeyPlayer.Position )val queryWrapper: Database Database( driver driver, hockeyPlayerAdapter HockeyPlayer.Adapter( positionAdapter EnumColumnAdapter() ) )EnumColumnAdapter()以无参形式调用时是一个inline reified工厂函数它会根据类型参数自动获取该枚举的所有取值见 EnumColumnAdapter.kt。底层实现原理EnumColumnAdapterT的编解码策略很直观EnumColumnAdapter.ktdecode在枚举值集合中查找name与数据库字符串相等的那一项enumValues.first { it.name databaseValue }encode直接取value.name作为存储字符串。也就是说数据库中保存的是枚举的name而非ordinal因此对枚举重命名会导致历史数据无法匹配迁移时需要注意这一点。此外该实现要求枚举值必须存在若数据库中出现未知字符串会抛出异常属于按名精确匹配的严格策略。Value 类型Value Types对于希望给列增加语义化包装、又不愿写完整适配器的场景SQLDelight 支持用AS VALUE声明让编译器为列自动生成一个包装底层数据库类型的 value 类型CREATE TABLE hockeyPlayer ( id INT AS VALUE );该语法对应 sqldelight.bnf 中column_type产生式的VALUE分支。从文档描述看生成的值类型会包裹该列在数据库中的底层类型从而在 Kotlin 侧获得一个区别于普通Long/Int的独立类型例如用于区分球员 id与球队 id避免传参时混用。AS LOCK语法则用于锁定该值类型防止其被隐式转换为底层原始类型。value 类型在写回数据库时仍以底层类型参与绑定因此不会改变表的物理存储结构。说明Value 类型是相对较新的语法特性具体生成代码的形态取决于你所使用的 SQLDelight 版本建议以当前版本实际生成的代码为准。总结与进一步阅读SQLDelight 的类型系统可以概括为一条主线SQLite 只有四种存储类型而 Kotlin 侧的类型由AS扩展约束决定凡是与默认四类映射不一致的类型都通过ColumnAdapter在数据库侧值与自定义类型之间桥接。从primitive-adapters的Int/Float/Short到枚举再到任意领域类型全部遵循同一套注入机制这也让生成的数据访问层既保持类型安全又具备充分的扩展空间。相关参考本文档同主题的其他方言版本android_sqlite/types.md、jvm_sqlite/types.md、multiplatform_sqlite/types.md自定义列类型的完整文档docs/common/custom_column_types.md运行时适配器接口与枚举适配器runtime/src/commonMain/kotlin/app/cash/sqldelight/ColumnAdapter.kt、runtime/src/commonMain/kotlin/app/cash/sqldelight/EnumColumnAdapter.kt原始类型适配器实现与测试adapters/primitive-adaptersAS语法产生式sqldelight-compiler/src/main/kotlin/app/cash/sqldelight/core/sqldelight.bnf赞分享后端ORM【免费下载链接】sqldelightSQLDelight - Generates typesafe Kotlin APIs from SQL项目地址https://gitcode.com/gh_mirrors/sq/sqldelight点击查看免费下载相关推荐SQLDelight Native SQLite 类型系统详解默认类型映射、ColumnAdapter 与自定义列类型实战SQLDelight Native SQLite 类型系统详解默认类型映射、ColumnAdapter 与自定义列类型实战 本文面向使用 SQLDelight后端ORMSQLDelight 类型系统完全指南SQLite 内置类型、Primitive 适配器、自定义列类型与 Value Type 实战SQLDelight 类型系统完全指南SQLite 内置类型、Primitive 适配器、自定义列类型与 Value Type 实战 SQLDelight 的后端ORMSQLDelight 自定义列类型完全指南ColumnAdapter、枚举映射与 Value Types 深入解析SQLDelight 自定义列类型完全指南ColumnAdapter、枚举映射与 Value Types 深入解析 导读 SQLDelight 通过 AS 语后端ORM上一篇探索 Sketch Measure设计师的测量利器下一篇自主托管指南: 掌握你的数字主权创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考