Skip to content

finding: driver-mongodb still lowers array_agg / string_agg — retired from AggregationFunction at #6188, refused by both SQL faces #13075

Description

@os-zhuang

Found while fixing #12818 in the same function (buildAccumulator). Filed unassigned, not fixed — that dispatch scoped the work to the default arm, and this is a second accept-face narrowing with its own changeset and its own argument.

What was read

packages/drivers/driver-mongodb/src/mongodb-aggregation.ts, buildAccumulator, carries two arms for names the Query Protocol no longer declares:

case'array_agg':
return{$push: fieldRef??'$$ROOT'};case'string_agg':
// Collect into array; caller can post-process with $reducereturn{$push: fieldRef??''};

and postProcessAggregation carries the matching string_agg join.

AggregationFunction (packages/spec/src/data/query.zod.ts) declares six values — count, sum, avg, min, max, count_distinct. array_agg and string_agg were removed at #6188 under ADR-0049 enforce-or-remove, and the enum's own error map hands each a retirement prescription. packages/spec/src/data/query.test.ts pins the six.

The divergence

Both SQL faces already treat these two as class-1 undeclared names and refuse them with INVALID_QUERY / 400:

driver-mongodb is the only face that still answers them. So one query gets a 400 on two backends and a $push array on the third — the local/remote fork #5907 exists to prevent, one vocabulary later.

Measured, without a server (mongodb-pipeline-evaluator.testkit.ts over AGGREGATION_ROWS): { function: 'array_agg', field: 'score' } answers [10, 20, 30, 40, 50, 60], and string_agg the same array before postProcessAggregation joins it. Both are pinned as current behaviour by mongodb-unrecognised-aggregate-function.test.ts (the "recorded, not fixed" block) so this divergence cannot be mistaken for an oversight in that file, and so whichever way it is decided, the pin moves deliberately.

Why it is worth a card rather than a silent cleanup

Reachability is the part that needs deciding rather than assuming. AggregationNodeSchema.function is the enum, so the protocol door rejects both spellings before they reach any driver; what can still reach buildAggregationPipeline is a direct caller of this exported builder, or the driver's own aggregate, which reads its aggregations through (query as any).aggregations. That is the same population #12818's refusal was written for.

Dispositions, for triage:

  • (a) delete both arms and let them fall to finding: driver-mongodb answers an unrecognised aggregate function as a silent SUM instead of refusing it #12818's class-1 refusal (400), matching both SQL faces. It also falsifies the converts string_agg arrays to joined strings case in mongodb-aggregation.test.ts, which would be INVERTED in place (asserting the refusal) rather than re-baselined, and postProcessAggregation's string_agg limb would go with them.
  • (b) keep them as a deliberate mongodb-only extension, and say so in the code — at which point the "one condition, one wording" parity note in driver-sql should record the exception.

(a) is the ADR-0049 direction and the one I would take, but it removes something a caller could be using today, so it is a vocabulary decision rather than a repair.

What was NOT established

Related: #12818 (the default arm, being fixed now), #6188 (the retirement), #7052 (the same interface's distinct?: boolean leftover after the same class of spec retirement — closed), #5907 (the two-class refusal these faces share).

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions