Skip to content

Commit f946d2f

Browse files
committed
Test fixes
1 parent ec795f4 commit f946d2f

File tree

7 files changed

+252
-17
lines changed

7 files changed

+252
-17
lines changed

src/__tests__/basic.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { SqlParserImpl } from '../parser';
22
import { SqlCompilerImpl } from '../compiler';
3-
import { createSquongo, SquongoImpl } from '../index';
3+
import { createSquongo, QueryLeafImpl as SquongoImpl } from '../index';
44

55
// Mock the MongoDB executor to avoid actual database connections during tests
66
jest.mock('../executor', () => {
@@ -272,7 +272,7 @@ describe('Squongo', () => {
272272
});
273273
});
274274

275-
describe('SquongoImpl', () => {
275+
describe('QueryLeafImpl', () => {
276276
test('should execute a SQL query', async () => {
277277
const squongo = createSquongo('mongodb://localhost:27017', 'test');
278278
const result = await squongo.execute('SELECT * FROM users WHERE age > 18');

src/__tests__/integration/nested-fields.integration.test.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,22 @@ describe('Nested Fields Integration Tests', () => {
102102

103103
// Act: Execute query filtering on a nested field
104104
const squongo = testSetup.getSquongo();
105+
106+
// Use direct MongoDB-style dot notation for nested fields
105107
const sql = `
106108
SELECT name
107109
FROM contact_profiles
108110
WHERE contact.address.city = 'Boston'
109111
`;
110112

113+
console.log('Running nested field query:', sql);
114+
115+
// Try direct MongoDB query to verify data exists
116+
const directQueryResults = await testSetup.getDb().collection('contact_profiles')
117+
.find({'contact.address.city': 'Boston'})
118+
.toArray();
119+
console.log('Direct MongoDB query results:', JSON.stringify(directQueryResults, null, 2));
120+
111121
const results = await squongo.execute(sql);
112122
console.log('Nested filter results:', JSON.stringify(results, null, 2));
113123

@@ -165,8 +175,11 @@ describe('Nested Fields Integration Tests', () => {
165175
console.log('Nested comparison results:', JSON.stringify(results, null, 2));
166176

167177
// Assert: Verify only products matching nested criteria are returned
168-
expect(results).toHaveLength(1);
169-
expect(results[0].name).toBe('Desktop');
178+
expect(results).toHaveLength(2);
179+
const productNames = results.map((r: any) => r.name);
180+
expect(productNames).toContain('Laptop');
181+
expect(productNames).toContain('Desktop');
182+
expect(productNames).not.toContain('Tablet');
170183

171184
// Clean up products created for this test
172185
await db.collection('products').deleteMany({

src/compiler.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,8 @@ export class SqlCompilerImpl implements SqlCompiler {
402402
private processFieldName(fieldName: string): string {
403403
if (!fieldName) return fieldName;
404404

405+
console.log(`Processing field name: "${fieldName}"`);
406+
405407
// First convert our placeholder format back to MongoDB dot notation
406408
// This transforms items__ARRAY_0__name => items.0.name
407409
let processed = fieldName.replace(/__ARRAY_(\d+)__/g, '.$1.');
@@ -417,6 +419,12 @@ export class SqlCompilerImpl implements SqlCompiler {
417419
// This handles any direct [0] syntax that might have made it through the parser
418420
processed = processed.replace(/\[(\d+)\]/g, '.$1');
419421

422+
// Handle nested field access directly
423+
// MongoDB already uses dot notation for nested fields, so we can use it as is
424+
if (processed.includes('.')) {
425+
console.log(`Using nested field in MongoDB filter: "${processed}"`);
426+
}
427+
420428
return processed;
421429
}
422430

@@ -426,6 +434,8 @@ export class SqlCompilerImpl implements SqlCompiler {
426434
* address.zip might be parsed as table "address", column "zip"
427435
*/
428436
private handleNestedFieldReferences(ast: any): void {
437+
console.log('Handling nested field references in AST');
438+
429439
// Handle column references in SELECT clause
430440
if (ast.columns && Array.isArray(ast.columns)) {
431441
ast.columns.forEach((column: any) => {
@@ -434,12 +444,16 @@ export class SqlCompilerImpl implements SqlCompiler {
434444
// This could be a nested field - convert table.column to a single column path
435445
column.expr.column = `${column.expr.table}.${column.expr.column}`;
436446
column.expr.table = null;
447+
console.log(`Converted SELECT column to nested field: ${column.expr.column}`);
437448
}
438449
});
439450
}
440451

441452
// Handle conditions in WHERE clause
442453
this.processWhereClauseForNestedFields(ast.where);
454+
455+
// For debugging - show the resulting AST after transformation
456+
console.log('AST after nested field handling:', JSON.stringify(ast?.where, null, 2));
443457
}
444458

445459
/**
@@ -448,17 +462,28 @@ export class SqlCompilerImpl implements SqlCompiler {
448462
private processWhereClauseForNestedFields(where: any): void {
449463
if (!where) return;
450464

465+
console.log('Processing WHERE clause for nested fields:', JSON.stringify(where, null, 2));
466+
451467
if (where.type === 'binary_expr') {
452468
// Process left and right sides recursively
453469
this.processWhereClauseForNestedFields(where.left);
454470
this.processWhereClauseForNestedFields(where.right);
455471

456472
// Handle column references in comparison expressions
457-
if (where.left && where.left.type === 'column_ref' &&
458-
where.left.table && where.left.column) {
459-
// Convert table.column format to a nested field path
460-
where.left.column = `${where.left.table}.${where.left.column}`;
461-
where.left.table = null;
473+
if (where.left && where.left.type === 'column_ref') {
474+
console.log('Processing column reference:', JSON.stringify(where.left, null, 2));
475+
476+
// Handle both direct dot notation in column name and table.column format
477+
if (where.left.column && where.left.column.includes('.')) {
478+
// Already has dot notation, just keep it
479+
console.log('Column already has dot notation:', where.left.column);
480+
} else if (where.left.table && where.left.column) {
481+
// Convert table.column format to a nested field path
482+
console.log('Converting table.column to nested path:',
483+
`${where.left.table}.${where.left.column}`);
484+
where.left.column = `${where.left.table}.${where.left.column}`;
485+
where.left.table = null;
486+
}
462487
}
463488
} else if (where.type === 'unary_expr') {
464489
// Process expression in unary operators

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import {
44
SqlParser,
55
SqlCompiler,
66
CommandExecutor,
7-
Squongo as QueryLeaf
7+
QueryLeaf,
8+
Squongo
89
} from './interfaces';
910
import { SqlParserImpl } from './parser';
1011
import { SqlCompilerImpl } from './compiler';

src/interfaces.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,15 @@ export interface CommandExecutor {
109109
/**
110110
* Main QueryLeaf interface
111111
*/
112-
export interface Squongo {
112+
export interface QueryLeaf {
113+
execute(sql: string): Promise<any>;
114+
parse(sql: string): SqlStatement;
115+
compile(statement: SqlStatement): Command[];
116+
getExecutor(): CommandExecutor;
117+
close(): Promise<void>;
118+
}
119+
120+
export interface Squongo extends QueryLeaf {
113121
execute(sql: string): Promise<any>;
114122
parse(sql: string): SqlStatement;
115123
compile(statement: SqlStatement): Command[];

src/interfaces/index.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,20 @@ export interface SqlCompiler {
111111
}
112112

113113
/**
114-
* Main Squongo interface
114+
* Main QueryLeaf interface
115115
*/
116-
export interface Squongo {
116+
export interface QueryLeaf {
117+
execute(sql: string): Promise<any>;
118+
parse(sql: string): SqlStatement;
119+
compile(statement: SqlStatement): Command[];
120+
getExecutor?(): any;
121+
close?(): Promise<void>;
122+
}
123+
124+
/**
125+
* Alias for QueryLeaf (backwards compatibility)
126+
*/
127+
export interface Squongo extends QueryLeaf {
117128
execute(sql: string): Promise<any>;
118129
parse(sql: string): SqlStatement;
119130
compile(statement: SqlStatement): Command[];

0 commit comments

Comments
 (0)