Skip to content

QM 语法手册

下载本文档

QM(Query Model,查询模型)用于定义基于 TM 的查询视图,包含可查询的字段和 UI 配置。

1. 基本结构

QM 文件使用 JavaScript 语法,导出一个 queryModel 对象:

javascript
export const queryModel = {
    name: 'FactOrderQueryModel',    // 查询模型名称(必填)
    caption: '订单查询',             // 显示名称
    model: 'FactOrderModel',        // 关联的 TM 模型名称(必填)

    columnGroups: [...],            // 列组定义
    orders: [...]                   // 默认排序
};

1.1 基础字段

字段类型必填说明
namestring查询模型唯一标识
captionstring显示名称
modelstring/array关联的 TM 模型(单个或多个)
columnGroupsarray列组定义
ordersarray默认排序

2. 单模型关联

最常见的情况是 QM 关联单个 TM:

javascript
export const queryModel = {
    name: 'FactOrderQueryModel',
    model: 'FactOrderModel',   // 直接使用 TM 名称
    columnGroups: [...]
};

3. 多模型关联

当需要关联多个事实表时,使用 loadTableModel 加载模型,通过 ref 引用字段。

javascript
// 加载模型
const fo = loadTableModel('FactOrderModel');
const fp = loadTableModel('FactPaymentModel');

export const queryModel = {
    name: 'OrderPaymentJoinQueryModel',
    caption: '订单支付关联查询',

    // 多模型配置
    model: [
        {
            name: fo,
            alias: 'fo'                    // 表别名
        },
        {
            name: fp,
            alias: 'fp',
            onBuilder: () => {             // JOIN 条件
                return 'fo.order_id = fp.order_id';
            }
        }
    ],

    columnGroups: [
        {
            caption: '订单信息',
            items: [
                { ref: fo.orderId },           // V2:使用 ref 引用
                { ref: fo.orderStatus },
                { ref: fo.customer }           // 维度引用,自动展开为 $id 和 $caption
            ]
        },
        {
            caption: '支付信息',
            items: [
                { ref: fp.paymentId },
                { ref: fp.payAmount }
            ]
        }
    ]
};

3.1 多模型字段说明

字段类型必填说明
namestring/proxyTM 模型名称或 loadTableModel 返回的代理
aliasstring表别名,用于区分不同模型的字段
onBuilderfunctionJOIN 条件构建函数(第二个及之后的模型必填)

4. 列组定义 (columnGroups)

列组用于对查询字段进行分组,便于 UI 展示。使用 loadTableModel 加载模型后,通过 ref 引用字段:

javascript
const fo = loadTableModel('FactOrderModel');

columnGroups: [
    {
        caption: '订单信息',
        items: [
            { ref: fo.orderId },
            { ref: fo.orderStatus }
        ]
    },
    {
        caption: '客户维度',
        items: [
            { ref: fo.customer },              // 自动展开为 $id + $caption
            { ref: fo.customer$customerType }  // 维度属性
        ]
    }
]

ref 语法优势

  • IDE 支持代码补全和类型检查
  • 重构时自动更新引用
  • 编译时即可发现错误

4.1 维度引用的自动展开

ref 指向一个维度(无 $ 后缀)时,会自动展开为两列:

javascript
{ ref: fo.customer }
// 等价于自动生成两列:
// customer$id
// customer$caption

4.2 列组字段

字段类型必填说明
captionstring组名称
namestring组标识
itemsarray列项列表

4.3 列项字段

字段类型必填说明
refobject字段引用(使用 loadTableModel 代理)
captionstring覆盖 TM 中的显示名称
aliasstring输出列别名
uiobjectUI 配置

4.4 UI 配置

字段类型说明
fixedstring固定位置:left / right
widthnumber列宽度(像素)
alignstring对齐方式:left / center / right
visibleboolean是否默认可见

5. 字段引用格式

使用 loadTableModel 加载模型后,通过代理对象引用字段:

javascript
const fo = loadTableModel('FactOrderModel');

// 事实表属性
fo.orderId
fo.orderStatus

// 度量
fo.totalAmount

// 维度(自动展开为 $id + $caption)
fo.customer

// 维度属性
fo.customer$customerType
fo.customer$province

// 嵌套维度(使用 . 路径语法)
fo.product.category$caption
fo.product.category.group$caption

5.1 嵌套维度引用

语法规则. 负责维度层级导航,$ 负责属性访问,二者职责分离:

fo.product.category$caption
   ├─────────────┘  └──┘
   │  维度路径(.分隔)   属性名($分隔)

三种引用方式

javascript
// 方式1:完整路径(精确,无需 alias)
{ ref: fo.product.category$caption }
{ ref: fo.product.category.group$caption }

// 方式2:别名(推荐,需在 TM 中定义 alias)
{ ref: fo.productCategory$caption }     // alias: 'productCategory'
{ ref: fo.categoryGroup$caption }       // alias: 'categoryGroup'

// 方式3:DSL 查询中使用下划线格式(输出列名格式)
columns: ["product_category$caption", "product_category_group$caption"]

注意:不能用多个 $ 代替 .(如 product$category$caption),解析器会将第一个 $ 后的内容整体视为属性名,导致查找失败。

