Skip to content

Commit d5d94d1

Browse files
committed
full transformers
1 parent 3c4c2b9 commit d5d94d1

File tree

8 files changed

+454
-0
lines changed

8 files changed

+454
-0
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { Parser } from '@pgsql/parser';
2+
import {
3+
PG13ToPG17Transformer,
4+
PG14ToPG17Transformer,
5+
PG15ToPG17Transformer,
6+
PG16ToPG17Transformer
7+
} from '../src/transformers-full';
8+
9+
describe('Direct Transformers', () => {
10+
const testSQL = 'SELECT id, name FROM users WHERE active = true';
11+
12+
describe('PG16ToPG17Transformer', () => {
13+
it('should transform PG16 AST to PG17', async () => {
14+
const pg16Parser = new Parser({ version: 16 });
15+
16+
const pg16Ast = await pg16Parser.parse(testSQL);
17+
const transformer = new PG16ToPG17Transformer();
18+
const transformedAst = transformer.transform(pg16Ast);
19+
20+
expect(transformedAst.version).toBe(170004);
21+
expect(transformedAst.stmts).toBeDefined();
22+
expect(transformedAst.stmts.length).toBe(1);
23+
24+
// Verify the structure is preserved
25+
expect(transformedAst.stmts[0].stmt).toBeDefined();
26+
const stmt = transformedAst.stmts[0].stmt as any;
27+
expect(stmt.SelectStmt).toBeDefined();
28+
});
29+
});
30+
31+
describe('PG15ToPG17Transformer', () => {
32+
it('should transform PG15 AST to PG17', async () => {
33+
const pg15Parser = new Parser({ version: 15 });
34+
35+
const pg15Ast = await pg15Parser.parse(testSQL);
36+
const transformer = new PG15ToPG17Transformer();
37+
const transformedAst = transformer.transform(pg15Ast);
38+
39+
expect(transformedAst.version).toBe(170004);
40+
expect(transformedAst.stmts).toBeDefined();
41+
expect(transformedAst.stmts.length).toBe(1);
42+
43+
// Verify the structure is preserved
44+
expect(transformedAst.stmts[0].stmt).toBeDefined();
45+
const stmt = transformedAst.stmts[0].stmt as any;
46+
expect(stmt.SelectStmt).toBeDefined();
47+
});
48+
});
49+
50+
describe('PG14ToPG17Transformer', () => {
51+
it('should transform PG14 AST to PG17', async () => {
52+
const pg14Parser = new Parser({ version: 14 });
53+
54+
const pg14Ast = await pg14Parser.parse(testSQL);
55+
const transformer = new PG14ToPG17Transformer();
56+
const transformedAst = transformer.transform(pg14Ast);
57+
58+
expect(transformedAst.version).toBe(170004);
59+
expect(transformedAst.stmts).toBeDefined();
60+
expect(transformedAst.stmts.length).toBe(1);
61+
62+
// Verify the structure is preserved
63+
expect(transformedAst.stmts[0].stmt).toBeDefined();
64+
const stmt = transformedAst.stmts[0].stmt as any;
65+
expect(stmt.SelectStmt).toBeDefined();
66+
});
67+
});
68+
69+
describe('PG13ToPG17Transformer', () => {
70+
it('should transform PG13 AST to PG17', async () => {
71+
const pg13Parser = new Parser({ version: 13 });
72+
73+
const pg13Ast = await pg13Parser.parse(testSQL);
74+
const transformer = new PG13ToPG17Transformer();
75+
const transformedAst = transformer.transform(pg13Ast);
76+
77+
expect(transformedAst.version).toBe(170004);
78+
expect(transformedAst.stmts).toBeDefined();
79+
expect(transformedAst.stmts.length).toBe(1);
80+
81+
// Verify the structure is preserved
82+
expect(transformedAst.stmts[0].stmt).toBeDefined();
83+
const stmt = transformedAst.stmts[0].stmt as any;
84+
expect(stmt.SelectStmt).toBeDefined();
85+
});
86+
});
87+
88+
describe('transformStatement method', () => {
89+
it('should transform individual statements', async () => {
90+
const pg15Parser = new Parser({ version: 15 });
91+
const pg15Ast = await pg15Parser.parse(testSQL);
92+
93+
const transformer = new PG15ToPG17Transformer();
94+
const stmt = pg15Ast.stmts[0].stmt;
95+
const transformedStmt = transformer.transformStatement(stmt);
96+
97+
expect(transformedStmt).toBeDefined();
98+
// The transformed statement should have the same top-level structure
99+
expect(Object.keys(transformedStmt)).toEqual(Object.keys(stmt));
100+
});
101+
});
102+
103+
describe('Error handling', () => {
104+
it('should throw error for invalid parse result', () => {
105+
const transformer = new PG15ToPG17Transformer();
106+
107+
expect(() => transformer.transform(null as any)).toThrow('Invalid parse result');
108+
expect(() => transformer.transform({} as any)).toThrow('Invalid parse result');
109+
expect(() => transformer.transform({ version: 150001 } as any)).toThrow('Invalid parse result');
110+
});
111+
});
112+
});

