Skip to content

Commit 27c3ad9

Browse files
committed
updates
1 parent d4ba1a1 commit 27c3ad9

File tree

2 files changed

+307
-1
lines changed

2 files changed

+307
-1
lines changed
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
import { Parser } from '@pgsql/parser';
2+
import { deparse } from 'pgsql-deparser';
3+
// TODO: Implement this composite transformer
4+
// import { PG13ToPG17Transformer } from '../src/transformers/pg13-to-pg17-composite';
5+
import { Node as PG13Node } from '../src/13/types';
6+
import { Node as PG17Node } from '../src/17/types';
7+
8+
// Placeholder class for scaffold testing
9+
class PG13ToPG17Transformer {
10+
transform(ast: any): any {
11+
// TODO: Implement composite transformation PG13 → PG17
12+
return ast;
13+
}
14+
}
15+
16+
describe('Full Transform Integration - PG13 to PG17', () => {
17+
// Scaffold: This test maps out the complete workflow
18+
// 1. Parse SQL with PG13 parser
19+
// 2. Transform PG13 AST → PG17 AST using composite transformer
20+
// 3. Deparse PG17 AST back to SQL using PG17 deparser
21+
22+
const pg13Parser = new Parser(13);
23+
const transformer = new PG13ToPG17Transformer(); // Composite of all 4 transformers
24+
25+
describe('Basic SQL Operations', () => {
26+
it('should handle simple SELECT statement', async () => {
27+
const sql = 'SELECT 1';
28+
29+
// Step 1: Parse with PG13
30+
const pg13Ast = await pg13Parser.parse(sql);
31+
expect(pg13Ast).toBeDefined();
32+
33+
// Step 2: Transform PG13 → PG17
34+
const pg17Ast = transformer.transform(pg13Ast);
35+
expect(pg17Ast).toBeDefined();
36+
37+
// Step 3: Deparse with PG17 deparser
38+
const deparsedSql = await deparse(pg17Ast);
39+
expect(deparsedSql).toBe('SELECT 1');
40+
});
41+
42+
it('should handle SELECT with string constants', async () => {
43+
const sql = "SELECT 'hello world'";
44+
45+
const pg13Ast = await pg13Parser.parse(sql);
46+
const pg17Ast = transformer.transform(pg13Ast);
47+
const deparsedSql = await deparse(pg17Ast);
48+
49+
expect(deparsedSql).toBe("SELECT 'hello world'");
50+
});
51+
52+
it('should handle INSERT statements', async () => {
53+
const sql = "INSERT INTO users (name, email) VALUES ('John', '[email protected]')";
54+
55+
const pg13Ast = await pg13Parser.parse(sql);
56+
const pg17Ast = transformer.transform(pg13Ast);
57+
const deparsedSql = await deparse(pg17Ast);
58+
59+
expect(deparsedSql).toBe(sql);
60+
});
61+
62+
it('should handle UPDATE statements', async () => {
63+
const sql = "UPDATE users SET name = 'Jane' WHERE id = 1";
64+
65+
const pg13Ast = await pg13Parser.parse(sql);
66+
const pg17Ast = transformer.transform(pg13Ast);
67+
const deparsedSql = await deparse(pg17Ast);
68+
69+
expect(deparsedSql).toBe(sql);
70+
});
71+
72+
it('should handle DELETE statements', async () => {
73+
const sql = 'DELETE FROM users WHERE id = 1';
74+
75+
const pg13Ast = await pg13Parser.parse(sql);
76+
const pg17Ast = transformer.transform(pg13Ast);
77+
const deparsedSql = await deparse(pg17Ast);
78+
79+
expect(deparsedSql).toBe(sql);
80+
});
81+
});
82+
83+
describe('DDL Operations', () => {
84+
it('should handle CREATE TABLE statements', async () => {
85+
const sql = 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT NOT NULL, email VARCHAR(255))';
86+
87+
const pg13Ast = await pg13Parser.parse(sql);
88+
const pg17Ast = transformer.transform(pg13Ast);
89+
const deparsedSql = await deparse(pg17Ast);
90+
91+
// Note: Exact formatting might differ, but structure should be preserved
92+
expect(deparsedSql).toContain('CREATE TABLE users');
93+
expect(deparsedSql).toContain('id SERIAL PRIMARY KEY');
94+
expect(deparsedSql).toContain('name TEXT NOT NULL');
95+
});
96+
97+
it('should handle ALTER TABLE statements', async () => {
98+
const sql = 'ALTER TABLE users ADD COLUMN email TEXT';
99+
100+
const pg13Ast = await pg13Parser.parse(sql);
101+
const pg17Ast = transformer.transform(pg13Ast);
102+
const deparsedSql = await deparse(pg17Ast);
103+
104+
expect(deparsedSql).toBe(sql);
105+
});
106+
});
107+
108+
describe('Complex Queries', () => {
109+
it('should handle JOINs', async () => {
110+
const sql = 'SELECT * FROM users u JOIN orders o ON u.id = o.user_id';
111+
112+
const pg13Ast = await pg13Parser.parse(sql);
113+
const pg17Ast = transformer.transform(pg13Ast);
114+
const deparsedSql = await deparse(pg17Ast);
115+
116+
expect(deparsedSql).toContain('JOIN');
117+
expect(deparsedSql).toContain('u.id = o.user_id');
118+
});
119+
120+
it('should handle CTEs (Common Table Expressions)', async () => {
121+
const sql = `
122+
WITH user_orders AS (
123+
SELECT u.id, u.name, COUNT(o.id) as order_count
124+
FROM users u
125+
LEFT JOIN orders o ON u.id = o.user_id
126+
GROUP BY u.id, u.name
127+
)
128+
SELECT * FROM user_orders WHERE order_count > 0
129+
`;
130+
131+
const pg13Ast = await pg13Parser.parse(sql);
132+
const pg17Ast = transformer.transform(pg13Ast);
133+
const deparsedSql = await deparse(pg17Ast);
134+
135+
expect(deparsedSql).toContain('WITH user_orders AS');
136+
expect(deparsedSql).toContain('LEFT JOIN');
137+
expect(deparsedSql).toContain('GROUP BY');
138+
});
139+
140+
it('should handle window functions', async () => {
141+
const sql = `
142+
SELECT
143+
name,
144+
salary,
145+
RANK() OVER (ORDER BY salary DESC) as rank
146+
FROM employees
147+
`;
148+
149+
const pg13Ast = await pg13Parser.parse(sql);
150+
const pg17Ast = transformer.transform(pg13Ast);
151+
const deparsedSql = await deparse(pg17Ast);
152+
153+
expect(deparsedSql).toContain('RANK()');
154+
expect(deparsedSql).toContain('OVER');
155+
expect(deparsedSql).toContain('ORDER BY salary DESC');
156+
});
157+
});
158+
159+
describe('Critical Transformation Points', () => {
160+
// These tests focus on the specific changes that happen during transformation
161+
162+
it('should handle A_Const structure changes (PG14→PG15)', async () => {
163+
const sql = "SELECT 'test_string', 42, 3.14";
164+
165+
const pg13Ast = await pg13Parser.parse(sql);
166+
167+
// Verify PG13 structure has nested val
168+
const pg13Constants = extractAConstants(pg13Ast);
169+
expect(pg13Constants.some(c => c.val?.String?.str)).toBe(true);
170+
171+
const pg17Ast = transformer.transform(pg13Ast);
172+
173+
// Verify PG17 structure has flattened sval
174+
const pg17Constants = extractAConstants(pg17Ast);
175+
expect(pg17Constants.some(c => c.sval?.sval)).toBe(true);
176+
177+
const deparsedSql = await deparse(pg17Ast);
178+
expect(deparsedSql).toContain("'test_string'");
179+
expect(deparsedSql).toContain('42');
180+
expect(deparsedSql).toContain('3.14');
181+
});
182+
183+
it('should handle AlterTableStmt objtype field (PG13→PG14)', async () => {
184+
const sql = 'ALTER TABLE users ADD COLUMN email TEXT';
185+
186+
const pg13Ast = await pg13Parser.parse(sql);
187+
const pg17Ast = transformer.transform(pg13Ast);
188+
const deparsedSql = await deparse(pg17Ast);
189+
190+
expect(deparsedSql).toBe(sql);
191+
});
192+
193+
it('should handle publication statement changes (PG14→PG15)', async () => {
194+
const sql = 'ALTER PUBLICATION test_pub ADD TABLE users';
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('ALTER PUBLICATION');
201+
expect(deparsedSql).toContain('ADD TABLE users');
202+
});
203+
});
204+
205+
describe('Error Handling', () => {
206+
it('should handle malformed SQL gracefully', async () => {
207+
const sql = 'SELECT FROM'; // Invalid SQL
208+
209+
await expect(pg13Parser.parse(sql)).rejects.toThrow();
210+
});
211+
212+
it('should preserve AST structure integrity', async () => {
213+
const sql = 'SELECT 1';
214+
215+
const pg13Ast = await pg13Parser.parse(sql);
216+
const pg17Ast = transformer.transform(pg13Ast);
217+
218+
// Verify that the transformed AST is valid for PG17
219+
expect(async () => await deparse(pg17Ast)).not.toThrow();
220+
});
221+
});
222+
223+
describe('Performance and Edge Cases', () => {
224+
it('should handle large complex queries', async () => {
225+
const sql = `
226+
WITH RECURSIVE org_chart AS (
227+
SELECT id, name, manager_id, 0 as level
228+
FROM employees
229+
WHERE manager_id IS NULL
230+
231+
UNION ALL
232+
233+
SELECT e.id, e.name, e.manager_id, oc.level + 1
234+
FROM employees e
235+
JOIN org_chart oc ON e.manager_id = oc.id
236+
)
237+
SELECT
238+
level,
239+
name,
240+
COUNT(*) OVER (PARTITION BY level) as peers_count,
241+
LAG(name) OVER (ORDER BY level, name) as previous_employee
242+
FROM org_chart
243+
ORDER BY level, name
244+
LIMIT 100
245+
`;
246+
247+
const pg13Ast = await pg13Parser.parse(sql);
248+
const pg17Ast = transformer.transform(pg13Ast);
249+
const deparsedSql = await deparse(pg17Ast);
250+
251+
expect(deparsedSql).toContain('WITH RECURSIVE');
252+
expect(deparsedSql).toContain('UNION ALL');
253+
expect(deparsedSql).toContain('COUNT(*) OVER');
254+
expect(deparsedSql).toContain('LIMIT 100');
255+
});
256+
257+
it('should handle PostgreSQL-specific features', async () => {
258+
const sql = `
259+
SELECT
260+
ARRAY[1,2,3] as numbers,
261+
'{"key": "value"}'::jsonb as data,
262+
generate_series(1, 10) as series
263+
`;
264+
265+
const pg13Ast = await pg13Parser.parse(sql);
266+
const pg17Ast = transformer.transform(pg13Ast);
267+
const deparsedSql = await deparse(pg17Ast);
268+
269+
expect(deparsedSql).toContain('ARRAY[1,2,3]');
270+
expect(deparsedSql).toContain('::jsonb');
271+
expect(deparsedSql).toContain('generate_series');
272+
});
273+
});
274+
});
275+
276+
// Helper functions for testing
277+
function extractAConstants(ast: any): any[] {
278+
const constants: any[] = [];
279+
280+
function traverse(obj: any) {
281+
if (!obj || typeof obj !== 'object') return;
282+
283+
if (obj.A_Const) {
284+
constants.push(obj.A_Const);
285+
}
286+
287+
if (Array.isArray(obj)) {
288+
obj.forEach(traverse);
289+
} else {
290+
Object.values(obj).forEach(traverse);
291+
}
292+
}
293+
294+
traverse(ast);
295+
return constants;
296+
}
297+
298+
// TODO: Implement these classes and features
299+
// - PG13ToPG17Transformer (composite transformer)
300+
// - Individual transformers (V13ToV14Transformer, etc.)
301+
// - Proper type definitions for all PG versions
302+
// - Error handling and validation
303+
// - Performance optimizations
304+
// - AST validation utilities
305+
// - Transformation verification helpers

packages/transform/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"test:watch": "jest --watch"
3232
},
3333
"devDependencies": {
34-
"@pgsql/parser": "1.0.2",
34+
"@pgsql/parser": "^1.0.2",
35+
"pgsql-deparser": "^17.8.1",
3536
"pg-proto-parser": "^1.29.1"
3637
},
3738
"keywords": []

0 commit comments

Comments
 (0)