Metabase Embedding SDK 的 ActionKind 联合类型详解:五种动作类型的扁平化抽象与后端映射

发布时间:2026/9/10 6:14:15
Metabase Embedding SDK 的 ActionKind 联合类型详解:五种动作类型的扁平化抽象与后端映射 Metabase Embedding SDK 的 ActionKind 联合类型详解五种动作类型的扁平化抽象与后端映射【免费下载链接】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/metabaseMetabase Embedding SDK 通过useAction钩子让宿主应用以类型安全的方式触发预置的 Metabase Action行级写操作与自定义 SQL 动作。ActionKind是这套类型体系的核心枢纽——它用一个只有五个字面量的扁平联合类型统一了后端 Action 的命名空间化分类并驱动result结果的判别式discriminated union类型推导。读完本文你将理解ActionKind的五个取值各自代表什么、它们如何与后端implicitKind/type字段一一对应、以及如何在useActionTParameters, TKind中利用它获得零类型转换的强类型响应。一、ActionKind 的类型定义与五个字面量ActionKind定义在 SDK 公开类型模块中完整定义如下见 types.ts 与对应的 API 参考文档type ActionKind create | update | delete | bulk | sql;它刻意保持扁平flat——不引入嵌套命名空间或子类型而是向调用方暴露五个简单取值字面量语义结果响应形状create单行插入{ created-row: Recordstring, RowValue }update单行更新{ rows-updated: readonly RowValue[] }delete单行删除{ rows-deleted: readonly RowValue[] }bulk任意批量变体{ success: boolean; rows-created?: number; ... }sql自定义 SQL 动作{ rows-affected: number }设计要点create/update/delete始终指单行操作bulk一词覆盖所有批量变体批量新增、批量更新、批量删除sql则指代自定义 SQL 动作——即后端type为query的动作。二、与后端动作类型的映射关系ActionKind并非凭空发明而是对后端已存在的两种分类字段的降维Metabase 后端的 Basic Action隐式动作使用命名空间化的implicitKind取值形如row/*与bulk/*自定义 SQL 动作则使用type: query。ActionKind将这十种可能六种隐式种类 查询类型压缩为五种面向调用方的取值。在 types.ts 中后端命名空间化的隐式种类被明确声明为export type ActionImplicitKind | row/create | row/update | row/delete | bulk/create | bulk/update | bulk/delete;映射关系可以总结为如下表格后端implicitKind/typeActionKind扁平化结果row/createcreaterow/updateupdaterow/deletedeletebulk/create、bulk/update、bulk/deletebulktype querysql从后端视角验证在 model.clj 中Metabase 的类型化 schema 生成逻辑通过(when implicit? (keyword-name kind))为隐式动作填充:implicitKind字段——这印证了implicitKind与type确实是后端动作模型的一等字段而 SDK 端的ActionKind只是它们面向嵌入应用的精简投影。三、源码中的映射实现ActionKindFromDataAppSchema映射逻辑在类型层面由ActionKindFromDataAppSchema实现见 types.ts。它是一个条件类型读取 Data App 生成 schema 中单个动作条目的implicitKind或type query推导出对应的ActionKind字面量export type ActionKindFromDataAppSchemaTAction TAction extends { implicitKind: row/create; } ? create : TAction extends { implicitKind: row/update } ? update : TAction extends { implicitKind: row/delete } ? delete : TAction extends { implicitKind: bulk/${string} } ? bulk : TAction extends { type: query } ? sql : ActionKind;注意bulk/${string}这一模板字面量类型——它用一条分支覆盖了bulk/create、bulk/update、bulk/delete全部三种批量变体正是bulk 覆盖任意批量变体这一语义在类型系统里的直接体现。当TAction不是 schema 条目例如调用方直接传入裸的数字 id时回退为完整的ActionKind联合类型。ActionKindFromDataAppSchema是 Data App数据应用模式下的便捷工具它通常与ActionParametersFromDataAppSchema搭配使用让作者可以写出如下零类型转换的调用useAction ActionParametersFromDataAppSchematypeof action, ActionKindFromDataAppSchematypeof action (action.id);而在原始 SDKMode-1模式下调用方不导入这些派生工具而是手动声明TParameters并将TKind作为字面量传入。四、ActionKind 如何驱动结果类型ActionResultForKindActionKind的价值在于它不仅是运行时语义标签更是类型层面的判别键。ActionResultForKindTKind见 ActionResultForKind.md根据TKind泛型参数将结果类型收窄为对应的响应形状type ActionResultForKindTKind TKind extends create ? ActionResultForCreate : TKind extends update ? ActionResultForUpdate : TKind extends delete ? ActionResultForDelete : TKind extends bulk ? ActionResultForBulk : TKind extends sql ? ActionResultForSql : AnyActionResult;各结果形状定义于 types.ts具体为ActionResultForCreate{ created-row: Recordstring, RowValue }返回被插入的行ActionResultForUpdate{ rows-updated: readonly RowValue[] }返回受影响的主键列表ActionResultForDelete{ rows-deleted: readonly RowValue[] }返回被删除的主键列表ActionResultForBulk{ success: boolean; rows-created?: number; rows-updated?: number; rows-deleted?: number }成功标志加可选计数ActionResultForSql{ rows-affected: number }返回受影响的行数。当TKind被省略即undefined时result回退为AnyActionResult——五种响应形状的联合。这样做的设计意图在 types.ts 的注释中写得很清楚对于事先不知道动作种类的作者仍然可以通过key in result进行 TypeScript 收窄而不是被迫从一个宽松的Recordstring, unknown里做不安全的类型断言。五、在 useAction 中的实战用法ActionKind最常见的消费场景是作为useAction钩子的第二个泛型参数。钩子签名如下见 useAction.md 与 use-action.tsfunction useActionTParameters, TKind( actionId: SdkActionId | null, ): UseActionResultTParameters, TKind;第一个泛型TParameters约束为Recordstring, unknown用于给execute的参数对象提供类型第二个泛型TKind约束为ActionKind | undefined用于推导判别式result形状。典型用法来自文档示例useAction{ name: string; email: string }, create(42);这里传入的动作 id 是数字42。SdkActionId的定义为number | SdkEntityId见 SdkActionId.md即既可以传动作的数字主键 id也可以传其entity_id字符串。useAction的返回值UseActionResultTParameters, TKind提供五个成员见 UseActionResult.md属性类型说明execute(parameters: TParameters) PromiseActionResultForKindTKind \| null以给定参数触发动作成功时返回响应体失败时抛出异常同一错误也会存入error供渲染期消费isExecutingboolean是否正在执行resultActionResultForKindTKind \| null最近一次响应首次调用前与reset()之后为nullerrorActionExecuteError \| null最近一次错误规范化为公开的错误形状reset() void清空result与error需要特别注意的是执行时机与查询类钩子不同useAction不会在挂载时自动运行——调用方必须从事件处理器中显式调用execute。若需条件性拦截执行应在事件处理器内分支判断例如if (!user.canEdit) return;后再调用execute。此外当actionId为null或 SDK 尚未初始化时execute会解析为null且不会发起请求因此若这些情况可达宿主侧应先用if (!actionId) return;进行守卫。错误形状ActionExecuteErroruseAction在非 2xx 响应时抛出的错误会被规范化为ActionExecuteError见 ActionExecuteError.mdtype ActionExecuteError { data: { errors?: Recordstring, string; message?: string; }; isCancelled: boolean; status?: number; };消费时无需类型断言直接读取字段即可const message error?.data?.message;字段语义error.data.message是面向最终用户的可操作诊断信息error.data.errors是当后端报告参数级校验失败时的按字段映射{ slug: message }对于整请求失败例如外键约束{ message: Other rows refer to this row…, errors: {} }则为空对象status在传输层失败离线、请求被中止时因未收到 HTTP 响应而缺席。六、最佳实践小结能确定种类就传TKind若动作种类在开发期已知务必把create/update/delete/bulk/sql之一作为第二泛型传入让result获得精确的判别式类型不确定时才省略用key in result收窄。Data App 模式优先用派生工具ActionKindFromDataAppSchema与ActionParametersFromDataAppSchema会从生成的metabase.data.tsschema 自动推导TKind与TParameters实现编译期参数检查与类型化结果且无需任何类型断言。牢记批量语义bulk是bulk/*六种后端隐式种类的统称其响应以success标志为主、可选计数为辅而单行操作的结果都以具体的行/主键数据为主体。错误处理走规范形状始终通过error?.data?.message读取诊断信息并根据status是否存在区分 HTTP 层失败与传输层失败。ActionKind虽是一个只有五行的类型定义却是整个 Metabase Embedding SDK 动作体系前后端动作分类对齐 类型安全结果推导的支点。理解它的映射关系你就掌握了useAction强类型能力的全部脉络。【免费下载链接】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创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考