Support sort-by-alias and aliased duplicate parameterised fields
Problem
GLQL's sort pipeline has no awareness of user-defined aliases (as "Name"). The sort field is parsed independently from fields/dimensions/metrics via Field::from(&str), which only resolves hardcoded field name synonyms (e.g. dueDate -> Due). User-defined aliases are a display-layer concept that sort never cross-references.
This means:
- Standard mode:
fields: title as "Name",sort: Namedoes not sort by title. It either resolves toField::Name(a different field entirely) or errors as unrecognized. - Analytics mode:
dimensions: finished(weekly) as "Week",sort: WeekproducesUnknownField("Week")and fails sort coupling validation.
This gap blocks a specific use case: aliased duplicate parameterised fields. After !411 (merged), metrics: durationQuantile(0.5), durationQuantile(0.8) is correctly rejected as ambiguous. The natural fix is aliases (durationQuantile(0.5) as "p50", durationQuantile(0.8) as "p80"), but sort: p50 can't work without sort-by-alias support.
Proposal
Add alias resolution to the sort pipeline so that sort field names are matched against user-defined aliases in the selected fields list. This is a cross-cutting change that benefits all modes, not just analytics parameterised fields.
Sort alias resolution (all modes)
The sort pipeline needs a resolution step that cross-references sort field names against the aliases in the compiled fields/dimensions/metrics lists. If sort: p50 doesn't match a known Field variant, check whether any selected field has alias "p50" and resolve to that field.
This likely means:
- A new resolution pass after sort parsing and field compilation, before sort validation
- The
Sortstruct may need to carry the resolvedDisplayFieldreference (or at least the resolvedField) rather than just the raw parsedField validate_sort_coupling(analytics) and the standard sort validator both need to accept alias-resolved sorts
Analytics-specific: accept aliased duplicates
Once sort-by-alias works, the duplicate check from !411 (merged) can be relaxed to accept duplicates when each instance has a unique alias:
key()(src/types/display_field.rs):AliasedDisplayFieldreturns the alias as the key, producing unique keys for aliased duplicates.- GraphQL codegen (
src/codegen/graphql.rs): Emit GraphQL field aliases (e.g.p50: durationQuantile(quantile: 0.5)) when the outerAliasedDisplayFieldwraps aParameterizedField. - Transform layer (
src/transformer/field_functions.rs): Extract data using the alias as the GraphQL response key. - Validation (
src/analyzer/analytics.rs): Change the duplicate check to usekey()instead ofbase_field().
Estimated effort
~100-150 lines across 6-8 files, ~20-25 test cases. The sort alias resolution is the foundational piece; the analytics duplicate relaxation builds on top.
References
- Parent issue: #130 (closed)
- Duplicate rejection: !411 (merged) / #152 (closed)
- Raised in !409 (merged) review: !409 (comment 3485473582)