Fix orderBy columns missing from SELECT in DISTINCT subquery (#17079)

## Description

Fixes a bug where queries with relation field + scalar field ordering
would fail with:
```
column distinctAlias.person_position does not exist
```

## Root Cause

When a GraphQL query orders by columns that are **not in the selected
fields**, TypeORM's DISTINCT subquery fails because it expects those
columns in the inner SELECT with alias format (e.g., `person_position`).

The issue only manifests when:
1. A filter is applied (triggers DISTINCT path in TypeORM)
2. OrderBy includes columns NOT in the GraphQL selection
3. Example: query selects only `id`, but orders by `position`

## The Fix

`addRelationOrderColumnsToBuilder` now accepts `columnsToSelect` and
adds orderBy columns via `addSelect()` only if they're **NOT** already
in the selected columns:

- **Relation orderBy columns**: Always added (never in columnsToSelect)
- **Main entity orderBy columns**: Added only when not already selected

This ensures all orderBy columns are present in TypeORM's inner SELECT
for the DISTINCT subquery.

## Test Plan

Added integration test for the exact failing scenario:
- Filter with `neq` (triggers DISTINCT path)
- Multiple orderBy: relation field + scalar field  
- Minimal field selection (only `id`, not `position`)

## Related

Regression introduced in #17021 which added nested sort support.
This commit is contained in:
Félix Malfait
2026-01-11 14:19:05 +01:00
committed by GitHub
parent 20f62e05f5
commit 57363c2127
3 changed files with 76 additions and 11 deletions
@@ -142,17 +142,23 @@ export class GraphqlQueryParser {
queryBuilder: WorkspaceSelectQueryBuilder<any>,
parsedOrderBy: Record<string, OrderByClause>,
objectNameSingular: string,
columnsToSelect: Record<string, boolean>,
): void {
// Add relation ORDER BY columns with underscore alias for DISTINCT compatibility
// Add ORDER BY columns with underscore alias for DISTINCT compatibility
// This must be called AFTER setFindOptions because setFindOptions clears addSelect
// We need to add columns that are in orderBy but NOT in the selected columns
for (const orderByKey of Object.keys(parsedOrderBy)) {
const parts = orderByKey.split('.');
if (parts.length === 2) {
const [alias, column] = parts;
// Only add select for joined relation columns, not main entity columns
if (alias !== objectNameSingular) {
// For relation columns: always add (they're never in columnsToSelect)
// For main entity columns: only add if NOT already in columnsToSelect
const isMainEntity = alias === objectNameSingular;
const isAlreadySelected = isMainEntity && columnsToSelect[column];
if (!isAlreadySelected) {
queryBuilder.addSelect(
`"${alias}"."${column}"`,
`${alias}_${column}`,