Skip to content

[spec] SqlDriver 将 $field 编译为列对列比较(cross-field comparison push-down) #5222

Description

@xuyushun441-sys

一句话

FieldReferenceSchema({ $field: '...' })在 SQL 下推路径上真正执行 —— 编译为列对列比较(where "amount" > "budget"),补齐 #5041 裁决 C 明确挂起的那一半。

背景:本单是 #5041 的下半场

#5041 的维护者裁决(2026-08-04)选了 C —— 最低限度:SqlDriver 遇到 { $field } 值形态时按 ADR-0112 响亮拒绝(INVALID_FILTER + httpStatus 400),消除裸 TypeError$in/$between 列表里的静默零行;保留 spec 声明;真正的 SQL 实现另立本单。

也就是说,现状是已知且诚实的半态,不是遗漏:

执行路径 $field 行为
内存求值 matchesFilter(packages/formula/src/matches-filter.ts) ✅ 按记录解析引用,支持点号路径
SQL 下推 driver-sql / driver-sqlite-wasm INVALID_FILTER 响亮拒绝(#5041 已落地)

生产者是真实的:compileCelToFilter(packages/formula/src/cel-to-filter.ts)在把含字段间比较的 CEL 权限 / RLS 规则转译为 filter 时会产出 { $field: path }。所以今天这类规则只有内存路径能跑,一旦下推到 SQL 就是一个 400,而不是结果。

本单要做的事

packages/plugins/driver-sql 的比较发射点(applyFilterCondition / applyAstComparison)把 { $field: 'col' } 编译成列引用而非绑定值 —— SQL 层面 where ?? > ?? 是平凡的,难点全在语义边界(见下)。落地时把 #5041 装的那道拒绝闸门收窄到「仍然编译不了的形态」,而不是整个删掉。

验收面:

两个待决语义点(本单一并议,勿默认)

1. 点号关联路径的语义

内存求值器的 getPath{ $field: 'account.owner_id' }沿对象逐层取属性。SQL 侧同一个字符串有至少三种读法:

选哪个直接决定 FieldReferenceSchema$field 是「列名」还是「路径」,属于契约面,不应由实现顺手定。

2. 被引用列名的校验边界

$field 的值最终要进入 SQL 标识符位置。cloud#1051 讨论过:放行不校验等于拆护栏。需要明确:

  • 是否只允许对象已声明的字段(initObjects 已知列),未知列一律 INVALID_FILTER?
  • 系统列(created_at / space / 租户列)是否可被引用?尤其租户隔离列若可被引用,是否构成越权比较面?
  • 外部表 / 联邦表(ADR-0015,列集未知)上如何取舍 —— 拒绝,还是放行由数据库报错?

倾向:声明即枚举,只接受已声明字段,未知列在编译期响亮拒绝 —— 与本仓「declared = enforced」的一贯姿态一致,也让 AI 产出的元数据在写的时候就错不了,而不是在数据库里错。但这是需要维护者拍板的契约决定。

Refs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions