You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
case'contains': return{$regex: values[0]};// `notContains` had no arm and fell to the `default` below ... These three pass// through as the canonical spec operators every driver implements directly, so an// anchored match stays anchored rather than depending on regex dialect (#4128).case'notContains': return{$notContains: values[0]};case'startsWith': return{$startsWith: values[0]};case'endsWith': return{$endsWith: values[0]};
紧挨着的注释把三个同族算子改成规范算子的理由写得很清楚 ——「so an anchored match stays anchored rather than depending on regex dialect」—— 而 contains 留在了 $regex 上,同一个 switch 里的四个 LIKE 家族算子,三个走规范算子,一个走正则。
修 #5333(回显丢
$startsWith/$endsWith)时核对objectql-strategy.ts的算子覆盖面,发现这一条在执行侧,与 #5333 的回显侧只隔一个函数。位置
packages/services/service-analytics/src/strategies/objectql-strategy.ts的convertFilter(约 1018 行):紧挨着的注释把三个同族算子改成规范算子的理由写得很清楚 ——「so an anchored match stays anchored rather than depending on regex dialect」—— 而
contains留在了$regex上,同一个 switch 里的四个 LIKE 家族算子,三个走规范算子,一个走正则。实测(
ObjectQLStrategy.execute捕获交给executeAggregate的 filter)比较值原样放进
$regex,不转义。于是在任何把$regex当真正则求值的后端上:driver-memory的memory-matcher.ts正是new RegExp(target, …),并且catch之后return false—— 所以带正则元字符的比较值要么多匹配(.[|),要么静默零行(括号/量词非法时)。对照:driver-memory自己的 analytics 面(memory-analytics.ts)对contains是substring: (v) => this.driver.filterSubstringPattern(v),即用驱动自己的规则转义成字面子串;经由本 issue 这条路径进来的$regex绕过了那层转义。为什么是 bug(三点,都不依赖 #4706 的裁决)
$regex不在契约里。packages/spec/src/data/filter.zod.ts的FILTER_OPERATORS是 15 个:$eq $ne $gt $gte $lt $lte $in $nin $between $contains $notContains $startsWith $endsWith $null $exists—— 没有$regex。这里是一个生产方在向引擎发送 schema 未声明的算子;按 Prime Directive Add comprehensive test suite for Zod schema validation #12,修法在生产方,而不是让消费方各自容忍。read-scope-sql.ts的compileOperator遇到$regex直接抛[read-scope-sql] unsupported operator "$regex" on "stage" (fail-closed)(/analytics/sql回显的 SQL 丢掉$startsWith/$endsWith谓词:回显比实际执行的查询更宽,无法复现结果 #5333 的测试用它做 stand-in 引擎时当场撞上)。同一个FilterCondition在同一个包的两个消费方之间已经不通。driver-sql把$regex编译成子串LIKE(sql-driver.ts约 6489 行,注释还写着「$regexreaches SQL only via the better-auth adapter」—— 它不知道 analytics 是第二个生产方),而 regex 求值的后端按正则匹配。同一个 dashboard 的$containswidget 在不同驱动上返回不同行集 —— 这正是$regexon driver-sql is not a regex — it compiles to a substring LIKE, so it both over-matches and silently matches nothing #4706 第 3 点最想要答案的那个形状。建议
case 'contains': return { $contains: values[0] };—— 与它三个同族算子一致,一行。这样$regex在service-analytics里就没有生产方了,#4706 那道「$regex到底该是什么语义」的裁决也少一个受影响的调用方(本条不等它:改成规范算子无论 #4706 怎么裁都是对的)。需要的用例:
contains的比较值带正则元字符(a.b、50% (+))时,行结果与字面子串一致 —— 断言 SQL/filter 字符串会漏掉转义这一半。关联:#5333(同文件、回显侧的同类算子表漂移)、#4128(
convertFilter的default:从「当成等值」改成抛错、三个同族算子改成规范算子的那次)、#4706($regex语义待裁决,needs-user-decision)、#5374(driver-memoryanalytics 面改成整条谓词构建的那次,contains在那边是转义过的)。