Skip to content

QM 定义参考 ​

本文面向需要编写或审查 Foggy Query Model(QM)的开发者,按定义对象和属性组织当前公开查询模型契约。TM 定义请参考 TM 定义参考,运行时查询语法请参考 JSON Query DSL 语法参考。

QM 是面向 LLM、应用和工具协议的查询契约。它基于一个或多个 TM,选择对外暴露的字段,定义计算字段、默认排序和治理规则。DSL 查询只能引用当前 QM 暴露的语义字段,而不是任意 TM 字段或数据库物理列。

1. QM 文件结构 ​

QM 文件导出 queryModel 对象。

javascript
const fs = loadTableModel('FactSalesModel');

export const queryModel = {
    name: 'SalesAnalysisQueryModel',
    caption: '销售分析',
    model: fs,

    columnGroups: [],
    orders: [],
    accesses: []
};

1.1 queryModel 顶层属性 ​

属性类型必填默认值说明
namestring是无QM 唯一标识
captionstring否无显示名称
descriptionstring否无查询模型语义描述
modelobject是无关联的主 TM,通常为 loadTableModel 返回值
joinsarray否无多模型 QM 的显式关联定义
loaderstring否v1加载器版本;未配置或配置为 v1 时使用原有加载逻辑,v2 支持 TableModelProxy 和 ColumnRef
dataSourceobject否无宿主注入的数据源对象;公开模型通常使用 TM 的 dataSourceName
columnGroupsarray否无查询字段分组
ordersarray否无默认排序
accessesarray否无行级权限或查询增强规则
memberPermissionsarray否无覆盖 TM 维度成员权限
aiobject否无查询模型级 AI 元数据配置
deprecatedboolean否false是否废弃
extDataobject否无自定义扩展元数据

2. 模型绑定 ​

2.1 单模型绑定 ​

javascript
const fo = loadTableModel('FactOrderModel');

export const queryModel = {
    name: 'FactOrderQueryModel',
    model: fo,
    columnGroups: []
};

2.2 多模型绑定 ​

javascript
const fo = loadTableModel('FactOrderModel');
const fp = loadTableModel('FactPaymentModel');

export const queryModel = {
    name: 'OrderPaymentQueryModel',
    model: fo,
    joins: [
        fo.leftJoin(fp).on(fo.orderId, fp.orderId)
    ],
    columnGroups: []
};
属性类型必填说明
modelobject是主 TM 的 loadTableModel 返回值
joinsarray否由 leftJoin / innerJoin / rightJoin 等构造的关联定义
onfunction是指定关联字段,可链式追加 .and(...)

joins 是当前推荐的多模型 QM 写法。onBuilder 仍可作为 TM dimension 的高级自定义关联条件使用,但不建议作为新 QM 多模型绑定的主要示例。

3. 列组与列项 ​

columnGroups 决定 QM 对外暴露的查询字段。只有进入 columnGroups.items 并通过治理规则的字段,才应被视为 DSL 可引用字段。

javascript
columnGroups: [
    {
        caption: '指标',
        items: [
            { ref: fs.salesAmount },
            {
                name: 'profitRate',
                caption: '利润率(%)',
                formula: 'profitAmount / salesAmount * 100',
                type: 'NUMBER'
            }
        ]
    }
]

3.1 columnGroup 属性 ​

属性类型必填说明
captionstring否列组显示名称
itemsarray是列项列表

3.2 column item 属性 ​

属性类型必填默认值说明
refobject/string否¹无TM 字段引用,推荐使用 loadTableModel 返回的字段引用
namestring否¹普通字段可由 ref 派生输出字段名或计算字段名;计算字段通常需要显式提供
captionstring否无覆盖显示名称
descriptionstring否无字段说明
aliasstring否可由 ref 派生输出别名;未配置时通常使用 ref 的字段名
formulastring否无QM 计算字段公式
typestring否无计算字段返回类型
partitionBystring[]否无formula 计算字段的窗口函数分区字段
windowOrderByobject[]否无formula 计算字段的窗口函数排序字段
windowFramestring否无formula 计算字段的窗口帧定义
emptyDefaultany否无计算字段为空时的默认值,常用于 COALESCE
aiobject否无AI 元数据配置

¹ 普通字段通常使用 ref;计算字段通常使用 name + formula。

partitionBy、windowOrderBy 和 windowFrame 只用于带 formula 的 QM 计算字段。加载时这类列项会被转换为计算字段,执行时引擎先编译 formula 表达式,再按这些配置追加 OVER (PARTITION BY ... ORDER BY ... frame) 窗口子句。普通 ref 字段不会因为声明这些属性而变成窗口字段。

窗口配置引用的字段必须能被当前 QM 解析。windowOrderBy.dir 未配置时按升序处理;windowFrame 当前按 SQL frame 字符串透传给查询引擎。这里属于 formula 计算字段的兼容性边界;如果未来调整公开建模方式,需要继续保持对现有模型的兼容处理。

