SQLDelight 自定义投影(Custom Projections)实战:Typesafe Mapper 与 SQL 侧投影的正确用法
后端ORM【免费下载链接】sqldelightSQLDelight - Generates typesafe Kotlin APIs from SQL项目地址https://gitcode.com/gh_mirrors/sq/sqldelight点击查看免费下载本指南围绕 SQLDelight 官方文档 docs/common/custom_projections.md 展开讲解查询结果投影的两条路径默认的数据类投影、以及通过 typesafe mapper 覆盖默认行为并对比在 SQL 中完成投影这一更优实践。读完你将掌握 mapper 参数的具体签名、生成代码的底层原理以及如何在真实项目中把两者组合起来写出类型安全且高效的查询。默认行为每个查询都会生成一个数据类在 SQLDelight 中你在.sq文件里声明的每一个命名查询默认都会返回一个由编译器生成的数据类字段对应你 SELECT 的投影列。以文档中的hockeyPlayer表为例hockeyPlayer: CREATE TABLE hockeyPlayer ( player_number INTEGER NOT NULL, full_name TEXT NOT NULL ); selectAll: SELECT * FROM hockeyPlayer;编译后生成的查询函数形如fun selectAll(): QueryHockeyPlayer其中HockeyPlayer就是编译器依据表结构生成的数据类QueryT则是运行时提供的可监听、带类型的查询封装见 runtime/src/commonMain/kotlin/app/cash/sqldelight/Query.kt。这一默认行为在编译器里有明确的实现路径SelectQueryGenerator.defaultResultTypeFunction()会生成一个把查询参数直接转发给数据类构造器引用的函数编译器测试断言它生成的代码等价于public fun selectForId(id: Long): QueryData_ selectForId(id, ::Data_)见 sqldelight-compiler/src/test/kotlin/app/cash/sqldelight/core/queries/SelectQueryFunctionTest.kt#L23-L51也就是说默认投影 SELECT 的列 直接对应数据类的属性一一映射零额外代码。用 Typesafe Mapper 覆盖默认投影当你不想要整张数据类只想取出投影中的一部分列、或把它们组合成自定义类型时SQLDelight 允许给查询函数传入一个typesafe mapper类型安全映射器完全接管一行结果 → 一个对象的转换。文档中的原始示例val selectAllNames playerQueries.selectAll( mapper { player_number, full_name - full_name.toUppercase() } ) println(selectAllNames.executeAsList()) // Prints [RYAN GETZLAF, COREY PERRY]这里有几个关键点值得展开1. Mapper 的参数就是投影列的 Kotlin 类型。编译器根据SELECT的每一列推导出对应参数的类型——player_number是Long、full_name是String参数顺序与投影列顺序完全一致。若某列声明了自定义类型适配器如INTEGER AS LocalDateTimemapper 中该参数会直接以适配后的类型出现你无需关心底层解码细节。2. 生成的是泛型函数。从源码看SelectQueryGenerator.customResultTypeFunctionInterface()会为查询函数添加类型变量T并把 mapper 声明为从各投影列到T的 Lambda返回值变为QueryT见 sqldelight-compiler/src/main/kotlin/app/cash/sqldelight/core/compiler/SelectQueryGenerator.kt#L86-L127。对应生成的代码签名形如public fun T : Any selectAll( mapper: (player_number: Long, full_name: String) - T ): QueryT编译器测试中可找到完全一致的生成结果例如selectForId生成public fun T : kotlin.Any selectForId(id: kotlin.Long, mapper: (id: kotlin.Long, value_: kotlin.String) - T): app.cash.sqldelight.QueryT见 SelectQueryFunctionTest.kt#L151。3. 运行时逐行调用 mapper。生成的QueryT内部持有这个 mapper执行时由ExecutableQuery遍历游标并逐行调用。executeAsList()的实现就是while (cursor.next().value) result.add(mapper(cursor))见 runtime/src/commonMain/kotlin/app/cash/sqldelight/Query.kt#L174-L178。同一套 mapper 机制还支撑executeAsOne()要求恰好一行否则抛异常与executeAsOneOrNull()最多一行可为 null。4. Mapper 不只是改个类型。它是在 Kotlin 侧对每一行执行的任意函数因此可以组合列、丢弃不需要的数据、直接构造你的领域对象。例如把两列拼成你自己的值对象data class PlayerName(val number: Long, val name: String) val names playerQueries.selectAll( mapper { player_number, full_name - PlayerName(player_number, full_name) } ).executeAsList()优先在 SQL 中完成投影文档给出了一个重要原则In general you should be leveraging SQL to do custom projections whenever possible.一般来说只要可能就应该借助 SQL 完成自定义投影。文档的示例selectNames: SELECT upper(full_name) FROM hockeyPlayer;val selectAllNames playerQueries.selectNames() println(selectAllNames.executeAsList()) // Prints [RYAN GETZLAF, COREY PERRY]同样是拿到大写化后的名字列表但这次转换完全由数据库在查询阶段完成Kotlin 侧连 mapper 都不需要写。这样做的好处是实质性的计算下推upper、lower、abs、concat等标量函数在数据库引擎内执行客户端只拿到最终结果避免了全量取回 逐行转换的双重开销传输更少数据投影列越少游标需要解码的数据越少这对网络驱动的 JDBC/R2DBC 与 Web 场景尤其有意义代码更简洁无需 mapper、无需定义中间类型生成的查询函数直接返回标量类型。一个值得注意的编译期行为是当查询只有单列投影时SQLDelight 会直接让查询返回该列的 Kotlin 类型根本不会生成带 mapper 的泛型函数。从源码看这是customResultTypeFunctionInterface()中needsWrapper()为 false 的分支No custom type possible, just returns the single column:fun selectSomeText(_id): QueryString见 SelectQueryGenerator.kt#L120-L124。测试同样验证了这一点例如SELECT NULL会生成fun T : Any selectData(mapper: (expr: kotlin.Nothing?) - T): ExecutableQueryT的泛型版本见 SelectQueryFunctionTest.kt#L489。需要留意的是能下推到 SQL 的函数集取决于你所用的方言SQLite、MySQL、PostgreSQL、H2、HSQL 各自支持的标量函数与语法并不相同仓库中各方言模块如 dialects/sqlite、dialects/postgresql即是对应语法解析与代码生成的支持单元。因此在 SQL 中投影要以你目标数据库的方言能力为边界。两种方式怎么选对照与决策维度客户端 Typesafe MapperSQL 侧投影转换执行位置Kotlin 侧逐行调用 Lambda数据库引擎内完成数据量先取回全部投影列再转换只回传需要的结果生成签名fun T select(... , mapper: (cols) - T): QueryT单列直接返回标量多列返回数据类适用场景组合多列构造领域对象、复用既有类型、需要适配器解码后的类型单列标量变换大小写、数值、拼接、聚合结果、过滤后裁剪类型安全参数类型由编译器按列推导返回类型同样由编译器推导代码量需要写 mapper Lambda只需写 SQL决策建议很简单能下推给 SQL 的单列变换、聚合、裁剪优先写在.sq文件里需要把多列组装成自定义对象、或依赖 Kotlin 类型系统做进一步加工的再用 mapper。两者并不互斥——同一个.sq文件里可以同时存在SQL 投影版和默认数据类版两个查询各取所需。实战在 sample 项目中落地仓库自带的示例工程把这两种用法都用上了。在 sample/common/src/iosMain/kotlin/com/example/sqldelight/hockey/ui/PlayerData.kt 中面向 Swift 的桥接对象直接消费生成的查询fun players(teamId: Long) Db.instance.playerQueries.forTeam(teamId).executeAsList()这里forTeam返回数据类列表靠的是默认投影。而在 Android 端 sample/android/src/main/java/com/example/sqldelight/hockey/ui/PlayersActivity.kt#L22同样的查询结果被直接喂给 RecyclerView 适配器players.adapter PlayersAdapter(db.forTeam(intent.getLongExtra(TEAM_ID, -1)).executeAsList())若你想在真实工程里体验 mapper可以在hockeyPlayer.sq中追加一个只取名字的查询并配合 Kotlin 侧组合selectPlayerNames: SELECT player_number, full_name FROM hockeyPlayer;data class PlayerName(val number: Long, val name: String) val names playerQueries.selectPlayerNames( mapper { number, name - PlayerName(number, name) } ).executeAsList()小结SQLDelight 的投影体系遵循默认数据类 → 可选 typesafe mapper → 优先 SQL 投影三层设计默认行为零成本mapper 在需要自定义对象组装时提供完全类型安全的覆盖手段其签名由编译器按投影列逐一推导而凡是能在数据库内完成的变换都应优先写进.sq文件的 SELECT 子句里。理解 SelectQueryGenerator.kt 的生成逻辑与 Query.kt 的运行时执行路径你就能准确预判每个查询会生成怎样的函数签名从而写出既类型安全又高效的查询代码。赞分享后端ORM【免费下载链接】sqldelightSQLDelight - Generates typesafe Kotlin APIs from SQL项目地址https://gitcode.com/gh_mirrors/sq/sqldelight点击查看免费下载相关推荐SQLDelight 自定义投影Custom Projections实战类型安全 Mapper 与 SQL 投影的取舍SQLDelight 自定义投影Custom Projections实战类型安全 Mapper 与 SQL 投影的取舍 本文基于 SQLDelight 官后端ORMSQLDelight 自定义投影Type Projections实战指南从类型安全 Mapper 到纯 SQL 投影SQLDelight 自定义投影Type Projections实战指南从类型安全 Mapper 到纯 SQL 投影 SQLDelight 会根据 .sq后端ORMSQLDelight 类型投影Type Projections与自定义 Mapper 实战指南SQLDelight 类型投影Type Projections与自定义 Mapper 实战指南 SQLDelight 默认会把每条 SELECT 查询的结果后端ORM上一篇Apache Arrow 内嵌 double-conversion 依赖解析版本溯源、更新流程与浮点转换应用下一篇Genkit Dart Google GenAI 插件实战用 Gemini API 完成文本生成、Embedding、图像生成与 TTS创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

看懂人群,然后远离人群:普通人逆袭的路径

看懂人群,然后远离人群:普通人逆袭的路径

看懂人群,然后远离人群:普通人逆袭的唯一路径 你有没有发现一个诡异的现象—— 从小到大,所有人都在告诉你"合群"的重要性。 上学时,老师说:别标新立异,跟大家保持一致。 找工作时,父…

2026/10/9 13:04:34 阅读更多 →
一次真实压测,先证明“我量到的是被测系统“:四个角色、八个坑,和逐层找墙

一次真实压测,先证明“我量到的是被测系统“:四个角色、八个坑,和逐层找墙

一次真实压测,先证明"我量到的是被测系统":四个角色、八个坑,和逐层找墙主题:压测结论的可信性(干扰项证伪 工具自证 逐层找墙)先说结论 给一个微服务电商项目里的 AI 导购流式接口&#xff08…

2026/10/11 3:38:05 阅读更多 →
Codeface 编程等宽字体画廊:一站式检索、下载与定制开源开发字体

Codeface 编程等宽字体画廊:一站式检索、下载与定制开源开发字体

数据集 【免费下载链接】codeface Typefaces for source code beautification 项目地址: https://gitcode.com/gh_mirrors/co/codeface 点击查看 免费下载 Codeface 是一个面向开发者的等宽(monospaced)编程字体画廊与字体仓库,核…

