Repository navigation
Description
做 #5374($notContains 编译成裸 {$not: 'x'})时,为了确认修复没有把 $match 的组装弄坏,逐个实测了「一个 where 里同一字段带多个算子」会编译成什么。这一条不属于 #5374 的范围面 —— #5374 裁的是算子 → 谓词这一层(映射指向了错的目标),这一条在谓词 → $match 的组装这一层,#5374 修好之后依然完整存在。按 Prime Directive #10 单独记在这里,unassigned。
位置
packages/plugins/driver-memory/src/memory-analytics.ts,query() Stage 1 的 $match 组装循环(约 :180):
for (const filter of normalizedFilters) {
const fieldPath = this.resolveFieldPath(cube, filter.member);
matchStage[fieldPath] = /* 该条目的谓词 */; // ← 直接赋值,不合并
}flattenFilterCondition 对 {field: {$op1: a, $op2: b}} 会 push 两条 NormalizedCubeFilter,member 都是 field。两条都以 matchStage[fieldPath] = … 落盘,于是后一条覆盖前一条,前一个算子彻底消失。
现象(实测)
3 行数据,qty 分别为 100 / 200 / 300(id 分别为 1/2/3)。左列是 find(),右列是 analytics 面 —— 两列都是在 #5374 修复之后测的,即这条与那条无关:
where |
find() |
analytics | 实际编译出的 $match |
|---|---|---|---|
{qty: {$gte: 150, $lte: 250}} |
[2] |
[1,2] |
{qty: {$lt: 250}} |
{qty: {$ne: 300, $gt: 150}} |
[2] |
[2,3] |
{qty: {$gt: 150}} |
方向是放大:丢掉的永远是一个约束,所以行只会变多,不会变少。这与 #5345 / #5373 / #5374 是同一个方向、同一类后果 —— 一个看起来正常的图表统计了它本该排除的行 —— 只是机制换成了「谓词被生成了,但被下一个谓词覆盖掉」。
为什么是 bug
{$gte, $lte}是区间的规范写法。AnalyticsQuery.where是FilterCondition,而 dashboard widget 元数据直接用这个形状表达「金额在某区间」「日期在某窗口」。这恰恰是最常见的多算子写法,不是边角。- declared ≠ enforced。
ANALYTICS_FILTER_CAPABILITIES声明本面支持这 11 个算子,assertFilterConditionShape也放行了{$gte, $lte}这个形状 —— 声明能算,实际只算了一半。 - 另一半是对的。 live query path 的
normalizeFieldOperators把同字段的多个算子合并进一个对象,多个 regex 型算子还会通过_multiRegex提升成$and。所以这是同一个 driver 的两面对同一个where给出不同行集 ——{ field: {} }(零个操作符的字段约束)在同仓有三个答案:driver-sql 组合子内 TRUE、顶层抛 INVALID_FILTER、formula/driver-memory FALSE #5240 为本包立下的不变量所禁止的形状。
建议(不代裁决)
不是一行改。合并本身容易(matchStage[fieldPath] = {...existing, ...predicate}),但有两处必须一起想清楚,否则会把一个覆盖换成另一个覆盖:
- 两个 regex 型谓词无法共存于一个对象(
$contains+$contains,或$contains+$notContains各自带$regex)。live path 为此有_multiRegex→ 顶层$and的提升,cube 管线需要一份等价物。 $lte的 bare-day 半开区间规则(driver-memory / driver-mongodb:裸日期$lte上界在 datetime 值上同样丢当天数据(#3777 的非 SQL 驱动对齐) #4042)会把$lte写成$lt,与显式的$lt键相撞;合并时谁赢需要明确。
另一条路是拒收同字段多算子(与 #5345 同款),但那会拒掉本面 find() 明明能算、且是 widget 常用形状的查询,恐怕不是想要的答案。
未验证的部分
- 只测了
qty上的数值算子组合。没有测 regex 型算子的组合({name: {$contains: 'a', $notContains: 'b'}}),因为那正是上面第一个待裁决点,测出来的结果取决于怎么裁。 - 没有核对
generateSql那一半在同样输入下是否也丢约束(那个出口的算子层缺陷另有 driver-memory analytics 面的generateSql对in/notIn/set/notSet输出错误 SQL:回退成=且只取第一个值($in: ['100','200']→WHERE code = '100') #5433)。
关联:#5374(同文件、同一轮核对里发现;它裁的是算子→谓词层,本条是谓词→$match 组装层)、#5345、#5373、#5240(本包两面不得分叉)、#3948(no-silent-drop)。
Activity
os-zhuang commentedon Aug 5, 2026
分诊(backlog sweep,主 backlog 代扫):挂⚠️ 同文件族串行:#5433 / #5440 / #5442 / #5444 落同一文件,认领时严格跨轮串行。不构成认领。会话:
pm:queue+domain:engine。理由:落点packages/plugins/driver-memory/src/memory-analytics.ts(同字段多算子互相覆盖,区间塌成单边);实测证据具体,符合 auto-queue 判据。session_01N3uGFF8teXbpgtbEJ1aYXuGenerated by Claude Code
os-zhuang commentedon Aug 5, 2026
转
pm:on-hold(2026-08-05,维护者裁决,锚点 #5499):driver-memory 为早期测试便利组件,方向已定 sqlite 内存模式替代,缺陷修复投入冻结(撤销今晨 12:2xZ 的入队分诊——当时冻结裁决尚未下达)。重启条件:替代在测试面完成后随锚点整批关闭;若影响 CI 判绿正确性,按 restore-invariant 例外升级。不派发、不催。会话:session_01N3uGFF8teXbpgtbEJ1aYXuGenerated by Claude Code
fix(driver-memory): the analytics face compiles $notContains to a pre…
os-zhuang commentedon Aug 6, 2026
按 #5499 重启条件 + #5704 收口关闭(not planned):维护者 2026-08-06 裁定 driver-memory 的测试职能由 sqlite
:memory:替代,迁移已完成(PR #5715 / #5797 / #5806);本包处于投入冻结(#5499),analytics 面缺陷不再计划修复。若维护者后续裁定包本体保留并解冻,可重开。Generated by Claude Code