Skip to content

Commit 98f3123

Browse files
author
Manus AI
committed
Add automatic join detection for computed column expressions
- Created createJoinsForComputedColumn() method to parse computed column expressions - Extracts relationship paths (e.g., asset.financials) from column references - Automatically creates auto-joins for detected relationship paths - Handles recursive computed column expansion - Fixes 'Unknown column' errors when computed columns reference nested relationships
1 parent 0329831 commit 98f3123

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

src/Support/Reporting/ReportQueryConverter.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,9 @@ protected function buildComputedColumns(Builder $query, array &$selects): void
966966
throw new \InvalidArgumentException("Invalid computed column '{$name}': {$errors}");
967967
}
968968

969+
// Extract and create auto-joins for relationship paths in the expression
970+
$this->createJoinsForComputedColumn($query, $expression, $tableName);
971+
969972
// Resolve column references in the expression to use proper table aliases
970973
$resolvedExpression = $this->resolveComputedColumnReferences($expression, $tableName);
971974

@@ -1158,3 +1161,73 @@ protected function validateQueryConfig(): void
11581161
// }
11591162
}
11601163
}
1164+
1165+
/**
1166+
* Extract relationship paths from a computed column expression and create necessary joins.
1167+
*
1168+
* This method parses the expression to find column references like "asset.financials.monthly_hire_revenue"
1169+
* and ensures that all necessary auto-joins are created for the relationship paths.
1170+
*/
1171+
protected function createJoinsForComputedColumn(Builder $query, string $expression, string $rootTable): void
1172+
{
1173+
// First, expand any computed column references in the expression
1174+
$computedColumns = $this->queryConfig['computed_columns'] ?? [];
1175+
$computedColumnMap = [];
1176+
foreach ($computedColumns as $col) {
1177+
$computedColumnMap[$col['name']] = $col['expression'];
1178+
}
1179+
1180+
// Recursively expand computed column references
1181+
$maxDepth = 10;
1182+
$depth = 0;
1183+
$expandedExpression = $expression;
1184+
while ($depth < $maxDepth) {
1185+
$changed = false;
1186+
foreach ($computedColumnMap as $name => $expr) {
1187+
if (preg_match('/\b' . preg_quote($name, '/') . '\b/', $expandedExpression)) {
1188+
$expandedExpression = preg_replace('/\b' . preg_quote($name, '/') . '\b/', '(' . $expr . ')', $expandedExpression);
1189+
$changed = true;
1190+
}
1191+
}
1192+
if (!$changed) {
1193+
break;
1194+
}
1195+
$depth++;
1196+
}
1197+
1198+
// Now extract all column references that look like relationship paths (e.g., "asset.financials.monthly_hire_revenue")
1199+
// We need to match patterns like: word.word.word (but not inside string literals)
1200+
1201+
// First, remove string literals to avoid matching inside them
1202+
$cleanedExpression = preg_replace("/'[^']*'/", '', $expandedExpression);
1203+
$cleanedExpression = preg_replace('/"[^"]*"/', '', $cleanedExpression);
1204+
1205+
// Match column references with dots (relationship paths)
1206+
preg_match_all('/\b([a-z_][a-z0-9_]*\.[a-z_][a-z0-9_]*(?:\.[a-z_][a-z0-9_]*)*)\b/i', $cleanedExpression, $matches);
1207+
1208+
if (empty($matches[1])) {
1209+
return;
1210+
}
1211+
1212+
// Extract unique relationship paths (everything except the final column name)
1213+
$relationshipPaths = [];
1214+
foreach ($matches[1] as $columnPath) {
1215+
$parts = explode('.', $columnPath);
1216+
if (count($parts) >= 2) {
1217+
// Remove the last part (column name) to get the relationship path
1218+
array_pop($parts);
1219+
$relationshipPath = implode('.', $parts);
1220+
$relationshipPaths[$relationshipPath] = true;
1221+
}
1222+
}
1223+
1224+
// Create auto-joins for each unique relationship path
1225+
foreach (array_keys($relationshipPaths) as $path) {
1226+
try {
1227+
$this->applyAutoJoinPath($query, $rootTable, $path);
1228+
} catch (\Exception $e) {
1229+
// If the join fails, it might not be a valid relationship path
1230+
// Just continue - the error will be caught later when resolving the column
1231+
}
1232+
}
1233+
}

0 commit comments

Comments
 (0)