Skip to content

sort 的点号路径(?sort=account.company_name)仍然静默降级为「不排序」——#4226 收口后唯一漏网的 sort 形态 #4256

Description

@os-zhuang

TL;DR

#4226(PR #4240)让 sort 指向不存在的字段变成 400 INVALID_SORT。有一种形态故意被放过了,这里把它单独记下来,因为它需要一个产品决策而不只是一个 gate。

?sort=owner_ref.title —— 点号路径 —— 仍然是 200 + 未排序的行,没有任何报错。

实测

真引擎 + 真 registry,probe_taskowner_ref(lookup)字段:

?sort=owner_ref.title   -> 200,ids ["t1","t2","t3"](插入顺序,排序未生效)
?sort=no_such.title     -> 400 INVALID_SORT                                  ✅

为什么会这样(不是疏忽,是分层的结果)

assertSortFieldsExist头段判定字段是否存在 —— 与 engine.find() 校验投影的方式一致,也与 #4134 的隐式 filter gate 一致。owner_ref 是真实字段,所以 owner_ref.title 过闸;no_such.title 的头段不存在,所以被拦下。

过闸之后交给 driver,SqlDriver 把点号路径原样交给 Knex,渲染成 "owner_ref"."title",数据库报 unknown column,driver 的兜底重试丢掉排序重跑(objectstack#3821:行比行的顺序重要)。于是:查询成功,行全在,顺序是任意的。

这一条已经写进 content/docs/protocol/objectql/query-syntax.mdx 的告警里(PR #4240 补的),所以它是已记录的行为,不是未知的坑。但它仍然是 #3948 意义上的静默降级 —— 而且是 sort 轴上最后一个。

危害与已修的那些同级

sort + top 是取「最新 N 条」的写法。?sort=-account.created_at&top=10 拿到的是任意 10 条,与 #4226 修掉的那些在调用方视角下没有区别。

三条路,需要决策

  1. 在 ingress 拒绝跨表排序 —— 400 INVALID_SORT,消息说明「排序只能作用于本表的列,请用公式/汇总字段把值反范式化到本对象上」(正是 query-syntax.mdx 现在给的建议)。最小、与 REST 列表:sort / select / expand 指向不存在的字段时被静默丢弃(filter 轴已收口,这三条轴还没有) #4226 一致,但会让今天静默不排序的调用方开始收到 400
  2. 真正实现关联排序 —— join 或子查询。最贵,而且 expand 走的是批量 $in 二次读而非 join,与现有架构不合。
  3. 维持现状 —— 已记录在案,不再动。

我倾向 1#4226 的整个论证就是「一个没生效的表达式不该看起来像生效了」,把唯一的例外留下需要一个理由,而「实现起来贵」不是那个理由 —— 拒绝很便宜。但这条会改变现有调用方的行为,所以不该由实现者单方面决定。

需要先量一下影响面:有多少地方在发点号路径的 sort(objectui 的视图配置、保存的报表、sys_saved_report 里的存量数据),再决定是直接拒还是先加一轮 deprecation 告警。

关联

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions