Port PostgreSQL GraphQL groupby/aggregation + related features to release/2.0 - #3767
Merged
Conversation
naxing123
requested review from
Alekhya-Polavarapu,
Aniruddh Munde (Aniruddh25),
Jerry Nixon (JerryNixon),
RubenCerna2079,
aaronburtle,
Anusha Kolan (anushakolan),
rusamant,
Sourabh Jain (sourabh1007),
Souvik Ghosh (souvikghosh04),
Stuart Padley (stuartpa) and
vadeveka
as code owners
August 11, 2026 21:17
Contributor
There was a problem hiding this comment.
Pull request overview
Ports PostgreSQL GraphQL groupBy/aggregation support (plus related config/runtime fixes), PostgreSQL PUT/PATCH database policy behavior, and PostgreSQL DateTime filter handling from main back onto release/2.0, with corresponding updates to core query generation/execution and the test suite.
Changes:
- Enable/extend GraphQL aggregation (groupBy + aggregate functions) support to PostgreSQL, including deterministic ordering for groupBy results and correct mapped-column handling.
- Add PostgreSQL support for database policies on PUT/PATCH upsert paths (distinguishing “row missing” vs “policy blocked” via multi-result-set handling).
- Add PostgreSQL-specific parameter type casting for date/time filters and expand tests/snapshots/config/schema to cover the new behaviors.
Reviewed changes
Copilot reviewed 33 out of 33 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/Service.Tests/UnitTests/ConfigValidationUnitTests.cs | Updates config validation expectations for PostgreSQL create policy support and minor comment cleanup. |
| src/Service.Tests/SqlTests/SqlTestBase.cs | Fixes REST API wording and “Postgres” naming in doc comments. |
| src/Service.Tests/SqlTests/RestApiTests/Put/PostgreSqlPutApiTests.cs | Enables PUT database policy insert coverage for PostgreSQL (removes ignored stubs; adds expected SQL). |
| src/Service.Tests/SqlTests/RestApiTests/Patch/PostgreSqlPatchApiTests.cs | Enables PATCH database policy insert coverage for PostgreSQL (removes ignored stubs; adds expected SQL). |
| src/Service.Tests/SqlTests/RestApiTests/Find/FindApiTestBase.cs | Normalizes REST API phrasing and trims trailing whitespace in comments. |
| src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs | Adjusts PostgreSQL JSON aggregation handling (COALESCE) and enables DateTime-related coverage by removing a skip. |
| src/Service.Tests/SqlTests/GraphQLQueryTests/PostgreSqlGraphQLQueryTests.cs | Enables/extends PostgreSQL aggregation & groupBy GraphQL tests and adds mapped-column groupBy/aggregation scenarios. |
| src/Service.Tests/SqlTests/GraphQLQueryTests/MsSqlGraphQLQueryTests.cs | Adds mapped-column regression tests for groupBy/aggregations and makes groupBy ordering deterministic. |
| src/Service.Tests/SqlTests/GraphQLQueryTests/DwSqlGraphQLQueryTests.cs | Adds mapped-column groupBy regression tests and formatting/order determinism improvements. |
| src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForPostgreSql.verified.txt | Updates runtime config snapshot for PostgreSQL database policies and new DateOnlyTable entity. |
| src/Service.Tests/GraphQLBuilder/QueryBuilderTests.cs | Adds unit coverage for aggregation enablement (including PostgreSQL) and groupBy field presence/absence. |
| src/Service.Tests/DatabaseSchema-PostgreSql.sql | Adds date_only_table seed data and small formatting fixes. |
| src/Service.Tests/DatabaseSchema-MsSql.sql | Adds SET QUOTED_IDENTIFIER ON; and formatting fixes for seed scripts. |
| src/Service.Tests/dab-config.PostgreSql.json | Updates PostgreSQL config to include create database policy and adds DateOnlyTable entity. |
| src/Service.Tests/Configuration/RuntimeConfigLoaderTests.cs | Adds unit tests for EnableAggregation defaulting behavior and explicit config handling. |
| src/Service.Tests/Configuration/ConfigurationTests.cs | Updates assertions to match improved metadata-provider error messages. |
| src/Service.GraphQLBuilder/Sql/SchemaConverter.cs | Clarifies authorize-directive parameter docs. |
| src/Service.GraphQLBuilder/Queries/QueryBuilder.cs | Enables aggregation schema features for PostgreSQL via AggregationEnabledDatabaseTypes. |
| src/Service.GraphQLBuilder/GraphQLTypes/SupportedTypes.cs | Refines supported datetime type modeling/comments and datetimeoffset handling. |
| src/Core/Services/MetadataProviders/SqlMetadataProvider.cs | Improves exception messages (“database object … not inferred”) and clarifies schema-fill doc comment. |
| src/Core/Services/GraphQLSchemaCreator.cs | Fixes aggregation flag hot-reload, refactors role lookup loop, and uses safer DocumentNode definition merging. |
| src/Core/Resolvers/SqlPaginationUtil.cs | Fixes groupBy response shaping to distinguish fields vs aggregations by aggregation aliases. |
| src/Core/Resolvers/SqlMutationEngine.cs | Refines PUT/PATCH mutation result handling and error pathways for policy/not-found scenarios. |
| src/Core/Resolvers/Sql Query Structures/SqlQueryStructure.cs | Ensures groupBy selects use backing column names with exposed labels and adds deterministic order defaulting for groupBy. |
| src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs | Adds PostgreSQL-only parameter type coercion (notably DateTime handling for timestamp comparisons). |
| src/Core/Resolvers/PostgresQueryBuilder.cs | Adds PostgreSQL groupBy/aggregation query generation and extends upsert/insert generation for create/update policy semantics. |
| src/Core/Resolvers/PostgreSqlExecutor.cs | Implements multi-result-set handling for PostgreSQL upsert to return correct 403/404 outcomes for policies vs missing rows. |
| src/Core/Resolvers/BaseTSqlQueryBuilder.cs | Removes duplicated groupBy/having/order/aggregation helpers (now centralized). |
| src/Core/Resolvers/BaseSqlQueryBuilder.cs | Centralizes shared groupBy/having/order/aggregation SQL builders (used across engines). |
| src/Core/Configurations/RuntimeConfigValidator.cs | Adds PostgreSQL to the set of database types supporting create policies. |
| src/Config/ObjectModel/RuntimeConfig.cs | Fixes EnableAggregation default logic (enabled when runtime/graphql sections are absent) and updates docs. |
| schemas/dab.draft.schema.json | Adds runtime.graphql.enable-aggregation to schema and documents it. |
| config-generators/postgresql-commands.txt | Updates generator commands to reflect separate create/update policies and adds DateOnlyTable. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
aaronburtle
approved these changes
Aug 12, 2026
naxing123
enabled auto-merge (squash)
August 12, 2026 02:14
Anusha Kolan (anushakolan)
approved these changes
Aug 12, 2026
… section is absent (#3450) ## Why make this change? GraphQL aggregation features (`groupBy`, `sum`, `avg`, `min`, `max`, `count`) were silently disabled for users whose config lacked an explicit `runtime.graphql` section, even though `EnableAggregation` defaults to `true`. ## What is this change? **Bug fix: `RuntimeConfig.EnableAggregation` logic inversion** The property used `&&` logic, returning `false` when `Runtime` or `Runtime.GraphQL` was `null`. This is inconsistent with every analogous property (e.g. `IsGraphQLEnabled`) which use `||` logic to treat absence as "use default (enabled)": ```csharp // Before (broken): returns false when runtime.graphql section is absent public bool EnableAggregation => Runtime is not null && Runtime.GraphQL is not null && Runtime.GraphQL.EnableAggregation; // After (fixed): returns true when section is absent, consistent with IsGraphQLEnabled public bool EnableAggregation => Runtime is null || Runtime.GraphQL is null || Runtime.GraphQL.EnableAggregation; ``` **Additional fixes:** - `GraphQLSchemaCreator.OnConfigChanged` now updates `_isAggregationEnabled` on hot-reload (was omitted, causing stale state) - `schemas/dab.draft.schema.json`: added `enable-aggregation` to `runtime.graphql` properties — it was missing despite `additionalProperties: false`, meaning any config explicitly setting the flag would fail schema validation **Test refactoring (per code review feedback):** - Extracted a `LoadConfig` private helper in `RuntimeConfigLoaderTests` to eliminate repeated mock-filesystem setup across all `EnableAggregation` tests - Merged `EnableAggregation_WhenExplicitlyDisabled_ReturnsFalse` and `EnableAggregation_WhenExplicitlyEnabled_ReturnsTrue` into a single parameterized `[DataTestMethod]` (`EnableAggregation_WhenExplicitlySet_ReturnsConfiguredValue`) using `[DataRow(true)]` and `[DataRow(false)]` - Merged `Build_WithMssqlAndAggregationEnabled_AddsGroupByToConnectionType` and `Build_WithPostgreSqlAndAggregationEnabled_DoesNotAddGroupByToConnectionType` into a single parameterized `[DataTestMethod]` (`Build_WithAggregationEnabled_GroupByPresenceMatchesDatabaseSupport`) covering MSSQL, DWSQL (groupBy present), PostgreSQL, and MySQL (groupBy absent) ## How was this tested? - [ ] Integration Tests - [x] Unit Tests - `RuntimeConfigLoaderTests`: `EnableAggregation` defaults to `true` when `runtime` or `runtime.graphql` sections are absent; a single parameterized test (`EnableAggregation_WhenExplicitlySet_ReturnsConfiguredValue`) covers both `true` and `false` explicit values using `[DataRow]`. A shared `LoadConfig` helper eliminates repeated mock-filesystem setup. - `QueryBuilderTests`: a single parameterized test (`Build_WithAggregationEnabled_GroupByPresenceMatchesDatabaseSupport`) covers MSSQL and DWSQL (groupBy present) and PostgreSQL and MySQL (groupBy absent), plus a test confirming groupBy is omitted when aggregation is disabled. ## Sample Request(s) With a config that has no explicit `runtime.graphql` section, the following now works as expected for MSSQL/DWSQL entities: ```graphql { books { groupBy(fields: [price]) { fields { price } aggregations { count sum(field: price) avg(field: price) max(field: price) min(field: price) } } } } ``` --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Aniruddh25 <3513779+Aniruddh25@users.noreply.github.com> Co-authored-by: Aniruddh Munde <anmunde@microsoft.com> Co-authored-by: Souvik Ghosh <souvikofficial04@gmail.com> (cherry picked from commit 9391685)
## Why make this change? As per the behaviour expected from PUT/PATCH operations with database policies discussed in #1430, implement db policy support for PostgreSQL to fix #1372. ## What is this change? 1. Prior to this change, there was only one database policy for each operation. Since now database policies will be supported for both insert (or create)/update actions via PUT/PATCH operations, these 2 operations can have 2 database policies defined for them, one for each action. 2. The query generated by `PostgresQueryBuilder.Build(SqlUpsertQueryStructure structure)` is modified to accommodate create/update policies while also keeping intact the normal upsert behavior expected (try update, then insert). 3. The method `IQueryExecutor.GetMultipleResultSetsIfAnyAsync` has been provided another implementation specific to PostgreSql in `PostgreSqlExecutor`. The `DbDataReader` instance for the query being executed for the PUT/PATCH operation will always contain two result sets. 4. Different scenarios are added to the method `PostgreSqlExecutor.GetMultipleResultSetsIfAnyAsync` to throw appropriate exceptions (Forbidden/Authorization failure - 403 and NotFound - 404). Appropriate comments are added within the code to demonstrate each case. ## How was this tested? Integration Tests - Done --------- Co-authored-by: RubenCerna2079 <32799214+RubenCerna2079@users.noreply.github.com> (cherry picked from commit 57a195c)
## Why make this change? This pull request is to address #3094, which is a bug that happens because certain date/time SQL parameters are not being parsed to their appropriate .NET type (`DateTime` or `DateTimeOffset`) and are instead being treated as raw text. This is leading to type conversion issues when executing the underlying SQL query. ## What is this change? I have provided an overridden implementation of `MakeDbConnectionParam` in `BaseSqlQueryStructure.cs`. This method does some extra pre-processing for PostgreSQL parameters specifically by parsing each parameter into its appropriate system type before calling the base class implementation of `MakeDbConnectionParam` in `BaseQueryStructure.cs`. The system type of each parameter is retrieved from metadata of the underlying column that this parameter corresponds to via the method `GetColumnSystemType`. This change fixes the relevant issue because now parameters which correspond to an underlying `datetime` column in the schema are cast to their appropriate .NET type instead of falling through as text before building the final SQL query. Furthermore, this change is limited in scope to apply this parameter casting only when the underlying database is PostgreSQL. This ensures we do not see unexpected behavior with other database types where this sort of parameter casting may be unnecessary and/or erroneous. My original thought was to modify the method `ExtractValueFromIValueNode` in `ExecutionHelper.cs` to explicitly handle an `IValueNode` with a GraphQL scalar type of `SupportedHotChocolateTypes.DATETIME_TYPE` by parsing the `IValueNode` as a `DateTime` system type before being returned. For all practical purposes, this has the same desired effect as parsing the parameter in `MakeDbConnectionParam`, but the call to `ExtractValueFromIValueNode` happens upstream of the call to `MakeDbConnectionParam`. I believe that casting the parameters to their appropriate .NET type in `MakeDbConnectionParam` is appropriate because the method literally builds each parameter for the SQL query and the .NET type casting can be considered a part of this parameter building process. I do not think .NET type casting is as appropriate in `ExtractValueFromIValueNode` because this method serves the broader purpose of extracting a value from a GraphQL `IValueNode`, where the `IValueNode` could contain a scalar but it could also contain a variable that needs to be resolved recursively. For parameters that need to be cast to a .NET type, the control flow will go from `ExtractValueFromIValueNode` to eventually `MakeDbConnectionParam`, but again, `MakeDbConnectionParam` serves the sole purpose of building the parameter while `ExtractValueFromIValueNode` serves a broader purpose. ## How was this tested? - [ X] Integration Tests ## Sample Request(s) With query: ``` query { assignments(filter: { assignment_due_date: { gte: "2026-03-23T00:00:00.000Z" } }) { items { assignment_id assignment_name assignment_due_date } } } ``` Before: ``` SELECT * FROM public."Assignments" WHERE "Assignments"."assignment_due_date" >= '2026-03-23T00:00:00.000Z'::text; ``` After: ``` SELECT * FROM public."Assignments" WHERE "Assignments"."assignment_due_date" >= '2026-03-23T00:00:00.000Z'; ``` (cherry picked from commit eb3a58b)
#3750) ## Why make this change? There is a bug when running aggregation queries, wherein if a mapping backed column is present, the aggregation fails since it references the surfaced column and not the backed column. This pull request improves how group-by queries with mapped (aliased) columns are handled in SQL generation and adds a regression test to ensure correct behavior. The main focus is to ensure that SQL queries reference the backing (database) column names in the SELECT and GROUP BY clauses, while projecting the correct exposed (mapped) names in the results. ## What is this change? * Updated `ProcessGroupByField` and `ProcessGroupByFieldSelections` in `SqlQueryStructure.cs` to ensure that the backing (database) column name is used in the SQL query, while the exposed (mapped) field name is used as the label in the results. This resolves previous issues where the SELECT clause referenced the exposed name instead of the actual database column. [[1]](diffhunk://#diff-4b3df270873038f36ec2f627091120b7aafa271c0e2a2d257380f90602f5a298L907-R908) [[2]](diffhunk://#diff-4b3df270873038f36ec2f627091120b7aafa271c0e2a2d257380f90602f5a298L956-R956) ## How was this tested? - [x] Integration Tests - [X] Unit Tests * Added a new test method `TestSupportForGroupByAggregationWithMappedColumns` in `MsSqlGraphQLQueryTests.cs` to verify that group-by fields and aggregations both resolve to the correct backing columns, and that results are projected under the mapped names. This prevents regressions on mapped column handling in group-by queries. * Added missing import for `Azure.DataApiBuilder.Service.GraphQLBuilder.Queries` in `MsSqlGraphQLQueryTests.cs` to support the new test. --------- Co-authored-by: ARPIT GUPTA <guptaar@microsoft.com> (cherry picked from commit 032eff9)
## Why make this change? Closes #2850. This PR adds support for group by and aggregation in PostgreSQL in GraphQL queries. ## What is this change? Groupby and aggregation types/enums were added to the GraphQL schema in PostgreSQL, but they essentially were orphaned because the user couldn't utilize them in their GraphQL query. This PR hooks up the groupby/aggregation schema types/enums into a GraphQL input query. ## How was this tested? - [X] Integration Tests ## Sample Request(s) ``` query { stocks_prices { groupBy(fields: [categoryid, pieceid]) { fields { categoryid pieceid } aggregations { total: sum(field: price) count: count(field: pieceid, having: { gt: 5 }) } } } } ``` Previously, a query such as the one above would fail because the `groupBy` field would not have been attached to the `stocks_prices` object type. This PR adds the `groupBy` field to the relevant list query entity types. The `groupBy` field serves as a window to the rest of the groupBy/aggregation query. --------- Co-authored-by: Anusha Kolan <anushakolan10@gmail.com> (cherry picked from commit 7ad4f49)
#3753) ## Why make this change? In a previously merged PR, there were comments about some gaps in testing scenarios, which is addressed as part of this change. ## What is this change? This pull request adds comprehensive regression tests for groupBy queries involving mapped (aliased) columns in both MS SQL and DWSQL environments, and ensures deterministic query results by explicitly specifying `orderBy` in all relevant test GraphQL queries. **Test Coverage Improvements:** * Added two new end-to-end regression tests to `DwSqlGraphQLQueryTests.cs`: * One test verifies that grouping and projecting only a mapped column works as expected, ensuring the backing column is used for grouping and the alias is used in the response. * Another test covers grouping, selecting, aggregating, applying HAVING filters, and ordering on a mapped column, confirming consistent use of the backing column in all SQL clauses while projecting the mapped names in the response. ## How was this tested? - [X] Integration Tests - [X] Unit Tests Co-authored-by: ARPIT GUPTA <guptaar@microsoft.com> (cherry picked from commit 3cfb270)
naxing123
force-pushed
the
port/pg-graphql-features
branch
from
August 12, 2026 02:30
030f6bf to
fa2765d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports the PostgreSQL GraphQL groupby/aggregation and related feature commits from
main(released in v2.1.0-rc) torelease/2.0via cherry-pick.Commits ported (chronological)
Notes
SqlMutationEngine.cs(part of Database policy support for PUT/PATCH operations - PostgreSQL #3694 port): the original referencedeffectiveOperationType(a local introduced by the unrelated refactor Eliminate code duplication between Upsert and Insert operations #3287, which is not inrelease/2.0). Substitutedcontext.OperationType, which is functionally equivalent in that non-upsert branch and matches therelease/2.0convention. Folded into the Database policy support for PUT/PATCH operations - PostgreSQL #3694 commit.