Skip to content

objectql having-filter.ts 是「无值字段」语义的第五个求值面,且带着 #5299 同款的早退守卫($nin / $notContains 不在豁免名单) #5905

Description

@os-zhuang

出自 #5298「第一棒:成本清单」的消费点清点(纯读调查),范围外发现,按 Prime Directive #10 记录,不指派。

事实(origin/main 5c94f833c,静态对读)

packages/objectql/src/having-filter.ts自己的一套 arm 求值 HAVING 子句,算子词表与 FilterCondition 同一套(having-filter.ts:35-37 列了 $eq $ne $gt $gte $lt $lte $between $in $nin $exists $null $contains $notContains $startsWith $endsWith $regex)。它是 driver-sql / driver-memory 的 mingo 面 / driver-memory 的参考匹配器 / formula.matchesFilterCondition 之外的第五个求值面,#5146 / #5299 / #5298 的清点里都没有出现过。

两处与 #5299 记录的 driver-memory 分叉形状完全相同:

  1. having-filter.ts:112
    if (value === undefined && op !== '$exists' && op !== '$ne' && op !== '$null') return false;
    —— 豁免名单里没有 $nin(也没有 $notContains),与 driver-memory 与 formula 对「字段没有值」给出三处不同答案:$notContains(null 值)、$exists(键在值为 null)、$nin(缺键) #5299 正文点名的 memory-matcher.ts 早退守卫逐字同构。
  2. having-filter.ts:137
    case '$notContains': if (typeof value !== 'string' || value.includes(target)) return false;
    —— 值不是字符串(null / undefined)一律判否,与 driver-memory 与 formula 对「字段没有值」给出三处不同答案:$notContains(null 值)、$exists(键在值为 null)、$nin(缺键) #5299 记录的 driver-memory 读法一致、与 formula 相反(formula/src/matches-filter.ts:183 判是)。

另外 having-filter.ts:126$nin 本体 if (Array.isArray(target) && target.includes(value)) return false;value === undefined 本来是「通过」的,是上面那条早退守卫先把它拦成了「不通过」—— 与 #5299 描述的机制一模一样。

为什么按 finding 记(不代 triage 定级)

HAVING 求值的输入是聚合输出行,measure 键通常总是存在,所以 value === undefined 这一格今天不太容易被真实用户撞到;$notContains 对 null 值那一格则取决于聚合是否产出 null measure。没有量化真实 dashboard 里出现这两种形状的频率。按「观察类」记,不因为「看着小」就压着不报 —— 定级请按 triage,不代表我判断它低。

与既有账的关系

关联

#5299(driver-memory vs formula 的同款三格)、#5298(非否定路径 NULL-safe 裁决)、#5146 / PR #5296(极性表)、#5239(FILTER_LOGIC_CASES —— 今天不覆盖 HAVING 路径)。

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions