You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Cerbos条件AST转换为Ucast CompoundCondition?

实现Cerbos queryPlanner AST到ucast CompoundCondition的转换

核心转换函数实现

要完成Cerbos AST到ucast条件对象的转换,编写一个递归处理AST节点的函数即可,针对复合条件(and/or)和字段比较条件分别处理:

import { CompoundCondition, FieldCondition } from '@ucast/core';

// 定义Cerbos AST的类型(TypeScript可选)
type CerbosAstOperand = { name: string } | { value: any };
type CerbosAstNode = {
  operator: string;
  operands: CerbosAstOperand[] | CerbosAstNode[];
};

function cerbosAstToUcast(ast: CerbosAstNode, resourceAlias = 'R'): CompoundCondition | FieldCondition {
  // 处理and/or复合条件,递归转换子节点
  if (['and', 'or'].includes(ast.operator)) {
    const childConditions = (ast.operands as CerbosAstNode[]).map(node => cerbosAstToUcast(node, resourceAlias));
    return new CompoundCondition(ast.operator, childConditions);
  }

  // 处理字段比较条件(gt/eq/in等)
  const [left, right] = ast.operands as CerbosAstOperand[];
  let field: string;
  let value: any;

  // 区分字段和值,处理in操作的顺序反转(Cerbos中in的operands是[value, name])
  if ('name' in left) {
    field = left.name.replace('request.resource.attr.', `${resourceAlias}.attr.`);
    value = (right as { value: any }).value;
  } else {
    field = (right as { name: string }).name.replace('request.resource.attr.', `${resourceAlias}.attr.`);
    value = (left as { value: any }).value;
  }

  return new FieldCondition(ast.operator as any, field, value);
}

函数逻辑说明

  1. 递归处理复合条件:当AST节点的operator是and或or时,递归转换每个子operand,生成对应的CompoundCondition。
  2. 字段路径转换:将Cerbos返回的request.resource.attr.xxx格式字段名,替换为查询时使用的表别名(如u.attr.xxx)。
  3. 特殊操作符处理:针对in操作,Cerbos返回的operands顺序是[value, name],需要反转后匹配ucastFieldCondition的(field, value)参数顺序。
  4. 字段比较条件生成:对于gt/eq/lt/ge/le/ne等操作符,直接生成对应的FieldCondition。

转换示例验证

使用你提供的Cerbos AST示例,执行转换后将得到预期的ucast Condition对象:

// 你的Cerbos AST示例
const cerbosAst = {
  "operator": "and",
  "operands": [
    { "operator": "gt", "operands": [{ "name": "request.resource.attr.foo" }, { "value": 4 }] },
    {
      "operator": "or",
      "operands": [
        { "operator": "eq", "operands": [{ "name": "request.resource.attr.bar" }, { "value": 5 }] },
        {
          "operator": "and",
          "operands": [
            { "operator": "eq", "operands": [{ "name": "request.resource.attr.fizz" }, { "value": 6 }] },
            { "operator": "in", "operands": [{ "value": "ZZZ" }, { "name": "request.resource.attr.buzz" }] }
          ]
        }
      ]
    }
  ]
};

// 转换为ucast Condition
const condition = cerbosAstToUcast(cerbosAst, 'u'); // 使用'u'作为表别名

生成TypeORM查询构建器

转换完成后,即可通过@ucast/sql生成TypeORM查询构建器:

import { createConnection } from 'typeorm';
import { interpret } from '@ucast/sql';
import { User } from './entities/User';

async function getAuthorizedUsers() {
  const conn = await createConnection({
    type: 'mysql',
    database: ':memory:',
    entities: [User]
  });

  const qb = interpret(condition, conn.createQueryBuilder(User, 'u'));
  const authorizedUsers = await qb.getMany();
  
  return authorizedUsers;
}

注意事项

  • 该函数已兼容and/or/gt/eq/lt/ge/le/ne/in等Cerbos常用操作符,可根据需要扩展支持更多操作符。
  • 可根据实际查询场景调整resourceAlias参数,匹配TypeORM查询时使用的表别名。
  • TypeScript环境下,完善类型定义可增强代码的类型安全。

内容的提问来源于stack exchange,提问作者Tal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 16:39:21