Thread resolved parameters through codegen and sort

What does this MR do and why?

This is MR 4 of 5 for parameterised field syntax.

MR 3 (!408 (merged)) added analyzer-level resolution that converts FieldFunction("finished", [Positional("daily")]) to ParameterizedField(Finished, [("granularity", "daily")]) and applies default parameter values to bare parameterisable fields. But the codegen layer completely ignored those resolved parameters: render_display_field dropped the Vec<(String, String)> by calling display_field.name(), then render_query_field matched on the bare string and always substituted hardcoded defaults. Similarly, graphql_sort_parameters always returned hardcoded {granularity: "weekly"} or {quantile: 0.95} regardless of what the user specified.

This MR threads the resolved parameters through both field codegen and sort codegen, giving users actual control over granularity and quantile values for the first time.

Field codegen

render_display_field now matches on ParameterizedField variants and renders the field name with its resolved parameters directly (e.g. finishedAt(granularity: "daily"), durationQuantile(quantile: 0.5)), recursing through AliasedDisplayField wrappers. For non-parameterised variants, rendering delegates to render_query_field as before.

The hardcoded startedAt, finishedAt, and durationQuantile match arms in PipelinesAnalyticsAnalyzer::render_query_field are removed since these fields are always ParameterizedField after resolution.

Sort parameter inheritance

Sort inherits parameters from the matching resolved dimension or metric rather than relying on per-source hardcoded values. For each sort field, build_aggregated_params looks up the corresponding ParameterizedField in dimensions/metrics by comparing base_field().dealias(), then passes the inherited (key, value) pairs through the graphql_sort_parameters trait method for source-level customisation.

The trait method signature changes from fn graphql_sort_parameters(&self, sort: &Sort) -> Option<&'static str> to fn graphql_sort_parameters(&self, sort: &Sort, inherited_params: &[(String, String)]) -> Vec<(String, String)>, returning structured data rather than a pre-formatted GraphQL string. The default passes inherited parameters through unchanged; sources can override to filter, transform, or extend parameters if needed. The PipelinesAnalyticsAnalyzer override is removed since the default does the right thing.

Code suggestions fix

This MR also fixes a latent bug where code suggestions sort by timestamp silently omitted the required granularity parameter because graphql_sort_parameters returned None for code suggestions. The backend requires parameters: {granularity: "monthly"} in the sort orderBy entry, and the new inheritance mechanism provides it automatically from the resolved dimension.

What this MR does NOT do

Compile output metadata (exposing resolved parameters per field in the serialised output) is deferred to MR 5.

References

How to set up and validate locally

  1. cargo test -- all 696 tests should pass
  2. cargo clippy -- should be clean
  3. cargo fmt --check -- should be clean

Manual testing via the Ruby extension

Build the native extension (re-run after any Rust changes):

cd glql_rb
bundle install
bundle exec rake compile

User-specified granularity flows through to GraphQL

mode: analytics
query: type = Pipeline and project = "gitlab-org/gitlab" and finished > -30d
dimensions: finished(daily), status
metrics: totalCount, successRate
sort: finished desc
Test via ruby extension
GLQL_QUERY='type = Pipeline and project = "gitlab-org/gitlab" and finished > -30d'

echo "q = Glql.compile('${GLQL_QUERY}', { mode: 'analytics', dimensions: 'finished(daily), status', metrics: 'totalCount, successRate', sort: 'finished desc' })[\"output\"]; puts q; exit" | bundle exec rake console

Expected: The GraphQL output should contain finishedAt(granularity: "daily") in the dimensions block and parameters: {granularity: "daily"} in the orderBy entry.

Default granularity still works for bare dimensions

mode: analytics
query: type = Pipeline and project = "gitlab-org/gitlab" and finished > -30d
dimensions: finished, status
metrics: totalCount
sort: finished desc
Test via ruby extension
GLQL_QUERY='type = Pipeline and project = "gitlab-org/gitlab" and finished > -30d'

echo "q = Glql.compile('${GLQL_QUERY}', { mode: 'analytics', dimensions: 'finished, status', metrics: 'totalCount', sort: 'finished desc' })[\"output\"]; puts q; exit" | bundle exec rake console

Expected: The GraphQL output should contain finishedAt(granularity: "weekly") (the default) and parameters: {granularity: "weekly"} in the orderBy.

Custom quantile value

mode: analytics
query: type = Pipeline and project = "gitlab-org/gitlab" and finished > -30d
dimensions: ref
metrics: totalCount, durationQuantile(0.5)
sort: durationQuantile desc
Test via ruby extension
GLQL_QUERY='type = Pipeline and project = "gitlab-org/gitlab" and finished > -30d'

echo "q = Glql.compile('${GLQL_QUERY}', { mode: 'analytics', dimensions: 'ref', metrics: 'totalCount, durationQuantile(0.5)', sort: 'durationQuantile desc' })[\"output\"]; puts q; exit" | bundle exec rake console

Expected: The GraphQL output should contain durationQuantile(quantile: 0.5) in the metrics and parameters: {quantile: 0.5} in the orderBy.

Code suggestions timestamp renders with granularity

mode: analytics
query: type = CodeSuggestion and timestamp >= -3m
dimensions: timestamp, language
metrics: totalCount
sort: timestamp desc
Test via ruby extension
GLQL_QUERY='type = CodeSuggestion and group = "gitlab-duo" and timestamp >= -3m'

echo "q = Glql.compile('${GLQL_QUERY}', { mode: 'analytics', dimensions: 'timestamp, language', metrics: 'totalCount', sort: 'timestamp desc' })[\"output\"]; puts q; exit" | bundle exec rake console

Expected: The GraphQL output should contain timestamp(granularity: "monthly") in the dimensions block and parameters: {granularity: "monthly"} in the orderBy. Previously, timestamp rendered as a bare field name and sort had no parameters block.

Edited by Robert Hunt

Merge request reports

Loading