Add GLQL parser support for CodeSuggestion analytics mode
Add GLQL parser support for querying CodeSuggestion analytics using `mode: analytics` syntax. **Epic:** gitlab-org&21212 Add CodeSuggestion aggregations to GLQL **Milestone:** 18.11 **Depends on:** gitlab#589608 (GraphQL mounting - MR !226274) **Related:** #592262 (UI), #592264 (Documentation) ## Example Query ```yaml mode: analytics query: type = CodeSuggestion and timestamp >= -30d dimensions: - language as "Language" - timeSegment(1w) on timestamp as "Week" metrics: - totalCount as "Total Suggestions" - acceptanceRate as "Acceptance Rate" - usersCount as "Active Users" sort: acceptanceRate desc limit: 10 ``` ## Background CodeSuggestions is the **first aggregation-based source type** in GLQL using GitLab's aggregation framework. Unlike standard sources (Issues, MergeRequests), it requires: - Nested GraphQL path: `aiUsage { codeSuggestions { aggregated { } } }` - Two-level structure: filters at outer level, sort/pagination at inner `aggregated` connection - Separation of dimensions (groupable) vs metrics (aggregatable) ### GraphQL Schema Reference Backend: `Analytics::AggregationEngines::CodeSuggestions` ([view engine](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/analytics/aggregation_engines/code_suggestions.rb)) **Filters:** `userId`, `language`, `ideName`, `timestampFrom`, `timestampTo` **Dimensions:** `user`, `language`, `ideName`, `timestamp(granularity)` **Metrics:** `totalCount`, `usersCount`, `acceptanceRate`, `suggestionSizeSum`, `acceptedCount`, `rejectedCount`, `shownCount` ## Implementation Plan ### Key Decisions | Aspect | Decision | Rationale | | -------------------- | ---------------------------------- | ----------------------------------------------------- | | **Field naming** | Exact 1:1 with GraphQL | `acceptanceRate` not `acceptance`, `totalCount` not `count` | | **Timestamp syntax** | `timeSegment(Xd/w/m/q/y)` | Maps to `timestamp(granularity: "...")` | | **Analytics mode** | Explicit `mode: analytics` required | Prevents ambiguity, clear validation | | **User dimension** | Auto-expand to all UserCore fields | `{ id, username, name, avatarUrl, webUrl }` for avatars | | **Nested paths** | Trait-based `parent_scope()` method | Extensible for future AI/analytics sources | | **Sort fields** | Allow dimensions AND metrics | Maximum flexibility | | **Field categorization** | Hardcoded per source analyzer | Follows existing Issues/MergeRequests pattern | ### Critical Gotchas **1. Nested GraphQL Path** First source requiring parent scope nesting. Add `parent_scope() -> Option<&str>` and `source_query_name() -> &str` to `SourceAnalyzer` trait. **2. Aggregated Connection** The `aggregated { }` wrapper is auto-generated by backend framework. GLQL must generate: `codeSuggestions(...filters) { aggregated(...sort) { nodes { dimensions {...} ...metrics } } }` **3. Dimensions vs Metrics Structure** - Dimensions: Go in `dimensions { }` block (for GROUP BY) - Metrics: Go at node level (calculated values) - Add `field_category()` method to trait returning `Dimension | Metric | Standard` **4. User Field Dual Nature** - As filter: `userId: [Int!]` (array) - As dimension: `user { id, username, name, avatarUrl, webUrl }` (object) **5. Filter Mapping** `user` → `userId`, `timestamp >=` → `timestampFrom`, `timestamp <=` → `timestampTo` **6. Analytics Mode Validation** Error cases: - `dimensions`/`metrics` without `mode: analytics` - `mode: analytics` without `dimensions`/`metrics` - `fields` property with `mode: analytics` (incompatible) ### Files Requiring Changes **GLQL Rust Compiler** ([gitlab-org/glql](https://gitlab.com/gitlab-org/glql)): - `src/types/source.rs` - Add `CodeSuggestions` variant - `src/types/field.rs` - Add 11 new fields (Language, IdeName, Timestamp, User, + 7 metrics) - `src/analyzer/sources/mod.rs` - Update trait: add `parent_scope()`, `source_query_name()`, `field_category()` - `src/analyzer/sources/code_suggestions.rs` - **NEW** Create analyzer implementation - `src/codegen/graphql.rs` - Handle nested paths + aggregated wrapper generation - `src/codegen/graphql_filters.rs` - Map filters to GraphQL arguments - `src/transformer/data.rs` - Flatten `dimensions { }`, extract metrics from nodes - `tests/code_suggestion_tests.rs` - **NEW** Comprehensive test coverage **GitLab Rails** ([gitlab-org/gitlab](https://gitlab.com/gitlab-org/gitlab)): - `config/feature_flags/gitlab_com_derisk/glql_code_suggestion_analytics_aggregation.yml` - **NEW** Feature flag - `Gemfile` - Update `gitlab_query_language` gem version - `ee/spec/requests/api/graphql/glql/code_suggestions_spec.rb` - **NEW** Integration tests ## Available Fields Reference ### Filters (Outer Level) | GLQL Field | GraphQL Argument | Type | Notes | | ------------ | ---------------- | --------- | ----------------- | | `user` | `userId` | `[Int!]` | Plural in GraphQL | | `language` | `language` | `[String!]` | Array | | `ideName` | `ideName` | `[String!]` | Array | | `timestamp >=` | `timestampFrom` | `Time` | Range start | | `timestamp <=` | `timestampTo` | `Time` | Range end | ### Dimensions (Groupable) | GLQL Field | GraphQL Field | Type | Parameters | Notes | | ---------- | ------------- | -------- | ----------- | --------------------------------------------------------- | | `user` | `user` | UserCore | - | Auto-expands to `{ id, username, name, avatarUrl, webUrl }` | | `language` | `language` | String | - | Programming language | | `ideName` | `ideName` | String | - | IDE name | | `timestamp` | `timestamp` | Date | `granularity` | Use `timeSegment(Xd/w/m/q/y)` syntax | ### Metrics (Aggregatable) | GLQL Field | GraphQL Field | Type | Description | | ----------------- | ----------------- | ----- | ----------------- | | `totalCount` | `totalCount` | Int | Total suggestions | | `usersCount` | `usersCount` | Int | Unique users | | `acceptanceRate` | `acceptanceRate` | Float | Accepted / shown | | `suggestionSizeSum` | `suggestionSizeSum` | Int | Total volume | | `acceptedCount` | `acceptedCount` | Int | Accepted count | | `rejectedCount` | `rejectedCount` | Int | Rejected count | | `shownCount` | `shownCount` | Int | Shown count | ## Feature Flag **Name:** `glql_code_suggestion_analytics_aggregation` **Type:** `gitlab_com_derisk` **Purpose:** Gates CodeSuggestion analytics functionality **Rollout:** Remove flag in same milestone per epic guidance ## Acceptance Criteria **GLQL Repository** ([gitlab-org/glql](https://gitlab.com/gitlab-org/glql)): - [ ] `CodeSuggestionsSourceAnalyzer` implements trait with `parent_scope()`, `source_query_name()`, `field_category()` - [ ] Code generator creates correct nested GraphQL: `aiUsage { codeSuggestions { aggregated { } } }` - [ ] Dimensions generate `dimensions { }` block, metrics at node level - [ ] Sort validation works for both dimensions and metrics - [ ] Filter mapping handles `user` → `userId`, timestamp ranges - [ ] `timeSegment()` syntax parses and maps to GraphQL granularity - [ ] Analytics mode validation catches all error cases - [ ] Parser tests cover all fields, filters, dimensions, metrics - [ ] Transformer flattens aggregated responses correctly - [ ] No regressions in existing sources **GitLab Repository** ([gitlab-org/gitlab](https://gitlab.com/gitlab-org/gitlab)): - [ ] Feature flag `glql_code_suggestion_analytics_aggregation` created (type: `gitlab_com_derisk`) - [ ] Update `gitlab_query_language` gem dependency - [ ] Integration tests verify end-to-end query execution - [ ] Feature flag gates functionality correctly ## Notes for Related Issues **For #592262 (UI Integration):** - User dimension auto-expands to `{ id, username, name, avatarUrl, webUrl }` for avatar rendering - Exact field names: `acceptanceRate`, `usersCount`, `totalCount`, etc. - Available dimensions: `user`, `language`, `ideName`, `timestamp` - Available metrics: `totalCount`, `usersCount`, `acceptanceRate`, `suggestionSizeSum`, `acceptedCount`, `rejectedCount`, `shownCount` **For #592264 (Documentation):** - Document `timeSegment(Xd/w/m/q/y)` syntax for timestamp granularity - Document analytics mode validation rules - Provide example queries for common use cases - Document feature flag requirement - Document exact field naming conventions ## Example Queries for Testing **Basic Analytics:** ```yaml type: CodeSuggestion mode: analytics query: timestamp >= -30d dimensions: - language as "Language" metrics: - totalCount as "Total" - acceptanceRate as "Rate" sort: totalCount desc limit: 10 ``` **Time Bucketing:** ```yaml type: CodeSuggestion mode: analytics query: timestamp >= -90d dimensions: - timeSegment(1w) on timestamp as "Week" - language as "Language" metrics: - totalCount as "Total" - usersCount as "Users" sort: timestamp asc ``` **Filter + Group:** ```yaml type: CodeSuggestion mode: analytics query: timestamp >= -30d and ideName = "vscode" and language = "ruby" dimensions: - user as "Developer" metrics: - totalCount as "Total" - acceptedCount as "Accepted" - acceptanceRate as "Rate" sort: acceptanceRate desc limit: 20 ```
issue