4. 字段引用 ​

QM 中通常通过 loadTableModel 的代理对象引用字段。

引用说明
fs.orderIdTM 属性
fs.salesAmountTM 指标
fs.customer维度引用,通常展开为 $id、$caption、维度属性和嵌套维度;显式列会避免重复输出
fs.customer$caption维度显示值
fs.customer$customerType维度属性
fs.product.category$caption嵌套维度属性

响应列名中,嵌套维度路径里的 . 通常转为 _:

QM 引用响应列名
fs.product$captionproduct$caption
fs.product.category$captionproduct_category$caption
fs.product.category.group$captionproduct_category_group$caption

DSL 请求应使用当前 QM 暴露的最终字段名。例如当前 QM 暴露 product_category$caption 时,DSL 中应引用 product_category$caption,而不是物理列名或未暴露的 TM 内部路径。

5. 默认排序 ​

5.1 orders ​

javascript
orders: [
    { name: 'salesDate$caption', order: 'desc', nullLast: true }
]
属性类型必填默认值说明
namestring否¹无排序字段名
refobject/string否¹无排序字段引用,支持 loadTableModel 字段引用或字符串
orderstring是无asc 或 desc
nullLastboolean否false空值排在最后
nullFirstboolean否false空值排在最前

¹ name 和 ref 至少提供一个;同时提供时以 ref 为准。

6. 权限与治理属性 ​

语义层治理分为 QM 文件内声明和宿主运行时注入两类。QM 文件负责声明静态模型契约;用户、公司、物理列黑名单等上下文通常由宿主系统在调用查询时注入。

6.1 accesses ​

QM 的 accesses 用于在查询构建阶段注入治理规则,例如行级过滤、租户边界或业务范围限制。

javascript
accesses: [
    {
        queryBuilder: (context) => {
            const query = context.query;
            query.and(fs.companyId, context.securityContext?.companyId);
        }
    }
]
属性类型说明
dimensionstring维度名,用于声明维度级访问规则
propertystring属性名,用于声明属性级访问规则
dimensionDataSqlfunction维度数据权限 SQL 生成函数
queryBuilderfunction接收 context,在查询构建阶段注入条件
context.queryobject查询构建器
context.securityContextobject安全上下文
context.requestobject原始查询请求

权限规则在引擎侧执行,不依赖 LLM 自行遵守提示词。

6.2 运行时治理参数 ​

运行时治理参数通常不直接写入 .tm 或 .qm 文件,而是由 MCP 服务、应用 API、Odoo Bridge 等宿主在查询请求上下文中注入。

参数说明
fieldAccessQM 字段白名单;为空列表表示无字段可见,null 表示不启用字段白名单
deniedColumns物理列黑名单,用于阻止查询访问指定表列
systemSlice系统强制过滤条件,如公司、租户、组织范围
securityContext当前用户、公司、角色等宿主安全上下文

LLM 不应自行构造或覆盖这些安全参数。Compose Script 和 DSL 查询应使用宿主暴露的受限 API,由引擎合并治理上下文并生成最终查询。

6.3 memberPermissions ​

QM 可通过 memberPermissions[] 覆盖 TM 维度上的 memberPermission,用于某个查询模型需要更窄的成员可见范围时使用。

javascript
memberPermissions: [
    {
        dimension: 'product',
        patch: {
            visibleColumns: ['id', 'caption'],
            forcedSlice: [
                { field: 'enabled', op: '=', value: true }
            ]
        }
    }
]
属性类型说明
dimensionstring被覆盖的 TM 维度名
patchobject静态成员权限补丁
queryBuilderfunction动态成员权限构建函数

patch.visibleColumns 控制成员查询返回字段;patch.forcedSlice 注入强制过滤;patch.forcedOrderBy 注入强制排序;patch.hierarchyEnabled 和 patch.allowedHierarchyOps 控制层级成员操作范围。QM 中的成员权限用于覆盖或收窄 TM 维度上的默认成员权限。

7. 命名规则 ​

对象建议命名示例
QM 文件{QueryModelName}.qmSalesAnalysisQueryModel.qm
QM namePascalCaseSalesAnalysisQueryModel
字段 namecamelCasesalesAmount
维度属性引用$ 分隔customer$caption
嵌套维度响应字段_ 连接路径段product_category$caption

8. 与 DSL 的关系 ​

QM 定义字段集合和治理边界;JSON Query DSL 在运行时引用这些字段。

QM 暴露字段DSL 引用
TM property order_id -> orderId"orderId"
TM measure sales_amount -> salesAmount"salesAmount"
dimension customer.captionColumn"customer$caption"
dimension property customer_type"customer$customerType"
QM calculated field profitRate"profitRate"

查询 DSL 语法见 JSON Query DSL 语法参考。