Skip to content

[finding] 已保存视图的 ViewFilterRule[] 被原样当 FilterNode 送进 $filter,未在客户端折成 AST #3431

Description

@yinlianghui

发现于 #3419(把 ObjectDataPage「Save as view」的 URL 下钻三元组折成 spec rule)。不在该 PR 的 fence 内,也没有在真后端上验证过,故按 observation 记录,不带 pm:queue

观察

已保存视图的 filter 落盘形状是 spec 的 ViewFilterRule[]({ field, operator, value })—— objectstack#5159 的修法就是让 persistViewFilterfolded.rules。读回来时:

  • ObjectView.tsx(约 1347 行)const base = viewDef.filter ?? listSchema.filter,再 [...baseArr, ...urlFilters] —— 这里会把 rule 对象和 URL 三元组混在同一个数组里;
  • 传给 ListViewschema.filter,ListView.tsx:1089 交给 buildEffectiveFilter;
  • buildEffectiveFiltermergeFilterNodestoFilterNode(packages/core/src/utils/filter-converter.ts:199),而 toFilterNode 对数组是原样返回:
if (Array.isArray(source)) return source.length > 0 ? (source as FilterNode) : undefined;

也就是说 [{ field: 'stage', operator: 'equals', value: 'open' }] 会被当成一个 FilterNode 直接进 $filter。客户端这一路没有任何地方把 rule 对象折成 [field, op, value](ListView.mapOperator 只在 convertFilterGroupToAST 里被调用,处理的是 FilterBuilder 的 group,不覆盖 schema.filter)。

值得注意的是 mergeFilterNodes 自己的注释就警告过这个形状:

spreading a ViewFilterRule[] puts bare rule OBJECTS where the AST expects nodes, and the server neither understands nor rejects that cleanly —— isFilterAST says no (a 400 since objectstack#4121), while parseFilterAST reads the rule as a Mongo condition and filters on columns literally named field / operator / value.

注释是针对 spread 写的,但 toFilterNode 的原样返回把同一个数组整体交出去,落到 $filter 上是同一类载荷。

为什么标成 observation 而不是缺陷

两种可能我没能区分,需要一个跑起来的后端才能定:

  1. 服务端本来就接受 ViewFilterRule[] —— 那这条只是注释与实现的语气不一致,顺手补一句说明即可;
  2. 服务端不接受 —— 那么今天每一条带 filter 的已保存视图筛选都是坏的(400 或静默按字面列名过滤)。若真如此,#5159 落地后应该早就被发现,所以我更倾向 1;但「早该被发现」不是证据。

复现方向(给接手的人)

起一套栈(AGENTS.md「每个 agent 独立测试栈」),在某对象上存一条带 filter 的列表视图,打开它,看网络面板里 $filter 的实际载荷与返回行数:是 [{"field":...}] 且结果正确,还是 400 / 未筛选。

相关

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions