Skip to content

Add groupby/aggregation support for PostgreSQL in GraphQL - #3741

Open
ArjunNarendra wants to merge 9 commits into
Azure:mainfrom
ArjunNarendra:user/an/add-aggregation-support-to-postgresql
Open

Add groupby/aggregation support for PostgreSQL in GraphQL#3741
ArjunNarendra wants to merge 9 commits into
Azure:mainfrom
ArjunNarendra:user/an/add-aggregation-support-to-postgresql

Conversation

@ArjunNarendra

Copy link
Copy Markdown
Contributor

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?

  • 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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enables end-to-end GraphQL groupBy + aggregation support for PostgreSQL by wiring Postgres into the GraphQL schema’s aggregation feature gate and updating the Postgres SQL query builder to emit aggregation columns and GROUP BY/HAVING clauses. It also re-enables the previously ignored PostgreSQL aggregation integration tests and updates the PostgreSQL test schema.

Changes:

  • Enable GraphQL aggregation support for DatabaseType.PostgreSQL in the schema builder.
  • Extend PostgresQueryBuilder SQL generation to include aggregation columns plus GROUP BY/HAVING/conditional ORDER BY.
  • Un-ignore and update PostgreSQL GraphQL aggregation tests; extend PostgreSQL test schema with date_only_table.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Service.GraphQLBuilder/Queries/QueryBuilder.cs Enables aggregation/groupBy schema features for PostgreSQL.
src/Core/Resolvers/PostgresQueryBuilder.cs Adds aggregation + group-by/having clause generation to Postgres SELECT queries.
src/Core/Resolvers/BaseTSqlQueryBuilder.cs Moves shared group-by/having/order-by/aggregation helpers out of the T-SQL-only base.
src/Core/Resolvers/BaseSqlQueryBuilder.cs Centralizes shared group-by/having/order-by/aggregation helper methods for all SQL builders.
src/Service.Tests/SqlTests/GraphQLQueryTests/PostgreSqlGraphQLQueryTests.cs Re-enables and updates PostgreSQL aggregation integration tests and expected SQL baselines.
src/Service.Tests/DatabaseSchema-PostgreSql.sql Adds/drop support for date_only_table test data.
Comments suppressed due to low confidence (2)

src/Service.Tests/SqlTests/GraphQLQueryTests/PostgreSqlGraphQLQueryTests.cs:633

  • This GROUP BY test’s expected SQL omits ORDER BY, but the assertion compares arrays by index. Postgres row order for GROUP BY without ORDER BY is not guaranteed, so the test can be flaky. Add ORDER BY on the group-by fields to make the expected result deterministic.
                    FROM stocks_price
                    GROUP BY categoryid, pieceid
                    HAVING SUM(price) > 50 AND COUNT(pieceid) <= 100
                ) AS table0";

src/Service.Tests/SqlTests/GraphQLQueryTests/PostgreSqlGraphQLQueryTests.cs:653

  • This GROUP BY expected SQL has no ORDER BY, but the test compares expected vs actual by position. Since Postgres doesn’t guarantee GROUP BY output order, add an ORDER BY on the group-by keys to avoid nondeterministic failures.
                    FROM stocks_price
                    GROUP BY categoryid, pieceid
                ) AS table0";

Comment on lines +607 to +610
FROM stocks_price
GROUP BY categoryid, pieceid
HAVING SUM(price) > 50
) AS table0";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting. I can add an ORDER BY on the grouping keys to stabilize the expected result ordering, but this does not guarantee anything about the actual result ordering. This change may patch the tests for now, but I do not think it fundamentally fixes the issue that the SQL that DAB generates in these cases does not have an ORDER BY, so there is no guaranteed row order from what DAB returns in these cases.

@ArjunNarendra ArjunNarendra Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every column in the GROUP BY clause will also be in the ORDER BY clause when building the query in DAB (see thread below).

@Aniruddh25 Aniruddh25 assigned anushakolan and unassigned Aniruddh25 Jul 30, 2026
Comment thread src/Core/Resolvers/BaseSqlQueryBuilder.cs
Comment on lines 41 to +51
Build(structure.Predicates),
Build(structure.PaginationMetadata.PaginationPredicate));

string query = $"SELECT {MakeSelectColumns(structure)}"
string aggregations = BuildAggregationColumns(structure);

string query = $"SELECT {MakeSelectColumns(structure)}{aggregations}"
+ $" FROM {fromSql}"
+ $" WHERE {predicates}"
+ $" ORDER BY {Build(structure.OrderByColumns)}"
+ BuildGroupBy(structure)
+ BuildHaving(structure)
+ BuildOrderBy(structure)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the Build(SqlQueryStructure) method now appends BuildOrderBy(structure), which only emits ORDER BY when structure.OrderByColumns.Any(). For a groupBy query the grouping keys are not guaranteed to be in OrderByColumns, so DAB emits GROUP BY with no ORDER BY. Postgres does not guarantee row order for GROUP BY without ORDER BY, so the client-visible ordering of aggregation results becomes nondeterministic (and pagination over grouped results would be unstable)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this kind of resonates with one of the test case comment summaryimage.png

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right. This is an issue with the implementation (not just the tests), and the clearest negative effect it may have is that pagination over grouped results becomes unstable.

@ArjunNarendra ArjunNarendra Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix I am planning is that every column in the GROUP BY clause will also be in the ORDER BY clause when building the query in DAB.

@ArjunNarendra ArjunNarendra changed the title User/an/add aggregation support to postgresql Add groupby/aggregation support for PostgreSQL in GraphQL Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enh]: Support Aggregations in read (PostgreSQL)

5 participants