路径语法说明

  • fo.product → 一级维度
  • fo.product.category → 二级维度(product 的子维度)
  • fo.product.category$caption → 二级维度的 caption 属性
  • fo.product.category$id → 二级维度的 id
  • fo.product.category.group$caption → 三级维度的 caption

输出列名格式

路径中的 . 在输出时自动转为 _,避免 JavaScript 属性名冲突:

QM 引用输出列名
fo.product$captionproduct$caption
fo.product.category$captionproduct_category$caption
fo.product.category.group$captionproduct_category_group$caption

6. 默认排序 (orders)

定义查询的默认排序规则:

javascript
orders: [
    { name: 'orderTime', order: 'desc' },
    { name: 'orderId', order: 'asc' }
]

6.1 排序字段

字段类型必填说明
namestring排序字段名
orderstring排序方向:asc(升序)/ desc(降序)

7. 计算字段

可以在 QM 中定义计算字段:

javascript
columnGroups: [
    {
        caption: '计算字段',
        items: [
            {
                name: 'profitRate',
                caption: '利润率',
                formula: 'profitAmount / salesAmount * 100',
                type: 'NUMBER'
            },
            {
                name: 'avgPrice',
                caption: '平均单价',
                formula: 'totalAmount / totalQuantity',
                type: 'MONEY'
            }
        ]
    }
]

8.1 计算字段配置

字段类型必填说明
namestring计算字段名
captionstring显示名称
formulastring计算公式
typestring结果数据类型

8. 完整示例

8.1 基础查询模型

javascript
// FactOrderQueryModel.qm

const fo = loadTableModel('FactOrderModel');

export const queryModel = {
    name: 'FactOrderQueryModel',
    caption: '订单查询',
    model: fo,

    columnGroups: [
        {
            caption: '订单信息',
            items: [
                { ref: fo.orderId },
                { ref: fo.orderStatus },
                { ref: fo.orderTime }
            ]
        },
        {
            caption: '客户信息',
            items: [
                { ref: fo.customer },
                { ref: fo.customer$customerType },
                { ref: fo.customer$province }
            ]
        },
        {
            caption: '商品信息',
            items: [
                { ref: fo.product },
                { ref: fo.product$category },
                { ref: fo.product$unitPrice }
            ]
        },
        {
            caption: '度量',
            items: [
                { ref: fo.totalQuantity },
                { ref: fo.totalAmount },
                { ref: fo.profitAmount }
            ]
        }
    ],

    orders: [
        { name: 'orderTime', order: 'desc' }
    ]
};

8.2 多事实表关联

javascript
// OrderPaymentQueryModel.qm

const order = loadTableModel('FactOrderModel');
const payment = loadTableModel('FactPaymentModel');

export const queryModel = {
    name: 'OrderPaymentQueryModel',
    caption: '订单支付查询',

    model: [
        {
            name: order,
            alias: 'order'
        },
        {
            name: payment,
            alias: 'payment',
            onBuilder: () => 'order.order_id = payment.order_id'
        }
    ],

    columnGroups: [
        {
            caption: '订单信息',
            items: [
                { ref: order.orderId },
                { ref: order.orderStatus },
                { ref: order.totalAmount }
            ]
        },
        {
            caption: '支付信息',
            items: [
                { ref: payment.paymentId },
                { ref: payment.paymentMethod },
                { ref: payment.paymentAmount },
                { ref: payment.paymentTime }
            ]
        },
        {
            caption: '客户信息',
            items: [
                { ref: order.customer },
                { ref: order.customer$customerType }
            ]
        }
    ],

    orders: [
        { name: 'payment.paymentTime', order: 'desc' }
    ]
};

8.3 带计算字段的查询模型

javascript
// SalesAnalysisQueryModel.qm

const fs = loadTableModel('FactSalesModel');

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

    columnGroups: [
        {
            caption: '维度',
            items: [
                { ref: fs.salesDate$year },
                { ref: fs.salesDate$month },
                { ref: fs.product$category },
                { ref: fs.customer$customerType }
            ]
        },
        {
            caption: '基础度量',
            items: [
                { ref: fs.salesQuantity },
                { ref: fs.salesAmount },
                { ref: fs.costAmount },
                { ref: fs.profitAmount }
            ]
        },
        {
            caption: '计算指标',
            items: [
                {
                    name: 'profitRate',
                    caption: '利润率(%)',
                    formula: 'profitAmount / salesAmount * 100',
                    type: 'NUMBER'
                },
                {
                    name: 'avgOrderAmount',
                    caption: '客单价',
                    formula: 'salesAmount / COUNT(*)',
                    type: 'MONEY'
                }
            ]
        }
    ],

    orders: [
        { name: 'salesDate$year', order: 'desc' },
        { name: 'salesDate$month', order: 'desc' }
    ]
};

9. 命名约定

9.1 文件命名

  • QM 文件:{TM模型名}QueryModel.qm
  • 示例:FactOrderQueryModel.qm

9.2 模型命名

  • 查询模型名:{TM模型名}QueryModel
  • 示例:FactOrderQueryModel

下一步