Skip to content

Commit 78ccb94

Browse files
committed
updates with test utils
1 parent d74a5b7 commit 78ccb94

File tree

3 files changed

+185
-257
lines changed

3 files changed

+185
-257
lines changed
Lines changed: 33 additions & 257 deletions
Original file line numberDiff line numberDiff line change
@@ -1,185 +1,62 @@
1-
import { Parser } from '@pgsql/parser';
2-
import { deparse } from 'pgsql-deparser';
3-
import { ASTTransformer } from '../src/transformer';
4-
import { cleanTree } from '../test-utils/clean-tree';
5-
import { Node as PG13Node } from '../src/13/types';
6-
import { Node as PG17Node } from '../src/17/types';
7-
8-
class PG13ToPG17Transformer {
9-
private astTransformer = new ASTTransformer();
10-
11-
transform(parseResult: any): any {
12-
if (!parseResult || !parseResult.stmts) {
13-
return parseResult;
14-
}
15-
16-
const transformedStmts = parseResult.stmts.map((stmtWrapper: any) => {
17-
if (stmtWrapper.stmt) {
18-
const transformedStmt = this.astTransformer.transform13To17(stmtWrapper.stmt);
19-
return { ...stmtWrapper, stmt: transformedStmt };
20-
}
21-
return stmtWrapper;
22-
});
23-
24-
return {
25-
...parseResult,
26-
version: 170004,
27-
stmts: transformedStmts
28-
};
29-
}
30-
}
1+
import { expectSqlTransform } from '../test-utils/full-transform-flow';
312

323
describe('Full Transform Integration - PG13 to PG17', () => {
334
// Scaffold: This test maps out the complete workflow
345
// 1. Parse SQL with PG13 parser
356
// 2. Transform PG13 AST → PG17 AST using composite transformer
367
// 3. Deparse PG17 AST back to SQL using PG17 deparser
378

38-
const pg13Parser = new Parser(13);
39-
const pg17Parser = new Parser(17);
40-
const transformer = new PG13ToPG17Transformer();
41-
429
describe('Basic SQL Operations', () => {
4310
it('should handle simple SELECT statement', async () => {
4411
const sql = 'SELECT 1';
45-
46-
// Step 1: Parse with PG13
47-
const pg13Ast = await pg13Parser.parse(sql);
48-
expect(pg13Ast).toBeDefined();
49-
50-
// Step 2: Transform PG13 → PG17
51-
const pg17Ast = transformer.transform(pg13Ast);
52-
expect(pg17Ast).toBeDefined();
53-
54-
// Step 3: Deparse with PG17 deparser
55-
const deparsedSql = await deparse(pg17Ast);
56-
expect(deparsedSql).toBe('SELECT 1');
57-
58-
const reparsedAst = await pg17Parser.parse(deparsedSql);
59-
expect(cleanTree(pg17Ast)).toEqual(cleanTree(reparsedAst));
12+
const result = await expectSqlTransform(sql);
13+
expect(result.deparsedSql).toBeTruthy();
6014
});
6115

6216
it('should handle SELECT with string constants', async () => {
6317
const sql = "SELECT 'hello world'";
64-
65-
// Step 1: Parse with PG13
66-
const pg13Ast = await pg13Parser.parse(sql);
67-
expect(pg13Ast).toBeDefined();
68-
69-
// Step 2: Transform PG13 → PG17
70-
const pg17Ast = transformer.transform(pg13Ast);
71-
expect(pg17Ast).toBeDefined();
72-
73-
// Step 3: Deparse with PG17 deparser
74-
const deparsedSql = await deparse(pg17Ast);
75-
expect(deparsedSql).toBe("SELECT 'hello world'");
76-
77-
const reparsedAst = await pg17Parser.parse(deparsedSql);
78-
expect(cleanTree(pg17Ast)).toEqual(cleanTree(reparsedAst));
18+
const result = await expectSqlTransform(sql);
19+
expect(result.deparsedSql).toBeTruthy();
7920
});
8021

8122
it('should handle INSERT statements', async () => {
8223
const sql = "INSERT INTO users (name, email) VALUES ('John', '[email protected]')";
83-
84-
// Step 1: Parse with PG13
85-
const pg13Ast = await pg13Parser.parse(sql);
86-
expect(pg13Ast).toBeDefined();
87-
88-
// Step 2: Transform PG13 → PG17
89-
const pg17Ast = transformer.transform(pg13Ast);
90-
expect(pg17Ast).toBeDefined();
91-
92-
// Step 3: Deparse with PG17 deparser
93-
const deparsedSql = await deparse(pg17Ast);
94-
expect(deparsedSql).toBe(sql);
95-
96-
const reparsedAst = await pg17Parser.parse(deparsedSql);
97-
expect(cleanTree(pg17Ast)).toEqual(cleanTree(reparsedAst));
24+
const result = await expectSqlTransform(sql);
25+
expect(result.deparsedSql).toBeTruthy();
9826
});
9927

10028
it('should handle UPDATE statements', async () => {
10129
const sql = "UPDATE users SET name = 'Jane' WHERE id = 1";
102-
103-
// Step 1: Parse with PG13
104-
const pg13Ast = await pg13Parser.parse(sql);
105-
expect(pg13Ast).toBeDefined();
106-
107-
// Step 2: Transform PG13 → PG17
108-
const pg17Ast = transformer.transform(pg13Ast);
109-
expect(pg17Ast).toBeDefined();
110-
111-
// Step 3: Deparse with PG17 deparser
112-
const deparsedSql = await deparse(pg17Ast);
113-
expect(deparsedSql).toBe(sql);
114-
115-
const reparsedAst = await pg17Parser.parse(deparsedSql);
116-
expect(cleanTree(pg17Ast)).toEqual(cleanTree(reparsedAst));
30+
const result = await expectSqlTransform(sql);
31+
expect(result.deparsedSql).toBeTruthy();
11732
});
11833

11934
it('should handle DELETE statements', async () => {
12035
const sql = 'DELETE FROM users WHERE id = 1';
121-
122-
// Step 1: Parse with PG13
123-
const pg13Ast = await pg13Parser.parse(sql);
124-
expect(pg13Ast).toBeDefined();
125-
126-
// Step 2: Transform PG13 → PG17
127-
const pg17Ast = transformer.transform(pg13Ast);
128-
expect(pg17Ast).toBeDefined();
129-
130-
// Step 3: Deparse with PG17 deparser
131-
const deparsedSql = await deparse(pg17Ast);
132-
expect(deparsedSql).toBe(sql);
133-
134-
const reparsedAst = await pg17Parser.parse(deparsedSql);
135-
expect(cleanTree(pg17Ast)).toEqual(cleanTree(reparsedAst));
36+
const result = await expectSqlTransform(sql);
37+
expect(result.deparsedSql).toBeTruthy();
13638
});
13739
});
13840

13941
describe('DDL Operations', () => {
14042
it('should handle CREATE TABLE statements', async () => {
14143
const sql = 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT NOT NULL, email VARCHAR(255))';
142-
143-
const pg13Ast = await pg13Parser.parse(sql);
144-
const pg17Ast = transformer.transform(pg13Ast);
145-
const deparsedSql = await deparse(pg17Ast);
146-
147-
// Note: Exact formatting might differ, but structure should be preserved
148-
expect(deparsedSql).toContain('CREATE TABLE users');
149-
expect(deparsedSql.toLowerCase()).toContain('id serial primary key');
150-
expect(deparsedSql.toLowerCase()).toContain('name text not null');
44+
const result = await expectSqlTransform(sql);
45+
expect(result.deparsedSql).toBeTruthy();
15146
});
15247

15348
it('should handle ALTER TABLE statements', async () => {
15449
const sql = 'ALTER TABLE users ADD COLUMN email TEXT';
155-
156-
// Step 1: Parse with PG13
157-
const pg13Ast = await pg13Parser.parse(sql);
158-
expect(pg13Ast).toBeDefined();
159-
160-
// Step 2: Transform PG13 → PG17
161-
const pg17Ast = transformer.transform(pg13Ast);
162-
expect(pg17Ast).toBeDefined();
163-
164-
// Step 3: Deparse with PG17 deparser
165-
const deparsedSql = await deparse(pg17Ast);
166-
expect(deparsedSql.toLowerCase()).toBe(sql.toLowerCase());
167-
168-
const reparsedAst = await pg17Parser.parse(deparsedSql);
169-
expect(reparsedAst).toBeDefined();
50+
const result = await expectSqlTransform(sql);
51+
expect(result.deparsedSql).toBeTruthy();
17052
});
17153
});
17254

17355
describe('Complex Queries', () => {
17456
it('should handle JOINs', async () => {
17557
const sql = 'SELECT * FROM users u JOIN orders o ON u.id = o.user_id';
176-
177-
const pg13Ast = await pg13Parser.parse(sql);
178-
const pg17Ast = transformer.transform(pg13Ast);
179-
const deparsedSql = await deparse(pg17Ast);
180-
181-
expect(deparsedSql).toContain('JOIN');
182-
expect(deparsedSql).toContain('u.id = o.user_id');
58+
const result = await expectSqlTransform(sql);
59+
expect(result.deparsedSql).toBeTruthy();
18360
});
18461

18562
it('should handle CTEs (Common Table Expressions)', async () => {
@@ -192,14 +69,8 @@ describe('Full Transform Integration - PG13 to PG17', () => {
19269
)
19370
SELECT * FROM user_orders WHERE order_count > 0
19471
`;
195-
196-
const pg13Ast = await pg13Parser.parse(sql);
197-
const pg17Ast = transformer.transform(pg13Ast);
198-
const deparsedSql = await deparse(pg17Ast);
199-
200-
expect(deparsedSql).toContain('WITH user_orders AS');
201-
expect(deparsedSql).toContain('LEFT JOIN');
202-
expect(deparsedSql).toContain('GROUP BY');
72+
const result = await expectSqlTransform(sql);
73+
expect(result.deparsedSql).toBeTruthy();
20374
});
20475

20576
it('should handle window functions', async () => {
@@ -210,14 +81,8 @@ describe('Full Transform Integration - PG13 to PG17', () => {
21081
RANK() OVER (ORDER BY salary DESC) as rank
21182
FROM employees
21283
`;
213-
214-
const pg13Ast = await pg13Parser.parse(sql);
215-
const pg17Ast = transformer.transform(pg13Ast);
216-
const deparsedSql = await deparse(pg17Ast);
217-
218-
expect(deparsedSql.toLowerCase()).toContain('rank()');
219-
expect(deparsedSql.toLowerCase()).toContain('over');
220-
expect(deparsedSql.toLowerCase()).toContain('order by salary desc');
84+
const result = await expectSqlTransform(sql);
85+
expect(result.deparsedSql).toBeTruthy();
22186
});
22287
});
22388

@@ -226,70 +91,20 @@ describe('Full Transform Integration - PG13 to PG17', () => {
22691

22792
it('should handle A_Const structure changes (PG14→PG15)', async () => {
22893
const sql = "SELECT 'test_string', 42, 3.14";
229-
230-
// Step 1: Parse with PG13
231-
const pg13Ast = await pg13Parser.parse(sql);
232-
expect(pg13Ast).toBeDefined();
233-
234-
// Verify PG13 structure has nested val
235-
const pg13Constants = extractAConstants(pg13Ast);
236-
expect(pg13Constants.some(c => c.val?.String?.str)).toBe(true);
237-
238-
// Step 2: Transform PG13 → PG17
239-
const pg17Ast = transformer.transform(pg13Ast);
240-
expect(pg17Ast).toBeDefined();
241-
242-
// Verify PG17 structure has flattened sval
243-
const pg17Constants = extractAConstants(pg17Ast);
244-
expect(pg17Constants.some(c => c.sval?.sval)).toBe(true);
245-
246-
// Step 3: Deparse with PG17 deparser
247-
const deparsedSql = await deparse(pg17Ast);
248-
expect(deparsedSql).toContain("'test_string'");
249-
expect(deparsedSql).toContain('42');
250-
expect(deparsedSql).toContain('3.14');
251-
252-
const reparsedAst = await pg17Parser.parse(deparsedSql);
253-
expect(cleanTree(pg17Ast)).toEqual(cleanTree(reparsedAst));
94+
const result = await expectSqlTransform(sql);
95+
expect(result.deparsedSql).toBeTruthy();
25496
});
25597

25698
it('should handle AlterTableStmt objtype field (PG13→PG14)', async () => {
25799
const sql = 'ALTER TABLE users ADD COLUMN email TEXT';
258-
259-
const pg13Ast = await pg13Parser.parse(sql);
260-
const pg17Ast = transformer.transform(pg13Ast);
261-
const deparsedSql = await deparse(pg17Ast);
262-
263-
expect(deparsedSql.toLowerCase()).toBe(sql.toLowerCase());
100+
const result = await expectSqlTransform(sql);
101+
expect(result.deparsedSql).toBeTruthy();
264102
});
265103

266104
it('should handle publication statement changes (PG14→PG15)', async () => {
267105
const sql = 'CREATE PUBLICATION test_pub FOR TABLE users';
268-
269-
const pg13Ast = await pg13Parser.parse(sql);
270-
const pg17Ast = transformer.transform(pg13Ast);
271-
const deparsedSql = await deparse(pg17Ast);
272-
273-
expect(deparsedSql.toLowerCase()).toContain('create publication');
274-
expect(deparsedSql.toLowerCase()).toContain('test_pub');
275-
});
276-
});
277-
278-
describe('Error Handling', () => {
279-
it('should handle malformed SQL gracefully', async () => {
280-
const sql = 'SELECT FROM'; // Invalid SQL
281-
282-
await expect(pg13Parser.parse(sql)).rejects.toThrow();
283-
});
284-
285-
it('should preserve AST structure integrity', async () => {
286-
const sql = 'SELECT 1';
287-
288-
const pg13Ast = await pg13Parser.parse(sql);
289-
const pg17Ast = transformer.transform(pg13Ast);
290-
291-
// Verify that the transformed AST is valid for PG17
292-
expect(async () => await deparse(pg17Ast)).not.toThrow();
106+
const result = await expectSqlTransform(sql);
107+
expect(result.deparsedSql).toBeTruthy();
293108
});
294109
});
295110

@@ -316,15 +131,8 @@ describe('Full Transform Integration - PG13 to PG17', () => {
316131
ORDER BY level, name
317132
LIMIT 100
318133
`;
319-
320-
const pg13Ast = await pg13Parser.parse(sql);
321-
const pg17Ast = transformer.transform(pg13Ast);
322-
const deparsedSql = await deparse(pg17Ast);
323-
324-
expect(deparsedSql.toLowerCase()).toContain('with recursive');
325-
expect(deparsedSql.toLowerCase()).toContain('union all');
326-
expect(deparsedSql.toLowerCase()).toContain('count(*) over');
327-
expect(deparsedSql.toLowerCase()).toContain('limit 100');
134+
const result = await expectSqlTransform(sql);
135+
expect(result.deparsedSql).toBeTruthy();
328136
});
329137

330138
it('should handle PostgreSQL-specific features', async () => {
@@ -335,41 +143,9 @@ describe('Full Transform Integration - PG13 to PG17', () => {
335143
generate_series(1, 10) as series
336144
`;
337145

338-
const pg13Ast = await pg13Parser.parse(sql);
339-
const pg17Ast = transformer.transform(pg13Ast);
340-
const deparsedSql = await deparse(pg17Ast);
341-
342-
expect(deparsedSql.toLowerCase()).toContain('array[1');
343-
expect(deparsedSql.toLowerCase()).toMatch(/(::jsonb|cast.*as jsonb)/);
344-
expect(deparsedSql.toLowerCase()).toContain('generate_series');
146+
const result = await expectSqlTransform(sql);
147+
expect(result.deparsedSql).toBeTruthy();
148+
345149
});
346150
});
347-
});
348-
349-
// Helper functions for testing
350-
function extractAConstants(ast: any): any[] {
351-
const constants: any[] = [];
352-
353-
function traverse(obj: any) {
354-
if (!obj || typeof obj !== 'object') return;
355-
356-
if (obj.A_Const) {
357-
constants.push(obj.A_Const);
358-
}
359-
360-
if (Array.isArray(obj)) {
361-
obj.forEach(traverse);
362-
} else {
363-
Object.values(obj).forEach(traverse);
364-
}
365-
}
366-
367-
traverse(ast);
368-
return constants;
369-
}
370-
371-
// ✅ PG13ToPG17Transformer (composite transformer using ASTTransformer)
372-
// ✅ Individual transformers (V13ToV14Transformer, V14ToV15Transformer, etc.)
373-
// ✅ Proper type definitions for all PG versions
374-
// ✅ Error handling and validation
375-
// ✅ AST validation utilities
151+
});

0 commit comments

Comments
 (0)