You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Platform half of server-side list-view grouping: pin the compiled group-header and row-page queries through the existing POST /data/:object/query door (driver-sql + in-memory) #15330
Filed by the domain:spec seat (session_01H2oQebDDxYKfWZusyd8GXk, seat post #6017) at the ACCEPT of #14556's spec half (PR #15284, review comment 5540162483 on #14556), as the card's item 2 — the platform half of maintainer ruling A on objectui#7189 (2026-09-02, 「7189 A 其他同意」: grouping on a list view is server-side; the groups and every header number are query properties, rows within a group are paged). Filed unassigned for triage's domain:* (the fix lands in packages/rest / packages/objectql test surfaces, not in packages/spec).
What the spec half delivered (lands with PR #15284)
@objectstack/spec/ui exports compileListViewGroupQuery(view, { where?, depth? }) → EngineAggregateOptions (the group-header query: groupBy = grouping.fields[].field in nesting order, a fieldless count node aliased count, the view's column summaries mapped onto AggregationFunction, the four derived members as one count_<field> node each, where = the view's composed filter) and compileListViewGroupRowsQuery(view, groupKey, { where?, limit?, offset?, orderBy?, fields? }) → EngineQueryOptions (the per-group row page: { $and: [viewWhere, …keyPredicates] }, $null for the empty group), plus deriveColumnSummary(row, summary, field) for count_filled / count_empty / percent_filled / percent_empty on a header row. Pinned on the 186-row five-unit fixture (86/61/31/7/1 in both row orders) against a test-local reducer — not yet against a platform face.
The door already exists — no new route, no new wire shape
Measured on origin/main6e67b86c (2026-09-04): POST /data/:object/query (packages/rest/src/rest-server.ts:7947-7994) hands a body carrying groupBy / aggregations to protocol.findData (packages/metadata-protocol/src/protocol.ts:10293-10322), which routes it to engine.aggregate and answers { object, records, total, hasMore } with the header rows as records; client.data.query() (packages/client/src/index.ts:5321-5330) already posts there; the RPC face declares method: 'aggregate' with an EngineAggregateOptions body (data-engine.zod.ts:720-725). The seat's earlier claim that no aggregate door existed was false and is corrected on #14556 (5538128398). So this card mints nothing.
Deliverable
A REST-level (or dogfood) pin that posts the compiled header query and the compiled row page of the spec fixture's list view through POST /data/:object/query and asserts the five header rows (count 86/61/31/7/1) in both row orders, a two-level groupBy, the depth: 1 outer level, the empty group via $null, and one derived summary (count_filled of a nullable field) — on driver-sql and on the in-memory tier (the engine's dispatch at packages/objectql/src/engine.ts:13323 decides which face runs; both must agree).
A pin that limit / offset on the row page slice inside one group (86 rows page as [50, 36] with 86 distinct ids).
objectui's plugin-grid consuming the header rows and stopping page-scoped grouping — objectui#7189 (card item 3; unblocked by a spec publish carrying view-grouping-query). Any orderBy / limit on the aggregate verb for high-cardinality groupings — a separate engine-contract card if ever needed (recorded as a known limit on GroupingConfigSchema).
Dedupe (2026-09-04): the seat's reads of the lane queue and the open PR list carry no card for a REST/dogfood pin of the grouping queries; the nearest neighbours are #14556 (the spec half) and objectui#7189 (the ui half).
Filed by the
domain:specseat (session_01H2oQebDDxYKfWZusyd8GXk, seat post #6017) at the ACCEPT of #14556's spec half (PR #15284, review comment 5540162483 on #14556), as the card's item 2 — the platform half of maintainer ruling A on objectui#7189 (2026-09-02, 「7189 A 其他同意」: grouping on a list view is server-side; the groups and every header number are query properties, rows within a group are paged). Filed unassigned for triage'sdomain:*(the fix lands inpackages/rest/packages/objectqltest surfaces, not inpackages/spec).Blocked-by: #14556
What the spec half delivered (lands with PR #15284)
@objectstack/spec/uiexportscompileListViewGroupQuery(view, { where?, depth? })→EngineAggregateOptions(the group-header query:groupBy=grouping.fields[].fieldin nesting order, a fieldlesscountnode aliasedcount, the view's column summaries mapped ontoAggregationFunction, the four derived members as onecount_<field>node each,where= the view's composed filter) andcompileListViewGroupRowsQuery(view, groupKey, { where?, limit?, offset?, orderBy?, fields? })→EngineQueryOptions(the per-group row page:{ $and: [viewWhere, …keyPredicates] },$nullfor the empty group), plusderiveColumnSummary(row, summary, field)forcount_filled/count_empty/percent_filled/percent_emptyon a header row. Pinned on the 186-row five-unit fixture (86/61/31/7/1 in both row orders) against a test-local reducer — not yet against a platform face.The door already exists — no new route, no new wire shape
Measured on
origin/main6e67b86c(2026-09-04):POST /data/:object/query(packages/rest/src/rest-server.ts:7947-7994) hands a body carryinggroupBy/aggregationstoprotocol.findData(packages/metadata-protocol/src/protocol.ts:10293-10322), which routes it toengine.aggregateand answers{ object, records, total, hasMore }with the header rows asrecords;client.data.query()(packages/client/src/index.ts:5321-5330) already posts there; the RPC face declaresmethod: 'aggregate'with anEngineAggregateOptionsbody (data-engine.zod.ts:720-725). The seat's earlier claim that no aggregate door existed was false and is corrected on #14556 (5538128398). So this card mints nothing.Deliverable
POST /data/:object/queryand asserts the five header rows (count86/61/31/7/1) in both row orders, a two-levelgroupBy, thedepth: 1outer level, the empty group via$null, and one derived summary (count_filledof a nullable field) — on driver-sql and on the in-memory tier (the engine's dispatch atpackages/objectql/src/engine.ts:13323decides which face runs; both must agree).limit/offseton the row page slice inside one group (86 rows page as[50, 36]with 86 distinct ids).aggregation-conformance.ts), reported back on List-view grouping is server-side: group set and per-group counts come from an aggregate query, rows within a group are paged (objectui#7189 ruling A) #14556 before changing a spec pin.Not this card
objectui's
plugin-gridconsuming the header rows and stopping page-scoped grouping — objectui#7189 (card item 3; unblocked by a spec publish carryingview-grouping-query). AnyorderBy/limiton the aggregate verb for high-cardinality groupings — a separate engine-contract card if ever needed (recorded as a known limit onGroupingConfigSchema).Dedupe (2026-09-04): the seat's reads of the lane queue and the open PR list carry no card for a REST/dogfood pin of the grouping queries; the nearest neighbours are #14556 (the spec half) and objectui#7189 (the ui half).