packages/transform/src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ export { V14ToV15Transformer } from './transformers/v14-to-v15';
1616
export { V15ToV16Transformer } from './transformers/v15-to-v16';
1717
export { V16ToV17Transformer } from './transformers/v16-to-v17';
1818

19+
export { PG13ToPG17Transformer as DirectPG13ToPG17Transformer } from './transformers-full/v13-to-v17';
20+
export { PG14ToPG17Transformer as DirectPG14ToPG17Transformer } from './transformers-full/v14-to-v17';
21+
export { PG15ToPG17Transformer as DirectPG15ToPG17Transformer } from './transformers-full/v15-to-v17';
22+
export { PG16ToPG17Transformer as DirectPG16ToPG17Transformer } from './transformers-full/v16-to-v17';
23+
1924
export { PG13Node, PG14Node, PG15Node, PG16Node, PG17Node, PG13Types, PG14Types, PG15Types, PG16Types, PG17Types };
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Direct Transformers
2+
3+
This directory contains optimized, direct transformers for upgrading PostgreSQL ASTs from specific versions directly to PG17. These transformers are designed to support tree-shaking, allowing you to import only the transformer you need without pulling in unnecessary code for other version transformations.
4+
5+
## Available Transformers
6+
7+
- **PG13ToPG17Transformer**: Transforms ASTs from PostgreSQL 13 to 17
8+
- **PG14ToPG17Transformer**: Transforms ASTs from PostgreSQL 14 to 17
9+
- **PG15ToPG17Transformer**: Transforms ASTs from PostgreSQL 15 to 17
10+
- **PG16ToPG17Transformer**: Transforms ASTs from PostgreSQL 16 to 17
11+
12+
## Usage
13+
14+
### Basic Usage
15+
16+
```typescript
17+
import { PG15ToPG17Transformer } from '@pgsql/transform/transformers-direct/v15-to-v17';
18+
import { Parser } from '@pgsql/parser';
19+
20+
// Parse with PG15
21+
const pg15Parser = new Parser({ version: 15 });
22+
const pg15Ast = await pg15Parser.parse('SELECT * FROM users');
23+
24+
// Transform to PG17
25+
const transformer = new PG15ToPG17Transformer();
26+
const pg17Ast = transformer.transform(pg15Ast);
27+
```
28+
29+
### Using Pre-instantiated Transformers
30+
31+
For convenience, each module also exports a pre-instantiated transformer:
32+
33+
```typescript
34+
import { pg15ToPg17Transformer } from '@pgsql/transform/transformers-direct/v15-to-v17';
35+
36+
const pg17Ast = pg15ToPg17Transformer.transform(pg15Ast);
37+
```
38+
39+
### Transforming Individual Statements
40+
41+
You can also transform individual statements without the parse result wrapper:
42+
43+
```typescript
44+
import { PG15ToPG17Transformer } from '@pgsql/transform/transformers-direct/v15-to-v17';
45+
46+
const transformer = new PG15ToPG17Transformer();
47+
const transformedStmt = transformer.transformStatement(selectStmt);
48+
```
49+
50+
## Tree-Shaking Benefits
51+
52+
By importing only the specific transformer you need, your bundle will only include:
53+
54+
- The transformer for your specific version upgrade path
55+
- Only the intermediate transformers needed for that path
56+
- Only the type definitions for your source and target versions
57+
58+
For example:
59+
- Importing `PG16ToPG17Transformer` only includes the v16->v17 transformer
60+
- Importing `PG15ToPG17Transformer` includes v15->v16 and v16->v17 transformers
61+
- Importing `PG14ToPG17Transformer` includes v14->v15, v15->v16, and v16->v17 transformers
62+
- Importing `PG13ToPG17Transformer` includes all transformers in the chain
63+
64+
## Type Safety
65+
66+
Each transformer is fully typed with the appropriate input and output types:
67+
68+
```typescript
69+
import { PG15ToPG17Transformer } from '@pgsql/transform/transformers-direct/v15-to-v17';
70+
import type { ParseResult as PG15ParseResult } from '@pgsql/transform/15/types';
71+
import type { ParseResult as PG17ParseResult } from '@pgsql/transform/17/types';
72+
73+
const transformer = new PG15ToPG17Transformer();
74+
75+
// Type-safe transformation
76+
const transform = (pg15Ast: PG15ParseResult): PG17ParseResult => {
77+
return transformer.transform(pg15Ast);
78+
};
79+
```
80+
81+
## Implementation Details
82+
83+
Each direct transformer:
84+
1. Chains the necessary intermediate transformers internally
85+
2. Handles the parse result structure with `stmts` array
86+
3. Updates the version number to PG17 (170004)
87+
4. Preserves all other properties of the parse result
88+
89+
The transformers are implemented as separate modules to ensure proper tree-shaking by modern bundlers.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Direct transformers for specific version upgrades to PG17
3+
*
4+
* These transformers are optimized for tree-shaking, allowing users to import
5+
* only the specific transformer they need without pulling in unnecessary code.
6+
*
7+
* Example usage:
8+
* ```typescript
9+
* // Import only the transformer you need
10+
* import { PG15ToPG17Transformer } from '@pgsql/transform/transformers-direct/v15-to-v17';
11+
*
12+
* const transformer = new PG15ToPG17Transformer();
13+
* const pg17Ast = transformer.transform(pg15ParseResult);
14+
* ```
15+
*/
16+
17+
// Export individual transformers
18+
export { PG13ToPG17Transformer, pg13ToPg17Transformer } from './v13-to-v17';
19+
export { PG14ToPG17Transformer, pg14ToPg17Transformer } from './v14-to-v17';
20+
export { PG15ToPG17Transformer, pg15ToPg17Transformer } from './v15-to-v17';
21+
export { PG16ToPG17Transformer, pg16ToPg17Transformer } from './v16-to-v17';
22+
23+
// Re-export types for convenience
24+
export * as V13Types from '../13/types';
25+
export * as V14Types from '../14/types';
26+
export * as V15Types from '../15/types';
27+
export * as V16Types from '../16/types';
28+
export * as V17Types from '../17/types';
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import * as V13Types from '../../13/types';
2+
import * as V17Types from '../../17/types';
3+
import { V13ToV14Transformer } from '../../transformers/v13-to-v14';
4+
import { V14ToV15Transformer } from '../../transformers/v14-to-v15';
5+
import { V15ToV16Transformer } from '../../transformers/v15-to-v16';
6+
import { V16ToV17Transformer } from '../../transformers/v16-to-v17';
7+
8+
/**
9+
* Direct transformer from PG13 to PG17
10+
* This transformer chains v13->v14, v14->v15, v15->v16, and v16->v17 transformations
11+
*/
12+
export class PG13ToPG17Transformer {
13+
private v13ToV14 = new V13ToV14Transformer();
14+
private v14ToV15 = new V14ToV15Transformer();
15+
private v15ToV16 = new V15ToV16Transformer();
16+
private v16ToV17 = new V16ToV17Transformer();
17+
18+
/**
19+
* Transform a complete parse result from PG13 to PG17
20+
*/
21+
transform(parseResult: V13Types.ParseResult): V17Types.ParseResult {
22+
if (!parseResult || !parseResult.stmts) {
23+
throw new Error('Invalid parse result');
24+
}
25+
26+
const transformedStmts = parseResult.stmts.map((stmtWrapper: any) => {
27+
if (stmtWrapper.stmt) {
28+
// Chain transformations: v13 -> v14 -> v15 -> v16 -> v17
29+
let transformedStmt = this.v13ToV14.transform(stmtWrapper.stmt, { parentNodeTypes: [] });
30+
transformedStmt = this.v14ToV15.transform(transformedStmt, { parentNodeTypes: [] });
31+
transformedStmt = this.v15ToV16.transform(transformedStmt, { parentNodeTypes: [] });
32+
transformedStmt = this.v16ToV17.transform(transformedStmt, { parentNodeTypes: [] });
33+
return { ...stmtWrapper, stmt: transformedStmt };
34+
}
35+
return stmtWrapper;
36+
});
37+
38+
return {
39+
...parseResult,
40+
version: 170004, // PG17 version
41+
stmts: transformedStmts
42+
};
43+
}
44+
45+
/**
46+
* Transform a single statement from PG13 to PG17
47+
*/
48+
transformStatement(stmt: any): any {
49+
// Chain transformations: v13 -> v14 -> v15 -> v16 -> v17
50+
let transformedStmt = this.v13ToV14.transform(stmt, { parentNodeTypes: [] });
51+
transformedStmt = this.v14ToV15.transform(transformedStmt, { parentNodeTypes: [] });
52+
transformedStmt = this.v15ToV16.transform(transformedStmt, { parentNodeTypes: [] });
53+
return this.v16ToV17.transform(transformedStmt, { parentNodeTypes: [] });
54+
}
55+
}
56+
57+
// Export the transformer instance for convenience
58+
export const pg13ToPg17Transformer = new PG13ToPG17Transformer();
59+
60+
// Re-export types for convenience
61+
export { V13Types, V17Types };
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import * as V14Types from '../../14/types';
2+
import * as V17Types from '../../17/types';
3+
import { V14ToV15Transformer } from '../../transformers/v14-to-v15';
4+
import { V15ToV16Transformer } from '../../transformers/v15-to-v16';
5+
import { V16ToV17Transformer } from '../../transformers/v16-to-v17';
6+
7+
/**
8+
* Direct transformer from PG14 to PG17
9+
* This transformer chains v14->v15, v15->v16, and v16->v17 transformations
10+
*/
11+
export class PG14ToPG17Transformer {
12+
private v14ToV15 = new V14ToV15Transformer();
13+
private v15ToV16 = new V15ToV16Transformer();
14+
private v16ToV17 = new V16ToV17Transformer();
15+
16+
/**
17+
* Transform a complete parse result from PG14 to PG17
18+
*/
19+
transform(parseResult: V14Types.ParseResult): V17Types.ParseResult {
20+
if (!parseResult || !parseResult.stmts) {
21+
throw new Error('Invalid parse result');
22+
}
23+
24+
const transformedStmts = parseResult.stmts.map((stmtWrapper: any) => {
25+
if (stmtWrapper.stmt) {
26+
// Chain transformations: v14 -> v15 -> v16 -> v17
27+
let transformedStmt = this.v14ToV15.transform(stmtWrapper.stmt, { parentNodeTypes: [] });
28+
transformedStmt = this.v15ToV16.transform(transformedStmt, { parentNodeTypes: [] });
29+
transformedStmt = this.v16ToV17.transform(transformedStmt, { parentNodeTypes: [] });
30+
return { ...stmtWrapper, stmt: transformedStmt };
31+
}
32+
return stmtWrapper;
33+
});
34+
35+
return {
36+
...parseResult,
37+
version: 170004, // PG17 version
38+
stmts: transformedStmts
39+
};
40+
}
41+
42+
/**
43+
* Transform a single statement from PG14 to PG17
44+
*/
45+
transformStatement(stmt: any): any {
46+
// Chain transformations: v14 -> v15 -> v16 -> v17
47+
let transformedStmt = this.v14ToV15.transform(stmt, { parentNodeTypes: [] });
48+
transformedStmt = this.v15ToV16.transform(transformedStmt, { parentNodeTypes: [] });
49+
return this.v16ToV17.transform(transformedStmt, { parentNodeTypes: [] });
50+
}
51+
}
52+
53+
// Export the transformer instance for convenience
54+
export const pg14ToPg17Transformer = new PG14ToPG17Transformer();
55+
56+
// Re-export types for convenience
57+
export { V14Types, V17Types };

0 commit comments

Comments
 (0)