Skip to content

数据 API:集合算子 not_in/in 的比较值是标量(非数组)时答 500 DATABASE_ERROR,而不是带信封的 400 —— 而这个形状是 spec 合法的 ViewFilterRule #5869

Description

@yinlianghui

objectui#3470(PR 见下方 Refs)实施过程中的范围外发现,只记录不修、不指派。实测证据如下。

实测

后端:已发布 @objectstack/*@17.0.0-rc.2 + examples/app-showcase,objectstack dev --seed-admin --fresh;对象 showcase_task,status 为 select。

GET /api/v1/data/showcase_task?$filter=[["status","not_in",["done"]]]   -> 200,8 行(与 ["status","!=","done"] 基线同 8 行)
GET /api/v1/data/showcase_task?$filter=[["status","not_in","done"]]     -> 500 {"code":"DATABASE_ERROR"}
GET /api/v1/data/showcase_task?$filter=[["status","nin","done"]]        -> 500 {"code":"DATABASE_ERROR"}
GET /api/v1/data/showcase_task?$filter=[["status","notin","done"]]      -> 500 {"code":"DATABASE_ERROR"}

即:集合算子 + 标量比较值 = 500not_in/nin/notin 三种拼法一致,说明是规范化之后的同一条路径。

作为对照,同一批探针里形状错误的算子拼法是响亮且正确的 400:[["status","not in",["done"]]](带空格,不在 VALID_AST_OPERATORS)→ 400 INVALID_FILTER。所以问题不在拒收机制本身,而在这一类比较值形状根本没被拒收就下到了 DB 层。

为什么这是个缺陷而不是脏输入

ViewFilterRuleSchema.value 声明为 string | number | boolean | null | (string|number)[],没有按算子约束形状。因此

{ "field": "status", "operator": "not_in", "value": "done" }

是一条 spec 合法ViewFilterRule,可以正常写进 ListViewSchema.filter / ViewTab.filter 并通过发布校验。它下降成 AST 三元组 ["status","not_in","done"] 后又能通过 isFilterAST(该谓词只看算子与结构,不看值形状),于是一路走到 DB 层才炸。

可达性:objectui 侧 plugin-listnormalizeFilterCondition 只对数组值做 in/not-in 展开,标量值原样上线,所以作者写一个标量 not_in 的 tab preset,点开就是 500。

期望

#5348 / #5346 同一个口径:在收口点按形状拒收,给 ADR-0112 信封的 400 INVALID_FILTER,点名是哪个算子、哪个成员、期望什么形状 —— 而不是 500 DATABASE_ERROR(把服务端内部失败暴露成客户端错误的错误类别,也无法告诉作者该改哪个字段)。

一并建议评估:in 的标量值、以及 between 的非二元组值,是否落在同一条路径上(本次只测了 not_in 族,未展开)。

与既有账的关系

同属 #3948 / #4209 点名的「过滤器形状错误未被响亮拒收」大类,与 #5234($in/$nin 列表里的非 $field 对象成员 → 静默零行)是同一轴的不同格:

修法很可能能共用 PR #5223 装在比较发射器上的那道形状守卫(同一收口点、同一信封),但因为症状与入口面都不同,先按标准立独立条目,是否并入 #5234 的完成范围请 PM 裁决。

Refs:#5234#5346#5348#5369#3948#4209;发现于 objectui#3470(objectui PR:claude/issue-3470-userfilters-operator-table)。

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