Skip to content

Commit c1698f9

Browse files
committed
feat(plpgsql-deparser): include full CREATE FUNCTION in hydrate demo
- Parse full SQL statement to get CREATE FUNCTION wrapper - Modify function name: big_kitchen_sink -> big_kitchen_sink_MODIFIED - Include RETURNS TABLE clause in snapshot - Demonstrate full pipeline: SQL parse -> PL/pgSQL hydrate -> modify -> dehydrate -> SQL deparse
1 parent bf3c77d commit c1698f9

2 files changed

Lines changed: 36 additions & 14 deletions

File tree

packages/plpgsql-deparser/__tests__/__snapshots__/hydrate-demo.test.ts.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
22

3-
exports[`hydrate demonstration with big-function.sql should parse, hydrate, modify, and deparse big-function.sql 1`] = `
4-
"DECLARE
3+
exports[`hydrate demonstration with big-function.sql should parse, hydrate, modify, and deparse big-function.sql with full CREATE FUNCTION 1`] = `
4+
"CREATE OR REPLACE FUNCTION app_public."big_kitchen_sink_MODIFIED"(p_org_id uuid, p_user_id uuid, p_from_ts timestamptz DEFAULT now() - '30 days'::interval, p_to_ts timestamptz DEFAULT now(), p_min_total numeric DEFAULT 0, p_max_rows int DEFAULT 250, p_currency text DEFAULT 'USD', p_apply_discount boolean DEFAULT true, p_discount_rate numeric DEFAULT 0.05, p_tax_rate numeric DEFAULT 0.0875, p_round_to int DEFAULT 2, p_note text DEFAULT NULL, p_lock boolean DEFAULT false, p_debug boolean DEFAULT false) RETURNS TABLE ( org_id uuid, user_id uuid, period_from timestamptz, period_to timestamptz, orders_scanned int, orders_upserted int, gross_total numeric, discount_total numeric, tax_total numeric, net_total numeric, avg_order_total numeric, top_sku text, top_sku_qty bigint, message text ) LANGUAGE plpgsql AS $$DECLARE
55
v_orders_scanned int := 888;
66
v_orders_upserted int := 888;
77
v_gross numeric := 888;
@@ -167,5 +167,5 @@ END IF;
167167
RETURN;
168168
END;
169169
RETURN;
170-
END"
170+
END$$"
171171
`;

packages/plpgsql-deparser/__tests__/hydrate-demo.test.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { loadModule, parsePlPgSQLSync } from '@libpg-query/parser';
1+
import { loadModule, parsePlPgSQLSync, parseSync } from '@libpg-query/parser';
2+
import { deparse } from 'pgsql-deparser';
23
import * as fs from 'fs';
34
import * as path from 'path';
45
import { hydratePlpgsqlAst, dehydratePlpgsqlAst, PLpgSQLParseResult, deparseSync } from '../src';
@@ -8,13 +9,23 @@ describe('hydrate demonstration with big-function.sql', () => {
89
await loadModule();
910
});
1011

11-
it('should parse, hydrate, modify, and deparse big-function.sql', () => {
12+
it('should parse, hydrate, modify, and deparse big-function.sql with full CREATE FUNCTION', async () => {
1213
const fixturePath = path.join(__dirname, '../../../__fixtures__/plpgsql-pretty/big-function.sql');
1314
const sql = fs.readFileSync(fixturePath, 'utf-8');
1415

15-
const parsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
16+
const sqlParsed = parseSync(sql) as any;
17+
const createFunctionStmt = sqlParsed.stmts[0].stmt.CreateFunctionStmt;
1618

17-
const { ast: hydratedAst, stats } = hydratePlpgsqlAst(parsed);
19+
const asOption = createFunctionStmt.options.find(
20+
(opt: any) => opt.DefElem?.defname === 'as'
21+
);
22+
const plpgsqlBody = asOption?.DefElem?.arg?.List?.items?.[0]?.String?.sval;
23+
24+
expect(plpgsqlBody).toBeDefined();
25+
26+
const plpgsqlParsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
27+
28+
const { ast: hydratedAst, stats } = hydratePlpgsqlAst(plpgsqlParsed);
1829

1930
expect(stats.totalExpressions).toBe(68);
2031
expect(stats.parsedExpressions).toBe(68);
@@ -23,17 +34,28 @@ describe('hydrate demonstration with big-function.sql', () => {
2334
expect(stats.failedExpressions).toBe(0);
2435
expect(stats.rawExpressions).toBe(0);
2536

26-
const modifiedAst = modifyAst(JSON.parse(JSON.stringify(hydratedAst)));
37+
createFunctionStmt.funcname[1].String.sval = 'big_kitchen_sink_MODIFIED';
38+
39+
const modifiedPlpgsqlAst = modifyAst(JSON.parse(JSON.stringify(hydratedAst)));
2740

28-
const dehydratedAst = dehydratePlpgsqlAst(modifiedAst);
41+
const dehydratedAst = dehydratePlpgsqlAst(modifiedPlpgsqlAst);
42+
43+
const modifiedBody = deparseSync(dehydratedAst);
44+
45+
if (asOption?.DefElem?.arg?.List?.items?.[0]?.String) {
46+
asOption.DefElem.arg.List.items[0].String.sval = modifiedBody;
47+
}
2948

30-
const deparsed = deparseSync(dehydratedAst);
49+
const fullDeparsed = await deparse(sqlParsed.stmts[0].stmt);
3150

32-
expect(deparsed).toContain('v_discount_MODIFIED');
33-
expect(deparsed).toContain('v_tax_MODIFIED');
34-
expect(deparsed).toContain('888');
51+
expect(fullDeparsed).toContain('big_kitchen_sink_MODIFIED');
52+
expect(fullDeparsed).toContain('RETURNS TABLE');
53+
expect(fullDeparsed).toContain('CREATE OR REPLACE FUNCTION');
54+
expect(fullDeparsed).toContain('v_discount_MODIFIED');
55+
expect(fullDeparsed).toContain('v_tax_MODIFIED');
56+
expect(fullDeparsed).toContain('888');
3557

36-
expect(deparsed).toMatchSnapshot();
58+
expect(fullDeparsed).toMatchSnapshot();
3759
});
3860
});
3961

0 commit comments

Comments
 (0)