
Metabase Embedding SDK 的 SqlParameterChangePayload 详解SQL 参数变更事件的结构、来源与受控同步机制【免费下载链接】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/metabaseSqlParameterChangePayload是 Metabase Embedding SDK 中传递给onSqlParametersChange回调的载荷对象用于把嵌入页面内 SQL 问题Native Question的参数状态实时反馈给宿主应用。本文以该类型的完整定义为骨架逐一剖析parameters、defaultParameters、source三个字段的含义并结合仓库源码受控 hook、载荷构建函数、单元测试说明initial-state、manual-change、auto-change三种事件来源的判定逻辑以及如何与sqlParameters受控属性配合实现宿主与嵌入组件之间的双向同步。类型定义一览该类型的正式定义位于 SDK 文档的 SqlParameterChangePayload.md完整内容如下type SqlParameterChangePayload { defaultParameters: ParameterValues; parameters: ParameterValues; source: SqlParameterChangeSource; };它是传给onSqlParametersChange回调的载荷Payload在 Metabase Embedding SDK 中凡是通过 SQL原生查询创建的嵌入式问题组件——例如InteractiveQuestion和StaticQuestion——在 SQL 参数发生变化时都会携带该对象触发回调。在仓库源码中该类型被定义并归类在 InteractiveQuestion 类别下见 frontend/src/embedding-sdk-bundle/types/question.ts/** * Payload passed to onSqlParametersChange callback * * category InteractiveQuestion */ export type SqlParameterChangePayload { source: SqlParameterChangeSource; parameters: ParameterValues; defaultParameters: ParameterValues; };属性一览根据官方 API 文档的属性表该类型包含三个属性PropertyType说明defaultParametersParameterValues当前问题所有 SQL 参数的默认值集合按 slug 键控parametersParameterValues当前实际生效的参数值集合按 slug 键控sourceSqlParameterChangeSource本次变更的来源类型区分初始化、用户手动修改与自动更新三个字段在源码中的定义顺序与文档属性表一致源码中source居首、文档表中defaultParameters居首字段含义完全对应。字段详解一parameters与defaultParametersparameters与defaultParameters都是ParameterValues类型其定义为type ParameterValues Record string, | string | number | boolean | (string | number | boolean | null)[] | null | undefined ;也就是说它是一个键为参数 slug如product_id、值为标量或数组的映射对象。值得注意的是SQL 参数载荷中的键是slug变量名而非参数的内部 ID——这与onParametersChange仪表板参数的载荷设计保持一致便于宿主应用直接以 SQL 中的模板变量名读写。从源码实现看这两个字段由buildParametersPayload函数构建见 frontend/src/embedding-sdk-bundle/lib/controlled-parameters.tsexport function buildParametersPayload( applied: ParameterValuesMap, parameterDefinitions: UiParameter[], ): { parameters: ParameterValues; defaultParameters: ParameterValues } { return { parameters: getParameterValuesBySlug(parameterDefinitions, applied), defaultParameters: getParameterValuesBySlug( getDefaultValuePopulatedParameters(parameterDefinitions, {}), {}, ), }; }其行为可以归纳为parameters取自当前已应用的参数值applied通过getParameterValuesBySlug按参数定义转换为 slug 键控的对象反映此刻组件内 SQL 参数的真实状态。defaultParameters通过getDefaultValuePopulatedParameters(parameterDefinitions, {})先把参数定义中的默认值填充出来再转为 slug 键控对象。它代表如果宿主不提供任何值组件会使用什么。对于 SQL 问题场景buildParametersPayload的签名只返回parameters与defaultParameters两个字段不包含仪表板参数载荷中的lastUsedParameters最近使用值。这一点在单元测试中有明确断言Question payload spec omitslastUsedParametersentirely。字段详解二source与三种事件来源source的类型是SqlParameterChangeSource完整定义如下type SqlParameterChangeSource | initial-state | manual-change | auto-change;三种取值代表 SQL 参数变更事件的三种来源取值语义触发时机initial-state首次应用的初始状态每个问题question加载时触发一次manual-change用户在 UI 中手动编辑用户通过参数控件修改了 SQL 参数auto-change自动更新例如宿主传入的受控值被组件规范化后再回传给父级在仓库源码 frontend/src/embedding-sdk-bundle/types/question.ts 中有完全一致的定义与注释/** * Source of a sql-parameter-change event: * - initial-state - first applied state, fired once per question load. * - manual-change - user edited parameters in UI. * - auto-change - in the case of auto-updates, e.g. to pass normalized values back to parent. * * category InteractiveQuestion */ export type SqlParameterChangeSource | initial-state | manual-change | auto-change;其中auto-change的典型场景是宿主传入标量值如{ state: NY }组件内部将其规范化成数组形态如{ state: [NY] }再通过载荷回传此时载荷值与宿主原始输入在形状上不一致因此被标记为自动更新而非用户手动修改。使用场景onSqlParametersChange回调SqlParameterChangePayload的唯一出口是onSqlParametersChange回调。在InteractiveQuestion、StaticQuestion等 SDK 组件的属性文档中它的签名被描述为onSqlParametersChange?: (payload: SqlParameterChangePayload) void— Fires on SQL parameters change. The payloadssourcedistinguishes the initial state on load (initial-state), user edits in the UI (manual-change), and auto-updates (auto-change).相关属性文档见InteractiveQuestionProps.mdStaticQuestionProps.md在运行时组件的 props 校验 schema 会显式放行sqlParameters、initialSqlParameters与onSqlParametersChange三个属性见 InteractiveQuestion.schema.tsinitialSqlParameters: Yup.mixed().optional(), sqlParameters: Yup.mixed().optional(), onSqlParametersChange: Yup.mixed().optional(),受控模式sqlParametersonSqlParametersChange要理解SqlParameterChangePayload的完整价值需要把它放到受控controlled参数模式下看待initialSqlParameters非受控仅在挂载时应用一次用户后续在 UI 中的编辑不会回写到宿主sqlParameters受控每次渲染时都会用该对象整体替换问题的参数值宿主需要配合onSqlParametersChange监听变更并把新值写回自己的状态形成闭环。sqlParameters属性文档中的取值约定为参数设置为某个值 → 使用该值参数设置为null→ 严格清除即使它定义了默认值参数被省略或为undefined→ 回退到该参数的默认值无默认值则为null。源码级原理source是如何判定的SqlParameterChangePayload的生成与分发由私有 hookuseSdkControlledSqlParameters完成源码见 frontend/src/embedding-sdk-bundle/hooks/private/use-sdk-controlled-sql-parameters.ts。该 hook 专为 SQL 问题接线受控sqlParameters属性与onSqlParametersChange回调内部拆分为两个方向push hook宿主 → 查询状态usePushControlledSqlParameters监听宿主传入的sqlParameters在其变化且与当前已应用值不同时通过buildControlledParameters把 slug 键控值转换为内部按参数 ID 键控的值并派发若解析结果与已应用值一致则跳过派发避免冗余更新。observe hook状态 → 宿主useObserveAppliedSqlParameters观察已应用的 SQL 参数值按以下规则选定source并触发onSqlParametersChangeconst questionId question.id?.() ?? null; const isLoadEvent emittedQuestionIdRef.current ! questionId; if (isLoadEvent) { callbackRef.current?.({ source: initial-state, ...payload }); return; } const lastSqlParametersPush lastSqlParametersPushRef.current; lastSqlParametersPushRef.current null; if (lastSqlParametersPush ! null) { if (!isEqual(payload.parameters, lastSqlParametersPush)) { callbackRef.current?.({ source: auto-change, ...payload }); } return; } callbackRef.current?.({ source: manual-change, ...payload });判定逻辑可以概括为通过emittedQuestionIdRef记录已触发过初始事件的 question id。当 question id 变化如导航到新问题时判定为initial-state同一问题重复渲染不会重复触发初始事件。通过emittedValuesRef对已应用值做深度相等isEqual比较值未变化的渲染不重复触发回调。当宿主 push 的值到达组件并被应用后如果最终载荷中的parameters与宿主原始输入不同例如标量被规范化为数组则标记为auto-change用于把规范化后的值回传给宿主。其余由用户在 UI 控件上的修改统一标记为manual-change。回调本身通过useLatest保持最新引用宿主在挂载后替换回调函数也不会丢失后续事件。与 iframe SDK 桥接的关系SqlParameterChangePayload不仅用于 React Embedding SDK 的组件回调还被 iframe 嵌入场景复用。在 frontend/src/metabase/embedding/embedding-iframe-sdk/types/embed.ts 中它作为metabase.embed.sqlParametersChange消息的载荷在 iframe 与宿主页面之间传输export type SdkIframeEmbedComponentTagMessage | { type: metabase.embed.parametersChange; data: ParameterChangePayload; } | { type: metabase.embed.sqlParametersChange; data: SqlParameterChangePayload; };对应地QuestionEmbedOptions中同样声明了initialSqlParameters与sqlParameters两个选项说明该载荷体系同时服务组件属性props与 iframe 消息postMessage两条通路。实战示例监听 SQL 参数变更以下示例展示如何在宿主应用中通过onSqlParametersChange消费SqlParameterChangePayload以InteractiveQuestion为例import { useState } from react; import { InteractiveQuestion, MetabaseProvider, } from metabase/embedding-sdk-react; import type { SqlParameterChangePayload } from metabase/embedding-sdk-react; export function SqlParameterAwareQuestion() { // 受控 SQL 参数slug 键控 const [sqlParameters, setSqlParameters] useStateRecordstring, unknown({ product_id: 42, }); const handleSqlParametersChange (payload: SqlParameterChangePayload) { const { source, parameters, defaultParameters } payload; console.log(变更来源:, source); // initial-state | manual-change | auto-change console.log(当前生效值:, parameters); console.log(默认值:, defaultParameters); if (source manual-change) { // 仅把用户真正手动修改的值写回宿主状态形成受控闭环 setSqlParameters(parameters); } // auto-change 场景宿主传入了标量组件回传规范化后的数组 // 若直接写回可能引发额外渲染通常需要按业务决定是否采纳 }; return ( MetabaseProvider authConfig{{ metabaseInstanceUrl: https://your-metabase.example, authProviderUri: https://your-app.example/sso/metabase }} InteractiveQuestion questionId{1} sqlParameters{sqlParameters} onSqlParametersChange{handleSqlParametersChange} / /MetabaseProvider ); }使用时的关键注意点区分parameters与defaultParameters前者是当前真实生效值后者是参数自身的默认配置两者结合可用于判断用户是否偏离了默认值。按需响应source同步宿主状态时通常只关心manual-changeinitial-state用于初始化宿主状态auto-change代表组件内部的规范化回传直接写回容易造成与组件自身的冗余往返。undefined/null的语义差异在sqlParameters受控值中undefined或省略表示回退默认值null表示严格清除两者行为不同见上文属性约定。单元测试佐证仓库在 use-sdk-controlled-sql-parameters.unit.spec.tsx 中为上述行为提供了完整的测试覆盖可作为验证参考source: initial-state在首次见到某 question 时触发一次且载荷不包含lastUsedParametersquestion id 变化如navigateToNewCard会再次触发initial-state已应用值发生深度变化时触发manual-change内容深度相等的新引用不重复触发宿主 push 的标量值被规范化为数组时触发auto-change如{ state: NY }→{ state: [NY] }宿主在挂载后替换回调函数后续事件仍会派发到最新回调callback ref 隔离。总结SqlParameterChangePayload是 Metabase Embedding SDK 中 SQL 参数状态通知的统一契约parameters与defaultParameters以 slug 键控的ParameterValues提供当前值与默认值source则通过initial-state、manual-change、auto-change三个枚举值准确描述事件性质。在源码层面它由useSdkControlledSqlParameters的 push/observe 双向机制驱动与sqlParameters受控属性共同构成宿主与嵌入式 SQL 问题之间的完整双向绑定并被 iframe 嵌入的metabase.embed.sqlParametersChange消息复用。理解该类型及其来源判定规则是安全地在宿主应用中实现 SQL 参数持久化、URL 同步或联动过滤的前提。【免费下载链接】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),仅供参考