Skip to content

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

Closed

Description

@os-zhuang

TL;DR

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

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

实测

真引擎 + 真 registry,probe_task 有 owner_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

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions