Skip to content

Commit b3b7362

Browse files
author
Manus AI
committed
Fix join creation timing for computed columns in aggregates
- Moved join creation for computed columns to processAutoJoins phase - Added collectAutoJoinPathsFromComputedColumns() method - Extracted extractRelationshipPathsFromExpression() as reusable method - Joins are now created BEFORE aggregate expressions are resolved - Fixes 'Unknown column' error when aggregating computed columns with nested relationships - Previously: joins created during buildComputedColumns (too late for aggregates) - Now: joins created during processAutoJoins (before buildSelectClause)
1 parent 12f2400 commit b3b7362

1 file changed

Lines changed: 43 additions & 15 deletions

File tree

src/Support/Reporting/ReportQueryConverter.php

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ protected function processAutoJoins(Builder $query, string $tableName): void
229229
$this->collectAutoJoinPathsFromConditions($this->queryConfig['conditions'] ?? [], $autoJoinPaths);
230230
$this->collectAutoJoinPathsFromGroupBy($this->queryConfig['groupBy'] ?? [], $autoJoinPaths);
231231
$this->collectAutoJoinPathsFromSortBy($this->queryConfig['sortBy'] ?? [], $autoJoinPaths);
232+
$this->collectAutoJoinPathsFromComputedColumns($this->queryConfig['computed_columns'] ?? [], $autoJoinPaths, $tableName);
232233

233234
// dedupe and sort shortest->longest so parent joins first
234235
$autoJoinPaths = array_values(array_unique($autoJoinPaths));
@@ -288,6 +289,22 @@ protected function collectAutoJoinPathsFromSortBy(array $sortBy, array &$autoJoi
288289
}
289290
}
290291

292+
protected function collectAutoJoinPathsFromComputedColumns(array $computedColumns, array &$autoJoinPaths, string $rootTable): void
293+
{
294+
foreach ($computedColumns as $computedColumn) {
295+
$expression = $computedColumn['expression'] ?? '';
296+
if (empty($expression)) {
297+
continue;
298+
}
299+
300+
// Extract relationship paths from the expression
301+
$paths = $this->extractRelationshipPathsFromExpression($expression, $rootTable);
302+
foreach ($paths as $path) {
303+
$autoJoinPaths[] = $path;
304+
}
305+
}
306+
}
307+
291308
protected function applyAutoJoinPath(Builder $query, string $rootTable, string $fullPath): void
292309
{
293310
// Already joined?
@@ -963,8 +980,8 @@ protected function buildComputedColumns(Builder $query, array &$selects): void
963980
throw new \InvalidArgumentException("Invalid computed column '{$name}': {$errors}");
964981
}
965982

966-
// Extract and create auto-joins for relationship paths in the expression
967-
$this->createJoinsForComputedColumn($query, $expression, $tableName);
983+
// Note: Auto-joins for computed column relationships are now created earlier in processAutoJoins()
984+
// This ensures joins exist before aggregate expressions are resolved
968985

969986
// Resolve column references in the expression to use proper table aliases
970987
$resolvedExpression = $this->resolveComputedColumnReferences($expression, $tableName);
@@ -1159,12 +1176,16 @@ protected function validateQueryConfig(): void
11591176
}
11601177

11611178
/**
1162-
* Extract relationship paths from a computed column expression and create necessary joins.
1179+
* Extract relationship paths from a computed column expression.
11631180
*
11641181
* This method parses the expression to find column references like "asset.financials.monthly_hire_revenue"
1165-
* and ensures that all necessary auto-joins are created for the relationship paths.
1182+
* and returns the relationship paths (e.g., "asset.financials").
1183+
*
1184+
* @param string $expression The computed column expression
1185+
* @param string $rootTable The root table name (not used currently but kept for consistency)
1186+
* @return array Array of relationship paths
11661187
*/
1167-
protected function createJoinsForComputedColumn(Builder $query, string $expression, string $rootTable): void
1188+
protected function extractRelationshipPathsFromExpression(string $expression, string $rootTable): array
11681189
{
11691190
// First, expand any computed column references in the expression
11701191
$computedColumns = $this->queryConfig['computed_columns'] ?? [];
@@ -1202,7 +1223,7 @@ protected function createJoinsForComputedColumn(Builder $query, string $expressi
12021223
preg_match_all('/\b([a-z_][a-z0-9_]*\.[a-z_][a-z0-9_]*(?:\.[a-z_][a-z0-9_]*)*)\b/i', $cleanedExpression, $matches);
12031224

12041225
if (empty($matches[1])) {
1205-
return;
1226+
return [];
12061227
}
12071228

12081229
// Extract unique relationship paths (everything except the final column name)
@@ -1217,14 +1238,21 @@ protected function createJoinsForComputedColumn(Builder $query, string $expressi
12171238
}
12181239
}
12191240

1220-
// Create auto-joins for each unique relationship path
1221-
foreach (array_keys($relationshipPaths) as $path) {
1222-
try {
1223-
$this->applyAutoJoinPath($query, $rootTable, $path);
1224-
} catch (\Exception $e) {
1225-
// If the join fails, it might not be a valid relationship path
1226-
// Just continue - the error will be caught later when resolving the column
1227-
}
1228-
}
1241+
return array_keys($relationshipPaths);
1242+
}
1243+
1244+
/**
1245+
* Extract relationship paths from a computed column expression and create necessary joins.
1246+
*
1247+
* This method parses the expression to find column references like "asset.financials.monthly_hire_revenue"
1248+
* and ensures that all necessary auto-joins are created for the relationship paths.
1249+
*
1250+
* @deprecated This method is now redundant as join creation happens in processAutoJoins
1251+
*/
1252+
protected function createJoinsForComputedColumn(Builder $query, string $expression, string $rootTable): void
1253+
{
1254+
// This method is now a no-op since joins are created earlier in processAutoJoins
1255+
// Keeping it for backward compatibility but it does nothing
1256+
return;
12291257
}
12301258
}

0 commit comments

Comments
 (0)