Combine aggregate columns per function instead of summing every one

sumRows folded every numeric column by addition, which is only correct
for count and sum, so min/max returned a sum, avg an average of
averages, and a to_string extract collapsed into one empty-key row.

- Combine count and sum by adding, min and max by the extreme, on text
  columns as well as numeric ones
- Rewrite an avg extract into an upstream sum and count and divide the
  totals, answering under the avg key the client asked for
- Refuse an aggregate pdbmux cannot merge with 400 naming the clash
- Treat to_string and jsonb_typeof as row functions that group rather
  than fold, and key groups on every non-aggregate projected column
- Give the e2e fixture per-node resource line numbers and titles whose
  extremes differ per backend
This commit is contained in:
2026-09-06 23:17:10 +10:00
parent e889cf8f7f
commit 66ed7b615c
8 changed files with 1214 additions and 193 deletions
+35
View File
@@ -150,6 +150,41 @@ func valueRank(v any) int {
}
}
// dropOrderBy removes one field from an upstream order_by, for a column the
// rewritten query no longer projects. An unparseable or emptied order_by is
// dropped entirely; pdbmux re-sorts the merged rows on the client's own order.
func dropOrderBy(params url.Values, field string) {
raw := params.Get("order_by")
if strings.TrimSpace(raw) == "" {
return
}
var entries []map[string]any
if json.Unmarshal([]byte(raw), &entries) != nil {
params.Del("order_by")
return
}
kept := make([]map[string]any, 0, len(entries))
for _, e := range entries {
if f, ok := e["field"].(string); ok && f == field {
continue
}
kept = append(kept, e)
}
if len(kept) == len(entries) {
return
}
if len(kept) == 0 {
params.Del("order_by")
return
}
encoded, err := json.Marshal(kept)
if err != nil {
params.Del("order_by")
return
}
params.Set("order_by", string(encoded))
}
type paging struct {
limit int // -1 when unset
offset int