2026/10/9 14:47:48 阅读更多 →

最新新闻

DNA到蛋白质的完整路径:转录、翻译与中心法则的分子实战

DNA到蛋白质的完整路径:转录、翻译与中心法则的分子实战

DNA怎么变成蛋白质?这个问题的完整答案,比课本上那张中心法则的箭头要丰富得多。我当年第一次给学生讲清楚转录和翻译的全程时,最深的感受是:知识链条其实不长,但每一环都有大量“看似理所当然、实则经不起追问”的细节…

2026/10/14 3:40:38 阅读更多 →
基于CNN的水下声源定位实战:从数据到部署全流程

基于CNN的水下声源定位实战:从数据到部署全流程

简介:一套基于PyTorch的海洋水下声源定位实战项目,使用卷积神经网络(CNN)对水下声学信号进行建模,预测声源方位角与距离,完整覆盖从声学数据到位置估计的流程。资源面向水声工程、人工智能、电子信息、自动…

2026/10/14 3:40:38 阅读更多 →
Falcom经典游戏源码构建与调试实战指南

Falcom经典游戏源码构建与调试实战指南

简介:本资源为Falcom十大经典游戏系列的项目源码整理包,面向游戏开发初学者、JRPG爱好者及逆向分析兴趣者,提供一份轻量级参考素材,辅助理解经典日式RPG的设计脉络与基础架构逻辑。压缩包共3个文件,含1个HTML页面&…

2026/10/14 3:40:38 阅读更多 →
秋叶SD整合包V5.0代码版:从改代码到批量出图API实战

秋叶SD整合包V5.0代码版:从改代码到批量出图API实战

简介:秋叶SD整合包V5.0面向希望快速上手Stable Diffusion的Windows新手用户,解决环境配置繁琐、参数调节门槛高的问题。资源包共3个文件,以inscode工程配置、html页面与gitignore忽略规则为主,压缩包仅6KB,属于轻量级代…

2026/10/14 3:40:38 阅读更多 →
三站时差定位球面模型实战:从时差解算到经纬度

三站时差定位球面模型实战:从时差解算到经纬度

简介:这份资源围绕三站时差定位(TDOA)展开,面向无线通信、雷达定位与物联网设备追踪方向的学习者和开发者,重点解决无GPS覆盖环境下利用信号到达时间差解算信号源位置的问题。内容涉及Chan提出的球面TDOA实现思路&…

2026/10/14 3:40:38 阅读更多 →
一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

简介:面向 YOLOv11 模型验证需求,这份精简版鸟类目标检测数据集包含一张真实野外鸟类图像及配套标准标注,可用于快速原型验证、轻量级部署测试与小样本检测基线建立。压缩包共五个文件,包含三张 JPG 图像、一个数据配置文件与一个…

2026/10/14 3:39:38 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →