Skip to content

Commit 6eb2cba

Browse files
committed
test: add CoalesceExpr and RangeFunction round-trip fixtures
Add 9 new PL/pgSQL test fixtures exercising expression patterns that were causing UNSUPPORTED_EXPRESSION errors in constructive-db's deparser: - Test 38: COALESCE inside FuncCall arguments (RETURN QUERY) - Test 39: FuncCall in FROM clause (RangeFunction) - Test 40: COALESCE + FuncCall in FROM clause (combined) - Test 41: COALESCE + SRF in SELECT INTO - Test 42: Multiple SRFs in FROM clause - Test 43: COALESCE with function call in assignment - Test 44: Nested COALESCE expressions - Test 45: SELECT INTO from SRF in FROM clause - Test 46: FOR loop with SRF and WHERE filter All 9 patterns round-trip correctly through parse → deparse → reparse, confirming pgsql-parser handles these AST node combinations. The issue in constructive-db is in the SQL-level deparser, not upstream. 8 new snapshot tests added to deparser-fixes.test.ts with explicit assertions for COALESCE, FROM, and function name preservation. Ref: constructive-io/constructive-planning#896
1 parent 7ee33c0 commit 6eb2cba

4 files changed

Lines changed: 312 additions & 0 deletions

File tree

__fixtures__/plpgsql-generated/generated.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@
136136
"plpgsql_deparser_fixes-35.sql": "-- Test 35: CALL statement\nCREATE FUNCTION test_call_statement() RETURNS void\nLANGUAGE plpgsql AS $$\nBEGIN\n CALL my_procedure(1, 'hello');\n RETURN;\nEND$$",
137137
"plpgsql_deparser_fixes-36.sql": "-- =============================================================================\n-- Edge Case Tests: Real-World Patterns\n-- =============================================================================\n\n-- Test 36: Permission bitnum trigger pattern (the function that exposed the END; bug)\nCREATE FUNCTION test_permission_bitnum_trigger() RETURNS trigger\nLANGUAGE plpgsql AS $$\nDECLARE\n bitlen int;\n v_len int;\nBEGIN\n v_len := 32;\n BEGIN\n bitlen := bit_length(NEW.bitstr);\n EXCEPTION\n WHEN others THEN\n bitlen := 0;\n END;\n IF bitlen = 0 THEN\n NEW.bitstr := lpad('', v_len, '0');\n END IF;\n RETURN NEW;\nEND$$",
138138
"plpgsql_deparser_fixes-37.sql": "-- Test 37: Multi-step sign-in pattern (deeply nested IF chains)\nCREATE FUNCTION test_signin_pattern(v_email text) RETURNS record\nLANGUAGE plpgsql AS $$\nDECLARE\n v_user record;\n v_secret record;\nBEGIN\n SELECT * INTO v_user FROM users WHERE email = v_email;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'USER_NOT_FOUND';\n END IF;\n SELECT * INTO v_secret FROM secrets WHERE user_id = v_user.id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'NO_CREDENTIALS';\n END IF;\n IF v_secret.locked_at IS NOT NULL THEN\n RAISE EXCEPTION 'ACCOUNT_LOCKED';\n END IF;\n RETURN v_user;\nEND$$",
139+
"plpgsql_deparser_fixes-38.sql": "-- Test 38: COALESCE inside function call arguments\n-- Exercises CoalesceExpr as a FuncCall arg (e.g. jsonb_array_elements(COALESCE(v_config, '[]')))\nCREATE FUNCTION test_coalesce_in_func_args(v_config jsonb) RETURNS SETOF jsonb\nLANGUAGE plpgsql AS $$\nBEGIN\n RETURN QUERY SELECT jsonb_array_elements(COALESCE(v_config, '[]'::jsonb));\nEND$$",
140+
"plpgsql_deparser_fixes-39.sql": "-- Test 39: Set-returning function call in FROM clause (RangeFunction)\n-- Exercises FuncCall inside RangeFunction for set-returning functions\nCREATE FUNCTION test_func_in_from_clause(v_data jsonb) RETURNS TABLE(key text, value text)\nLANGUAGE plpgsql AS $$\nBEGIN\n RETURN QUERY SELECT elem->>'key', elem->>'value'\n FROM jsonb_array_elements(v_data) AS elem;\nEND$$",
141+
"plpgsql_deparser_fixes-40.sql": "-- Test 40: COALESCE in FROM clause with set-returning function (combined pattern)\nCREATE FUNCTION test_coalesce_in_from_srf(v_config jsonb) RETURNS TABLE(entry jsonb)\nLANGUAGE plpgsql AS $$\nBEGIN\n RETURN QUERY SELECT elem\n FROM jsonb_array_elements(COALESCE(v_config, '[]'::jsonb)) AS elem;\nEND$$",
142+
"plpgsql_deparser_fixes-41.sql": "-- Test 41: FOR loop with set-returning function and COALESCE in SELECT INTO\nCREATE FUNCTION test_for_loop_srf_coalesce(v_items jsonb) RETURNS integer\nLANGUAGE plpgsql AS $$\nDECLARE\n v_count integer;\nBEGIN\n SELECT count(*) INTO v_count\n FROM jsonb_array_elements(COALESCE(v_items, '[]'::jsonb)) AS elem;\n RETURN v_count;\nEND$$",
143+
"plpgsql_deparser_fixes-42.sql": "-- Test 42: Multiple set-returning functions in FROM clause\nCREATE FUNCTION test_multiple_srf_from(v_keys text[], v_values text[]) RETURNS TABLE(k text, v text)\nLANGUAGE plpgsql AS $$\nBEGIN\n RETURN QUERY SELECT unnest_k, unnest_v\n FROM unnest(v_keys) AS unnest_k, unnest(v_values) AS unnest_v;\nEND$$",
144+
"plpgsql_deparser_fixes-43.sql": "-- Test 43: COALESCE in assignment with function call\nCREATE FUNCTION test_coalesce_assign_func() RETURNS trigger\nLANGUAGE plpgsql AS $$\nBEGIN\n NEW.updated_at := COALESCE(NEW.updated_at, now());\n NEW.name := COALESCE(NEW.name, 'default_' || NEW.id::text);\n RETURN NEW;\nEND$$",
145+
"plpgsql_deparser_fixes-44.sql": "-- Test 44: Nested COALESCE expressions\nCREATE FUNCTION test_nested_coalesce(a text, b text, c text) RETURNS text\nLANGUAGE plpgsql AS $$\nBEGIN\n RETURN COALESCE(a, COALESCE(b, COALESCE(c, 'fallback')));\nEND$$",
146+
"plpgsql_deparser_fixes-45.sql": "-- Test 45: SELECT INTO with COALESCE and function call in FROM\nCREATE FUNCTION test_select_into_from_srf(v_data jsonb) RETURNS jsonb\nLANGUAGE plpgsql AS $$\nDECLARE\n v_first jsonb;\nBEGIN\n SELECT elem INTO v_first\n FROM jsonb_array_elements(v_data) AS elem\n LIMIT 1;\n RETURN v_first;\nEND$$",
147+
"plpgsql_deparser_fixes-46.sql": "-- Test 46: FOR loop with jsonb_array_elements and WHERE filter\nCREATE FUNCTION test_for_srf_with_filter(v_config jsonb, v_key text) RETURNS jsonb\nLANGUAGE plpgsql AS $$\nDECLARE\n v_entry jsonb;\nBEGIN\n FOR v_entry IN\n SELECT elem FROM jsonb_array_elements(v_config) AS elem\n WHERE elem->>'key' = v_key\n LOOP\n RETURN v_entry;\n END LOOP;\n RETURN NULL;\nEND$$",
139148
"plpgsql_control-1.sql": "--\n-- Tests for PL/pgSQL control structures\n--\n\n-- integer FOR loop\n\ndo $$\nbegin\n -- basic case\n for i in 1..3 loop\n raise notice '1..3: i = %', i;\n end loop;\n -- with BY, end matches exactly\n for i in 1..10 by 3 loop\n raise notice '1..10 by 3: i = %', i;\n end loop;\n -- with BY, end does not match\n for i in 1..11 by 3 loop\n raise notice '1..11 by 3: i = %', i;\n end loop;\n -- zero iterations\n for i in 1..0 by 3 loop\n raise notice '1..0 by 3: i = %', i;\n end loop;\n -- REVERSE\n for i in reverse 10..0 by 3 loop\n raise notice 'reverse 10..0 by 3: i = %', i;\n end loop;\n -- potential overflow\n for i in 2147483620..2147483647 by 10 loop\n raise notice '2147483620..2147483647 by 10: i = %', i;\n end loop;\n -- potential overflow, reverse direction\n for i in reverse -2147483620..-2147483647 by 10 loop\n raise notice 'reverse -2147483620..-2147483647 by 10: i = %', i;\n end loop;\nend$$",
140149
"plpgsql_control-2.sql": "-- BY can't be zero or negative\ndo $$\nbegin\n for i in 1..3 by 0 loop\n raise notice '1..3 by 0: i = %', i;\n end loop;\nend$$",
141150
"plpgsql_control-3.sql": "do $$\nbegin\n for i in 1..3 by -1 loop\n raise notice '1..3 by -1: i = %', i;\n end loop;\nend$$",

__fixtures__/plpgsql/plpgsql_deparser_fixes.sql

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,3 +505,90 @@ BEGIN
505505
END IF;
506506
RETURN v_user;
507507
END$$;
508+
509+
-- Test 38: COALESCE inside function call arguments
510+
-- Exercises CoalesceExpr as a FuncCall arg (e.g. jsonb_array_elements(COALESCE(v_config, '[]')))
511+
CREATE FUNCTION test_coalesce_in_func_args(v_config jsonb) RETURNS SETOF jsonb
512+
LANGUAGE plpgsql AS $$
513+
BEGIN
514+
RETURN QUERY SELECT jsonb_array_elements(COALESCE(v_config, '[]'::jsonb));
515+
END$$;
516+
517+
-- Test 39: Set-returning function call in FROM clause (RangeFunction)
518+
-- Exercises FuncCall inside RangeFunction for set-returning functions
519+
CREATE FUNCTION test_func_in_from_clause(v_data jsonb) RETURNS TABLE(key text, value text)
520+
LANGUAGE plpgsql AS $$
521+
BEGIN
522+
RETURN QUERY SELECT elem->>'key', elem->>'value'
523+
FROM jsonb_array_elements(v_data) AS elem;
524+
END$$;
525+
526+
-- Test 40: COALESCE in FROM clause with set-returning function (combined pattern)
527+
CREATE FUNCTION test_coalesce_in_from_srf(v_config jsonb) RETURNS TABLE(entry jsonb)
528+
LANGUAGE plpgsql AS $$
529+
BEGIN
530+
RETURN QUERY SELECT elem
531+
FROM jsonb_array_elements(COALESCE(v_config, '[]'::jsonb)) AS elem;
532+
END$$;
533+
534+
-- Test 41: FOR loop with set-returning function and COALESCE in SELECT INTO
535+
CREATE FUNCTION test_for_loop_srf_coalesce(v_items jsonb) RETURNS integer
536+
LANGUAGE plpgsql AS $$
537+
DECLARE
538+
v_count integer;
539+
BEGIN
540+
SELECT count(*) INTO v_count
541+
FROM jsonb_array_elements(COALESCE(v_items, '[]'::jsonb)) AS elem;
542+
RETURN v_count;
543+
END$$;
544+
545+
-- Test 42: Multiple set-returning functions in FROM clause
546+
CREATE FUNCTION test_multiple_srf_from(v_keys text[], v_values text[]) RETURNS TABLE(k text, v text)
547+
LANGUAGE plpgsql AS $$
548+
BEGIN
549+
RETURN QUERY SELECT unnest_k, unnest_v
550+
FROM unnest(v_keys) AS unnest_k, unnest(v_values) AS unnest_v;
551+
END$$;
552+
553+
-- Test 43: COALESCE in assignment with function call
554+
CREATE FUNCTION test_coalesce_assign_func() RETURNS trigger
555+
LANGUAGE plpgsql AS $$
556+
BEGIN
557+
NEW.updated_at := COALESCE(NEW.updated_at, now());
558+
NEW.name := COALESCE(NEW.name, 'default_' || NEW.id::text);
559+
RETURN NEW;
560+
END$$;
561+
562+
-- Test 44: Nested COALESCE expressions
563+
CREATE FUNCTION test_nested_coalesce(a text, b text, c text) RETURNS text
564+
LANGUAGE plpgsql AS $$
565+
BEGIN
566+
RETURN COALESCE(a, COALESCE(b, COALESCE(c, 'fallback')));
567+
END$$;
568+
569+
-- Test 45: SELECT INTO with COALESCE and function call in FROM
570+
CREATE FUNCTION test_select_into_from_srf(v_data jsonb) RETURNS jsonb
571+
LANGUAGE plpgsql AS $$
572+
DECLARE
573+
v_first jsonb;
574+
BEGIN
575+
SELECT elem INTO v_first
576+
FROM jsonb_array_elements(v_data) AS elem
577+
LIMIT 1;
578+
RETURN v_first;
579+
END$$;
580+
581+
-- Test 46: FOR loop with jsonb_array_elements and WHERE filter
582+
CREATE FUNCTION test_for_srf_with_filter(v_config jsonb, v_key text) RETURNS jsonb
583+
LANGUAGE plpgsql AS $$
584+
DECLARE
585+
v_entry jsonb;
586+
BEGIN
587+
FOR v_entry IN
588+
SELECT elem FROM jsonb_array_elements(v_config) AS elem
589+
WHERE elem->>'key' = v_key
590+
LOOP
591+
RETURN v_entry;
592+
END LOOP;
593+
RETURN NULL;
594+
END$$;

packages/plpgsql-deparser/__tests__/__snapshots__/deparser-fixes.test.ts.snap

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

3+
exports[`plpgsql-deparser bug fixes CoalesceExpr and RangeFunction patterns should handle COALESCE in FROM clause with set-returning function 1`] = `
4+
"BEGIN
5+
RETURN QUERY SELECT elem
6+
FROM jsonb_array_elements(COALESCE(v_config, '[]'::jsonb)) AS elem;
7+
RETURN;
8+
END"
9+
`;
10+
11+
exports[`plpgsql-deparser bug fixes CoalesceExpr and RangeFunction patterns should handle COALESCE inside function call arguments 1`] = `
12+
"BEGIN
13+
RETURN QUERY SELECT jsonb_array_elements(COALESCE(v_config, '[]'::jsonb));
14+
RETURN;
15+
END"
16+
`;
17+
18+
exports[`plpgsql-deparser bug fixes CoalesceExpr and RangeFunction patterns should handle COALESCE with function call in assignment 1`] = `
19+
"BEGIN
20+
NEW.updated_at := COALESCE(NEW.updated_at, now());
21+
NEW.name := COALESCE(NEW.name, 'default_' || NEW.id::text);
22+
RETURN NEW;
23+
END"
24+
`;
25+
26+
exports[`plpgsql-deparser bug fixes CoalesceExpr and RangeFunction patterns should handle FOR loop with SRF and WHERE filter 1`] = `
27+
"DECLARE
28+
v_entry jsonb;
29+
BEGIN
30+
FOR v_entry IN SELECT elem FROM jsonb_array_elements(v_config) AS elem
31+
WHERE elem->>'key' = v_key LOOP
32+
RETURN v_entry;
33+
END LOOP;
34+
RETURN NULL;
35+
END"
36+
`;
37+
38+
exports[`plpgsql-deparser bug fixes CoalesceExpr and RangeFunction patterns should handle SELECT INTO from set-returning function in FROM clause 1`] = `
39+
"DECLARE
40+
v_first jsonb;
41+
BEGIN
42+
SELECT elem INTO v_first FROM jsonb_array_elements(v_data) AS elem
43+
LIMIT 1;
44+
RETURN v_first;
45+
END"
46+
`;
47+
48+
exports[`plpgsql-deparser bug fixes CoalesceExpr and RangeFunction patterns should handle multiple SRFs in FROM clause 1`] = `
49+
"BEGIN
50+
RETURN QUERY SELECT unnest_k, unnest_v
51+
FROM unnest(v_keys) AS unnest_k, unnest(v_values) AS unnest_v;
52+
RETURN;
53+
END"
54+
`;
55+
56+
exports[`plpgsql-deparser bug fixes CoalesceExpr and RangeFunction patterns should handle nested COALESCE expressions 1`] = `
57+
"BEGIN
58+
RETURN COALESCE(a, COALESCE(b, COALESCE(c, 'fallback')));
59+
END"
60+
`;
61+
62+
exports[`plpgsql-deparser bug fixes CoalesceExpr and RangeFunction patterns should handle set-returning function in FROM clause (RangeFunction) 1`] = `
63+
"BEGIN
64+
RETURN QUERY SELECT elem->>'key', elem->>'value'
65+
FROM jsonb_array_elements(v_data) AS elem;
66+
RETURN;
67+
END"
68+
`;
69+
370
exports[`plpgsql-deparser bug fixes INTO clause depth-aware scanner should handle INTO STRICT 1`] = `
471
"DECLARE
572
v_id integer;

packages/plpgsql-deparser/__tests__/deparser-fixes.test.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,4 +872,153 @@ END$$`;
872872
expect(deparsed).toMatchSnapshot();
873873
});
874874
});
875+
876+
describe('CoalesceExpr and RangeFunction patterns', () => {
877+
it('should handle COALESCE inside function call arguments', async () => {
878+
const sql = `CREATE FUNCTION test_coalesce_in_func_args(v_config jsonb) RETURNS SETOF jsonb
879+
LANGUAGE plpgsql AS $$
880+
BEGIN
881+
RETURN QUERY SELECT jsonb_array_elements(COALESCE(v_config, '[]'::jsonb));
882+
END$$`;
883+
884+
await testUtils.expectAstMatch('COALESCE in FuncCall args', sql);
885+
886+
const parsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
887+
const deparsed = deparseSync(parsed);
888+
expect(deparsed).toMatchSnapshot();
889+
expect(deparsed).toContain('COALESCE');
890+
expect(deparsed).toContain('jsonb_array_elements');
891+
});
892+
893+
it('should handle set-returning function in FROM clause (RangeFunction)', async () => {
894+
const sql = `CREATE FUNCTION test_func_in_from(v_data jsonb) RETURNS TABLE(key text, value text)
895+
LANGUAGE plpgsql AS $$
896+
BEGIN
897+
RETURN QUERY SELECT elem->>'key', elem->>'value'
898+
FROM jsonb_array_elements(v_data) AS elem;
899+
END$$`;
900+
901+
await testUtils.expectAstMatch('FuncCall in FROM clause', sql);
902+
903+
const parsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
904+
const deparsed = deparseSync(parsed);
905+
expect(deparsed).toMatchSnapshot();
906+
expect(deparsed).toContain('jsonb_array_elements');
907+
expect(deparsed).toContain('FROM');
908+
});
909+
910+
it('should handle COALESCE in FROM clause with set-returning function', async () => {
911+
const sql = `CREATE FUNCTION test_coalesce_in_from_srf(v_config jsonb) RETURNS TABLE(entry jsonb)
912+
LANGUAGE plpgsql AS $$
913+
BEGIN
914+
RETURN QUERY SELECT elem
915+
FROM jsonb_array_elements(COALESCE(v_config, '[]'::jsonb)) AS elem;
916+
END$$`;
917+
918+
await testUtils.expectAstMatch('COALESCE in FROM SRF', sql);
919+
920+
const parsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
921+
const deparsed = deparseSync(parsed);
922+
expect(deparsed).toMatchSnapshot();
923+
expect(deparsed).toContain('COALESCE');
924+
expect(deparsed).toContain('FROM');
925+
expect(deparsed).toContain('jsonb_array_elements');
926+
});
927+
928+
it('should handle SELECT INTO from set-returning function in FROM clause', async () => {
929+
const sql = `CREATE FUNCTION test_select_into_from_srf(v_data jsonb) RETURNS jsonb
930+
LANGUAGE plpgsql AS $$
931+
DECLARE
932+
v_first jsonb;
933+
BEGIN
934+
SELECT elem INTO v_first
935+
FROM jsonb_array_elements(v_data) AS elem
936+
LIMIT 1;
937+
RETURN v_first;
938+
END$$`;
939+
940+
await testUtils.expectAstMatch('SELECT INTO from SRF in FROM', sql);
941+
942+
const parsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
943+
const deparsed = deparseSync(parsed);
944+
expect(deparsed).toMatchSnapshot();
945+
expect(deparsed).toContain('INTO');
946+
expect(deparsed).toContain('jsonb_array_elements');
947+
expect(deparsed).toContain('FROM');
948+
});
949+
950+
it('should handle FOR loop with SRF and WHERE filter', async () => {
951+
const sql = `CREATE FUNCTION test_for_srf_filter(v_config jsonb, v_key text) RETURNS jsonb
952+
LANGUAGE plpgsql AS $$
953+
DECLARE
954+
v_entry jsonb;
955+
BEGIN
956+
FOR v_entry IN
957+
SELECT elem FROM jsonb_array_elements(v_config) AS elem
958+
WHERE elem->>'key' = v_key
959+
LOOP
960+
RETURN v_entry;
961+
END LOOP;
962+
RETURN NULL;
963+
END$$`;
964+
965+
await testUtils.expectAstMatch('FOR loop SRF with WHERE', sql);
966+
967+
const parsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
968+
const deparsed = deparseSync(parsed);
969+
expect(deparsed).toMatchSnapshot();
970+
expect(deparsed).toContain('jsonb_array_elements');
971+
expect(deparsed).toContain('WHERE');
972+
});
973+
974+
it('should handle nested COALESCE expressions', async () => {
975+
const sql = `CREATE FUNCTION test_nested_coalesce(a text, b text, c text) RETURNS text
976+
LANGUAGE plpgsql AS $$
977+
BEGIN
978+
RETURN COALESCE(a, COALESCE(b, COALESCE(c, 'fallback')));
979+
END$$`;
980+
981+
await testUtils.expectAstMatch('nested COALESCE', sql);
982+
983+
const parsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
984+
const deparsed = deparseSync(parsed);
985+
expect(deparsed).toMatchSnapshot();
986+
expect(deparsed).toContain('COALESCE');
987+
});
988+
989+
it('should handle multiple SRFs in FROM clause', async () => {
990+
const sql = `CREATE FUNCTION test_multiple_srf(v_keys text[], v_values text[]) RETURNS TABLE(k text, v text)
991+
LANGUAGE plpgsql AS $$
992+
BEGIN
993+
RETURN QUERY SELECT unnest_k, unnest_v
994+
FROM unnest(v_keys) AS unnest_k, unnest(v_values) AS unnest_v;
995+
END$$`;
996+
997+
await testUtils.expectAstMatch('multiple SRFs in FROM', sql);
998+
999+
const parsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
1000+
const deparsed = deparseSync(parsed);
1001+
expect(deparsed).toMatchSnapshot();
1002+
expect(deparsed).toContain('unnest');
1003+
expect(deparsed).toContain('FROM');
1004+
});
1005+
1006+
it('should handle COALESCE with function call in assignment', async () => {
1007+
const sql = `CREATE FUNCTION test_coalesce_assign() RETURNS trigger
1008+
LANGUAGE plpgsql AS $$
1009+
BEGIN
1010+
NEW.updated_at := COALESCE(NEW.updated_at, now());
1011+
NEW.name := COALESCE(NEW.name, 'default_' || NEW.id::text);
1012+
RETURN NEW;
1013+
END$$`;
1014+
1015+
await testUtils.expectAstMatch('COALESCE assign with func', sql);
1016+
1017+
const parsed = parsePlPgSQLSync(sql) as unknown as PLpgSQLParseResult;
1018+
const deparsed = deparseSync(parsed);
1019+
expect(deparsed).toMatchSnapshot();
1020+
expect(deparsed).toContain('COALESCE');
1021+
expect(deparsed).toContain('now()');
1022+
});
1023+
});
8751024
});

0 commit comments

Comments
 (0)