数据分析数据可视化后端数据库客户端企业应用【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址https://gitcode.com/GitHub_Trending/me/metabase点击查看免费下载RowValue是 Metabase 模块化嵌入 SDKEmbedding SDK中定义的一个 TypeScript 类型别名它统一描述了嵌入应用中可能从 Metabase 拿到的单个单元格值——无论是查询返回的数据行还是执行写回Action后返回的主键、行数或新建记录。本文以 SDK API 文档中的 RowValue 类型定义 为主体结合仓库中metabase-types、embedding-sdk-bundle等模块的源码与单元测试梳理该类型的确切值域、在查询与动作两条数据通道中的实际用法以及类型收窄的编码实践帮助你在接入 SDK 时正确读写这些值。类型定义一个五值联合在 SDK API 文档中RowValue的定义原文如下type RowValue string | number | null | boolean | object;文档给出的语义说明是A single value returned by Metabase query results or action responses.即由 Metabase 查询结果或动作响应返回的单个值。这个定义并非 SDK 文档的孤例而是直接继承自仓库前端公共类型层。在 frontend/src/metabase-types/api/dataset.ts#L26-L27 中可以找到同构的底层声明/** * inline */ export type RowValue string | number | null | boolean | object; export type RowValues RowValue[];注意两个细节类型定义上标注了inline表示它在生成 API 文档时会内联展开这正是 snippets/RowValue.md 中那份简短定义的来源紧邻其后的RowValuesRowValue[]才是数据行层面的类型——一行数据Row就是一个RowValue数组每个单元格对应一个RowValue。值域边界为什么是这五种从数据仓库到前端展示Metabase 查询结果中的单元格最终会被归一化成以下五种 JavaScript 形态类型典型来源string文本列、日期时间的 ISO 8601 字符串、JSON 序列化后的对象number数值列、聚合结果sum、avg、count等boolean布尔列nullSQL 中的NULL值数据库空值被归一化为 JS 的nullobject被解析为对象的值例如 H2/PostgreSQL 的 JSON 列、数组类型等复合值其中object是一个开放类型意味着 SDK 并不对复合值做更细粒度的约束与之对照动作参数侧前端提交给动作的参数则被定义为更窄的ParametersForActionExecution见 frontend/src/metabase-types/api/actions.ts#L96-L98export type ParametersForActionExecution { [id: ParameterId]: string | number | boolean | null; };即查询结果侧允许object动作参数侧不允许object。这符合直觉——数据库可以返回 JSON 等复合值但动作表单通常只接受标量输入。查询结果通道RowValue 如何组成行与列RowValue在 SDK 中最主要的使用场景是查询结果。SDK 对外暴露的查询结果类型QueryDataTRow与QueryQuestionResult都以它为基础。QueryData带泛型的查询结果QueryData 类型定义 把原始行rawRows与泛型化后的行rows分开暴露type QueryDataTRow { columns: DatasetColumn[]; description?: QueryQuestionResult[description]; entityId?: QueryQuestionResult[entityId] | null; id?: QueryQuestionResult[id] | null; name?: QueryQuestionResult[name] | null; rawRows: RowValues[]; rowCount: number | null; rows: TRow[]; runningTime: number | null; };其中rawRows的类型是RowValues[]即RowValue[][]——未做类型映射的原始单元格矩阵rows是TRow[]由调用方通过泛型把原始行映射为带字段名的对象例如{ id: number; name: string }此时每个字段值仍然落在RowValue的值域内columns是DatasetColumn[]DatasetColumn与RowValues在文档中标注为Not Exported即它们是内部类型不对外导出。QueryQuestionResult问题的查询结果QueryQuestionResult 类型定义 是QueryData的单问题查询形态其rows字段直接是RowValues[]type QueryQuestionResult { columns: DatasetColumn[]; description: MetabaseQuestion[description]; entityId: MetabaseQuestion[entityId]; id: MetabaseQuestion[id]; name: MetabaseQuestion[name]; rowCount: number | null; rows: RowValues[]; runningTime: number | null; };源码侧查询结果如何落到 RowValue在 SDK 的底层实现中RowValue贯穿了从 HTTP 响应到公共 API 的映射。以 frontend/src/embedding-sdk-bundle/lib/query-question.ts#L21-L30 为例其导出类型与QueryQuestionResult一致export type QueryQuestionResult { id: MetabaseQuestion[id]; name: MetabaseQuestion[name]; description: MetabaseQuestion[description]; entityId: MetabaseQuestion[entityId]; rowCount: number | null; runningTime: number | null; columns: DatasetColumn[]; rows: RowValues[]; };实现上queryQuestion通过 dispatchloadQuestionSdk与runQuestionQuerySdk获取查询结果再取rawSeries[0].data.rows作为rows返回rows的元素正是后端/api/dataset响应体中data.rows的单元格值天然符合RowValue联合。同理frontend/src/embedding-sdk-bundle/lib/query-dataset.ts#L13-L18 中的QueryDatasetResult也把rows定义为RowValues[]并通过response.data?.rows ?? []兜底为空数组。由此可以确认一条事实链Metabase 后端数据接口返回的单元格值在 SDK 公共 API 层统一以RowValue联合类型呈现RowValues[]即一张二维表。这对消费查询结果的应用来说意味着读取任意单元格前都需要考虑它可能是string、number、boolean、null或object中的任意一种。动作响应通道RowValue 在主键与记录中的角色RowValue的第二个核心场景是动作Action响应。在 SDK 中通过useAction钩子触发动作后返回的result形状由动作类型kind决定而这些形状里凡是涉及数据值的位置都使用RowValue。在 docs/embedding/sdk/actions.md#L81-L87 的结果形状对照表中可以看到Action kind覆盖范围result形状create单行插入基础动作{ created-row: Recordstring, RowValue }update单行更新{ rows-updated: readonly RowValue[] }delete单行删除{ rows-deleted: readonly RowValue[] }bulk任意批量变体{ success: boolean; rows-created?: number; rows-updated?: number; rows-deleted?: number }sql自定义 SQL 动作{ rows-affected: number }对应到 SDK API 文档中的三个单行动作类型ActionResultForCreate{ created-row: Recordstring, RowValue }其中created-row是Recordstring, RowValue表示被插入的那一行——字段名映射到RowValueActionResultForUpdate{ rows-updated: readonly RowValue[] }即受影响行的主键值列表ActionResultForDelete{ rows-deleted: readonly RowValue[] }即被删除行的主键值列表。可以看到RowValue在这三处扮演了两种语义在create中它是记录字段的值在update/delete中它是主键值通常是number但可能是复合主键或字符串键。源码侧动作执行如何产出这些值SDK 的动作执行入口在 frontend/src/embedding-sdk-bundle/lib/execute-action.ts#L24-L32其注释直接点明了响应体按动作类型分化的结构/** * Loose response shape from the execute-action endpoint. The body varies * by action kind (created-row / rows-updated / rows-deleted / rows-affected * successcounts). Per-kind discrimination happens in the package hook via the * generated ActionResultTAction type — this lib stays loose. */ export type ExecuteActionResult Recordstring, unknown;底层通过 dispatch RTK Query 的executeActionMutation向POST /api/action/:id/execute发起请求参数包原样透传、由服务端校验。HTTP 类型的动作在服务端被拒绝不会走到这条代码路径。execute-action 的单元测试 印证了真实响应体的形态it(POSTs to /api/action/:id/execute with the given parameters, async () { fetchMock.post(path:/api/action/${NUMERIC_ID}/execute, { status: 200, body: { rows-affected: 7 }, }); const result await executeAction(setup())({ actionId: NUMERIC_ID, parameters: { id: 1, name: European }, }); expect(result).toEqual({ rows-affected: 7 }); ... });同文件中还有{ created-row: { id: 1 } }的断言说明created-row的对象值同样落在Recordstring, RowValue语义内。实战对 RowValue 做类型收窄由于RowValue是联合类型消费端代码必须对具体的值做类型收窄后才能安全使用。SDK 官方示例 docs/embedding/sdk/snippets/actions/typed-response.tsx#L36-L57 给出了一个完整的收窄模式——在不传TKind泛型时result退化为所有可能响应体的联合AnyActionResult此时用in运算符按响应键区分const { execute, result } useActionSetDiscountParameters( SET_DISCOUNT_ACTION_ID, ); const onClick async () { await execute({ id: orderId, discount: 0.1 }); }; let summary Apply discount; if (result rows-affected in result) { // result[rows-affected] is typed number here summary ${result[rows-affected]} rows affected; } else if (result created-row in result) { // result[created-row] is typed Recordstring, RowValue here summary Row created; }注意其中的关键点当收窄到created-row分支后result[created-row]的类型被推导为Recordstring, RowValue此时若想读取某个字段仍需对该字段值一个RowValue做进一步判断例如const created result[created-row]; const id created.id; // 类型为 RowValue if (typeof id number) { // 此时 id 才是安全的 number }这个约束同样适用于从QueryData/QueryQuestionResult的rows中取单元格值。如果你的数据列类型已知例如columns元数据给出了base_type可以据此缩小RowValue的实际取值分支如果列类型未知则必须按string | number | boolean | null | object全量处理。收窄时的边界注意null分支不可省略SQL 空值在结果里是null而不是undefined做非空判断时建议显式! null日期值是字符串SDK 约定日期时间以 ISO 8601 字符串传递见 actions.md 的日期与时区说明因此对日期列不要期望Date对象object是兜底遇到 JSON 列等复合值时不要假设其内部结构读取前应先做运行时校验例如isObject之类的守卫。与 SDK API 文档体系的关系RowValue属于 SDK API 参考文档中类型别名的一部分在 API 索引 中与QueryData、QueryQuestionResult、ActionResultForCreate等条目并列索引中RowValue的描述正是 A single value returned by Metabase query results or action responses.。它的 HTML 渲染页面位于 docs/embedding/sdk/api/RowValue.html由 Typedoc 从源码注释生成。从源码到文档的完整对应关系可以概括为层次位置内容类型根frontend/src/metabase-types/api/dataset.tsRowValue/RowValues原始定义查询通道frontend/src/embedding-sdk-bundle/lib/query-question.ts、query-dataset.ts查询结果rows: RowValues[]的落地动作通道frontend/src/embedding-sdk-bundle/lib/execute-action.ts动作响应体的松类型承载文档snippets/RowValue.md对外 API 参考小结RowValue虽然只是一个五值联合的类型别名但它是 Metabase Embedding SDK 中查询与动作两条数据通道共同的单元格值契约查询结果侧通过RowValues[]构成二维表动作响应侧通过Recordstring, RowValue或RowValue[]承载记录与主键。理解它的值域边界尤其null与object分支并掌握in运算符配合类型收窄的写法是安全消费 SDK 数据、避免运行时错误的基本功。上述类型定义、实现与测试均可在当前仓库中逐一溯源可作为你阅读 SDK 源码时的索引起点。赞分享数据分析数据可视化后端数据库客户端企业应用【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址https://gitcode.com/GitHub_Trending/me/metabase点击查看免费下载相关推荐Metabase Embedding SDK 中的 AnyActionResultAction 结果联合类型与 TS 类型收窄实战Metabase Embedding SDK 中的 AnyActionResultAction 结果联合类型与 TS 类型收窄实战 导读 在 Metabase数据分析数据可视化后端数据库客户端企业应用Metabase Embedding SDK 的 ActionKind 联合类型详解五种动作类型的扁平化抽象与后端映射Metabase Embedding SDK 的 ActionKind 联合类型详解五种动作类型的扁平化抽象与后端映射 Metabase Embedding数据分析数据可视化后端数据库客户端企业应用Metabase Embedding SDK 的 ActionResultForDelete单行删除动作响应类型深度解析Metabase Embedding SDK 的 ActionResultForDelete 单行删除动作响应类型深度解析 ActionResultForDe数据分析数据可视化后端数据库客户端企业应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?