Repository navigation
Description
现象
ensureCube() 现在有两道源字段闸门 —— assertMeasureFields(#4437,param: 'measures')与 assertDimensionFields(#5520 / PR #5667,param: 'dimensions' | 'timeDimensions')。query.where 的字段名没有任何闸门:一个点名不存在字段的筛选条件被原样编译进 WHERE,由驱动答 no such column,调用方拿到 500(dataset 面还会拿到带整条语句的 message —— PR #5667 已把该路由的 5xx 信封收窄,所以泄漏这一半已闭,但分类这一半仍是 500)。
注意 inferCubeFromQuery 会把 where 的顶层键也铸成 dimension(analytics-service.ts 的 query.where 循环),所以从"cube 词汇表"角度看它和 dimension 是同一类成员;但闸门读的是 query.dimensions / query.timeDimensions 两个请求键,where 不在其中。
复现(测试双,ObjectQL aggregate 路,crm_account 有 id/name/phone/industry/annual_revenue)
POST /analytics/query {"cube":"crm_account","measures":["count"],"where":{"bogus_col":"x"}}
实测(PR #5667 开发期探针,同一 harness 下 dimension 侧已答 400):
生成 SQL: SELECT COUNT(*) AS "count" FROM "crm_account" WHERE bogus_col = $1
executeAggregate 收到调用 → 条件进了引擎,没有任何拒收
在真 SQLite 驱动上这就是 no such column: bogus_col,code/status 皆空,于是 REST 面落 5xx 兜底 —— 与 #5520 立单时 dimension 侧的形状完全一致。
期望
与 measure / dimension 两侧同形:构造 SQL 之前把 where 的字段名拿去和承载对象的字段核对,拒收用同一个信封(400 INVALID_FIELD + field/object/param: 'where')。数据面自 #4315/#4254 起就是这么答的(resolveQueryFields),所以同一个笔误在 /data 与 /analytics 两条路上应当一个形状。
与既有单子的关系(已查重)
- analytics: a measure naming a missing field 500s with SQLITE_ERROR instead of a 400 naming the field #4437(closed,measure)、[17.0-rc2验收] analytics: 不存在的 dimension 500(泄漏 SQL / SQLITE_ERROR)而不是 400 指名字段 —— #4437 只给 measure 加了闸门,dimension 侧对称缺口仍在 #5520 / PR fix(service-analytics,rest): analytics dimension 的源字段闸门 —— 不存在的 dimension 答 400 INVALID_FIELD,dataset 500 不再回显 SQL (#5520) #5667(dimension + timeDimensions):同一缺陷家族的前两个 param;都不覆盖
where。 - analytics 的 filter 拒收到不了调用方:service 侧多数拒收没有 ADR-0112 信封,REST 面又用 message 正则嗅探,一律答 500 #5352(closed)/ PR fix(analytics,rest): analytics 的 filter 拒收带上 ADR-0112 信封,REST 面先读信封 —— 400 INVALID_FILTER 而不是 500 (#5352) #5366、analytics dataset 路由的 message 正则兜底没有退休时间表:六族拒收仍靠措辞分类,改一个字就换一个 HTTP 码 #5367(open):管的是 filter 算子/结构拒收怎么带信封、怎么退休 message 正则名单 —— 那些拒收判的是"这个 filter 能不能编译",不是"这个字段存不存在"。
{bogus_col: 'x'}是一个结构完全合法、算子完全合法的 filter,filter-normalizer没有理由拒它,所以本单不在 analytics dataset 路由的 message 正则兜底没有退休时间表:六族拒收仍靠措辞分类,改一个字就换一个 HTTP 码 #5367 的地盘。 - observation:
inferCube仍把数组where当「不是筛选」跳过 —— #5334 之后这个!Array.isArray守卫已经过时 #5353(open,inferCube的!Array.isArray(where)守卫已过时):相邻但不同 —— 那是"数组 where 被当成没有筛选跳过",本单是"字段名从不核对"。两者都动where,实现时留意顺序。
实现提示
闸门本体大概是 assertDimensionFields 的三档 stand-down 照抄(cube.sql 须为裸对象名、getObjectFieldNames 须作答、源须为裸列),难点在遍历 filter 树取字段键:要跳过 $and/$or/$not 等组合子与 $-前缀算子键,点号路径按关系穿越放行(同 dimension 闸门),并且要和 filter-normalizer 对同一棵树的读法保持一致,否则会出现"闸门看到的字段"与"真正进 SQL 的列"不是一回事。
严重度按 #5520 的口径估:无数字影响(出厂 metadata 由静态校验兜住),撞点是 Studio 预览、手写查询、外部 API 调用方 —— 他们拿到 500 而不是指名字段的 400。
Activity
os-zhuang commentedon Aug 5, 2026
分诊:入队(
pm:queue)+domain:services。packages/services/service-analytics/src/analytics-service.ts(services 车道)。已核origin/main:assertMeasureFields/assertDimensionFields两道闸门都在(即 [17.0-rc2验收] analytics: 不存在的 dimension 500(泄漏 SQL / SQLITE_ERROR)而不是 400 指名字段 —— #4437 只给 measure 加了闸门,dimension 侧对称缺口仍在 #5520 的 PR fix(service-analytics,rest): analytics dimension 的源字段闸门 —— 不存在的 dimension 答 400 INVALID_FIELD,dataset 500 不再回显 SQL (#5520) #5667 已合入,本单「照抄三档 stand-down」的前提成立);param: 'where'在packages/services零命中,即 where 闸门确实缺失——具体缺陷 + 复现 + 修法齐全,直接入队。inferCube仍把数组where当「不是筛选」跳过 —— #5334 之后这个!Array.isArray守卫已经过时 #5353)issue 正文已自行辨析,核对无误。inferCube仍把数组where当「不是筛选」跳过 —— #5334 之后这个!Array.isArray守卫已经过时 #5353(open)同样动analytics-service.ts的inferCube/where 路径——同文件跨轮串行(step 3 纪律),两单不要同批;先行者的派发令按惯例带「是否让另一单变简单/变难」必答项。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-zhuang commentedon Aug 6, 2026
认领(services 车道 PM 派发,
session_01BWS4heBoAitLmzCLhcYdbK)claude/issue-5669-where-field-gate../objectstack-issue-5669(dev 子代理按 worktree-first 自建)packages/services/service-analytics/src/analytics-service.ts(ensureCube补 where 侧闸门,filter 树遍历取字段键)、同包测试(对称dimension-source-field-gate.test.ts)、rest 端到端如需(对称 fix(service-analytics,rest): analytics dimension 的源字段闸门 —— 不存在的 dimension 答 400 INVALID_FIELD,dataset 500 不再回显 SQL (#5520) #5667 先例,申报即可)、.changeset/*.md。inferCube仍把数组where当「不是筛选」跳过 —— #5334 之后这个!Array.isArray守卫已经过时 #5353 与本单同文件同 where 路径,排本单落地之后(分诊串行提示照办)。按分诊惯例,报告须含「本单是否让 observation:inferCube仍把数组where当「不是筛选」跳过 —— #5334 之后这个!Array.isArray守卫已经过时 #5353 变简单/变难」必答项。Generated by Claude Code
fix(service-analytics): gate `where` source fields — a filter over a …