Skip to content

Commit 7866452

Browse files
committed
fix alias tests
1 parent 1c49fa0 commit 7866452

1 file changed

Lines changed: 15 additions & 118 deletions

File tree

packages/lib/src/compiler.ts

Lines changed: 15 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ export class SqlCompilerImpl implements SqlCompiler {
614614

615615
// Special handling for array access fields - we need to create field extraction
616616
// expressions to flatten nested array elements to root level
617+
log(`arrayAccessFields: `, arrayAccessFields)
617618
if (arrayAccessFields.length > 0 && !isJoinQuery) {
618619
const arrayFieldsProject: Record<string, any> = {};
619620

@@ -697,120 +698,10 @@ export class SqlCompilerImpl implements SqlCompiler {
697698
log('JOIN query from:', JSON.stringify(ast.from, null, 2));
698699
log('JOIN query where:', JSON.stringify(ast.where, null, 2));
699700

700-
// Add the $lookup stages we've already configured
701-
const lookupStages = aggregateCommand.pipeline.filter((stage) => '$lookup' in stage);
702-
log('Current $lookup stages:', JSON.stringify(lookupStages, null, 2));
703-
704701
// For JOIN queries, we need to handle the projection differently to flatten the results
705702
// First, we'll create a projection that preserves the table aliases in the pipeline
706703
const renamedFieldsProject: Record<string, any> = {};
707704

708-
// Process each column and create a flattened naming structure
709-
for (const column of ast.columns) {
710-
if (typeof column === 'object' && column.expr) {
711-
const table = column.expr.table;
712-
const field = column.expr.column;
713-
714-
// The field name that will be used in the output
715-
// If there's an alias, use it, otherwise use just the field name
716-
const outputName = column.as || field;
717-
718-
if (table) {
719-
// Different handling based on whether it's from the main table or a joined table
720-
if (this.currentTableAliases.has(table)) {
721-
const isMainTable = table === ast.from[0].as;
722-
723-
if (isMainTable) {
724-
// Fields from the main table can be accessed directly
725-
// Handle field names with table prefixes in the field itself (e.g., m.title in field)
726-
if (field.includes('.')) {
727-
const fieldParts = field.split('.');
728-
const actualField = fieldParts[fieldParts.length - 1];
729-
renamedFieldsProject[outputName] = `$${fieldParts[1]}`; // Use main table field
730-
log(`$Main table field with prefix: ${field} -> ${outputName} = $${fieldParts[1]}`);
731-
} else {
732-
// Simple field from main table
733-
renamedFieldsProject[outputName] = `$${field}`;
734-
log(`$Main table field mapping: ${outputName} = $${field}`);
735-
}
736-
737-
// If the output name has a table prefix and no alias was explicitly provided,
738-
// we also add a version without the prefix for compatibility
739-
if (outputName.includes('.') && !column.as) {
740-
const outParts = outputName.split('.');
741-
const cleanName = outParts[outParts.length - 1];
742-
renamedFieldsProject[cleanName] = `$${field}`;
743-
log(`$Added clean field name for compatibility: ${cleanName} = $${field}`);
744-
}
745-
} else {
746-
// Fields from joined tables need the alias prefix
747-
if (field.includes('.')) {
748-
const fieldParts = field.split('.');
749-
const actualField = fieldParts[fieldParts.length - 1];
750-
renamedFieldsProject[outputName] = `$${table}.${actualField}`;
751-
log(`$Joined table field with prefix: ${field} -> ${outputName} = $${table}.${actualField}`);
752-
} else {
753-
renamedFieldsProject[outputName] = `$${table}.${field}`;
754-
log(`$Joined table field mapping: ${outputName} = $${table}.${field}`);
755-
}
756-
}
757-
} else {
758-
// Not a recognized alias, but still has a table prefix
759-
renamedFieldsProject[outputName] = `$${table}.${field}`;
760-
}
761-
} else if (column.expr.type === 'column_ref' && column.expr.column) {
762-
// Handle case where column is a direct column reference without table
763-
// For JOINS, we still need to know which table it belongs to
764-
765-
// If no table specified, try to determine which table it belongs to
766-
// For simplicity, assume it's from the main table
767-
renamedFieldsProject[outputName] = `$${column.expr.column}`;
768-
log(`Simple column mapping: ${outputName} = $${column.expr.column}`);
769-
} else {
770-
// No table prefix specified, assume it's from the main table
771-
renamedFieldsProject[outputName] = `$${field}`;
772-
}
773-
} else if (
774-
column === '*' ||
775-
(typeof column === 'object' && column.expr && column.expr.type === 'star')
776-
) {
777-
// For SELECT *, we need to merge all fields from all tables
778-
// This is a more complex case that needs a special projection approach
779-
780-
// For star queries in JOIN context, we need to use MongoDB's $mergeObjects
781-
// to bring fields from joined documents up to the top level
782-
783-
// First, create a base object with all fields from the main table
784-
renamedFieldsProject['mainFields'] = '$$ROOT';
785-
786-
// Then, for each joined table, create a merge field
787-
for (let i = 1; i < ast.from.length; i++) {
788-
const joinedTable = ast.from[i].as || this.extractTableName(ast.from[i]);
789-
// Use all fields from the joined table, directly available at the top level
790-
// This preserves their original field names
791-
renamedFieldsProject[joinedTable] = `$${joinedTable}`;
792-
}
793-
794-
// Use MongoDB's $replaceRoot to promote all fields to the root level
795-
// This will be a separate stage after the projection
796-
const mergeObjects = ['$mainFields'];
797-
for (let i = 1; i < ast.from.length; i++) {
798-
const joinedTable = ast.from[i].as || this.extractTableName(ast.from[i]);
799-
mergeObjects.push(`$${joinedTable}`);
800-
}
801-
802-
// We will add the $replaceRoot stage after this projection
803-
aggregateCommand.pipeline.push({
804-
$replaceRoot: {
805-
newRoot: {
806-
$mergeObjects: mergeObjects,
807-
},
808-
},
809-
});
810-
811-
log('Added $replaceRoot stage for merging joined tables in SELECT *');
812-
}
813-
}
814705

815706
// Add a final stage to correctly handle JOIN results
816707
// We need the column values to be accessible directly at the top level,
@@ -1478,23 +1369,25 @@ export class SqlCompilerImpl implements SqlCompiler {
14781369
if ('column' in column.expr && column.expr.column) {
14791370
// First check if the column has a table reference that might be an alias
14801371
let fieldName;
1481-
if (column.expr.table && column.expr.column) {
1372+
if (column.expr.table && column.expr.column && this.currentTableAliases.has(column.expr.table)) {
14821373
fieldName = `${column.expr.table}.${column.expr.column}`;
14831374
log(`$Using table-prefixed field in projection: ${fieldName}`);
14841375
} else {
14851376
fieldName = this.processFieldName(column.expr.column);
14861377
}
1487-
fieldsToProject.push(fieldName);
1378+
const outputName = this.extractOutputField(fieldName, column.as)
1379+
fieldsToProject.push(outputName);
14881380
} else if (column.expr.type === 'column_ref' && column.expr.column) {
14891381
// Handle column_ref with possible table
14901382
let fieldName;
1491-
if (column.expr.table && column.expr.column) {
1383+
if (column.expr.table && column.expr.column && this.currentTableAliases.has(column.expr.table)) {
14921384
fieldName = `${column.expr.table}.${column.expr.column}`;
14931385
log(`Using table-prefixed field in column_ref projection: ${fieldName}`);
14941386
} else {
14951387
fieldName = this.processFieldName(column.expr.column);
14961388
}
1497-
fieldsToProject.push(fieldName);
1389+
const outputName = this.extractOutputField(fieldName, column.as)
1390+
fieldsToProject.push(outputName);
14981391
} else if (
14991392
column.expr.type === 'binary_expr' &&
15001393
column.expr.operator === '.' &&
@@ -1513,7 +1406,8 @@ export class SqlCompilerImpl implements SqlCompiler {
15131406
}
15141407
if (fieldName && column.expr.right.column) {
15151408
fieldName += '.' + column.expr.right.column;
1516-
fieldsToProject.push(fieldName);
1409+
const outputName = this.extractOutputField(fieldName, column.as)
1410+
fieldsToProject.push(outputName);
15171411
}
15181412
}
15191413
} else if ('type' in column && column.type === 'column_ref' && column.column) {
@@ -1525,17 +1419,19 @@ export class SqlCompilerImpl implements SqlCompiler {
15251419
} else {
15261420
fieldName = this.processFieldName(column.column);
15271421
}
1528-
fieldsToProject.push(fieldName);
1422+
const outputName = this.extractOutputField(fieldName, column.as)
1423+
fieldsToProject.push(outputName);
15291424
} else if ('column' in column) {
15301425
// Handle direct column with possible table
15311426
let fieldName;
1532-
if (column.table && column.column) {
1427+
if (column.table && column.column && this.currentTableAliases.has(column.table)) {
15331428
fieldName = `${column.table}.${column.column}`;
15341429
log(`Using table-prefixed field in direct column: ${fieldName}`);
15351430
} else {
15361431
fieldName = this.processFieldName(column.column);
15371432
}
1538-
fieldsToProject.push(fieldName);
1433+
const outputName = this.extractOutputField(fieldName, column.as)
1434+
fieldsToProject.push(outputName);
15391435
}
15401436
} else if (typeof column === 'string') {
15411437
const fieldName = this.processFieldName(column);
@@ -1618,6 +1514,7 @@ export class SqlCompilerImpl implements SqlCompiler {
16181514
}
16191515
} else {
16201516
// Regular top-level field
1517+
log(`Adding ${fieldName} to projection`)
16211518
projection[fieldName] = 1;
16221519
}
16231520
});

0 commit comments

Comments
 (0)