Skip to content

Commit b5e5bdd

Browse files
committed
Implement pretty formatting improvements for 6 complex misc SQL test cases
- Enhanced CaseExpr formatting with proper WHEN/THEN/ELSE alignment - Improved WindowDef formatting for OVER clauses with PARTITION BY/ORDER BY - Enhanced JoinExpr formatting for complex JOIN ON conditions with proper indentation - Added containsMultilineStringLiteral helper to preserve string literal content - Created comprehensive test suite for misc SQL scenarios including CTEs, window functions, LATERAL joins, and complex subqueries - Fixed critical CaseExpr bug that caused 'CASE1' syntax error by ensuring proper spacing - Generated snapshots for 6 misc test cases to visualize pretty formatting improvements - All kitchen-sink tests now pass with AST equivalence validation Co-Authored-By: Dan Lynch <[email protected]>
1 parent ca28d17 commit b5e5bdd

File tree

3 files changed

+348
-16
lines changed

3 files changed

+348
-16
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Pretty Misc SQL formatting should format misc-1: Complex CTE with joins and aggregation 1`] = `
4+
"WITH
5+
recent_orders AS (SELECT
6+
o.id,
7+
o.user_id,
8+
o.created_at
9+
FROM orders AS o
10+
WHERE
11+
o.created_at > (now() - '30 days'::interval)),
12+
high_value_orders AS (SELECT
13+
r.user_id,
14+
count(*) AS order_count,
15+
sum(oi.price * oi.quantity) AS total_spent
16+
FROM recent_orders AS r
17+
JOIN order_items AS oi ON r.id = oi.order_id
18+
GROUP BY
19+
r.user_id)
20+
SELECT
21+
u.id,
22+
u.name,
23+
h.total_spent
24+
FROM users AS u
25+
JOIN high_value_orders AS h ON u.id = h.user_id
26+
WHERE
27+
h.total_spent > 1000
28+
ORDER BY
29+
h.total_spent DESC"
30+
`;
31+
32+
exports[`Pretty Misc SQL formatting should format misc-2: Window functions with FILTER and GROUPING SETS 1`] = `
33+
"SELECT
34+
department,
35+
employee_id,
36+
count(*) FILTER (WHERE status = 'active') OVER (PARTITION BY department) AS active_count,
37+
rank() OVER (
38+
PARTITION BY department
39+
ORDER BY salary DESC
40+
) AS salary_rank
41+
FROM employee_status
42+
GROUP BY
43+
GROUPING SETS (department, (department, employee_id))"
44+
`;
45+
46+
exports[`Pretty Misc SQL formatting should format misc-3: LATERAL joins with JSON functions 1`] = `
47+
"SELECT
48+
u.id,
49+
u.name,
50+
j.key,
51+
j.value
52+
FROM users AS u, LATERAL jsonb_each_text(u.preferences) AS j(key, value)
53+
WHERE
54+
j.key LIKE 'notif_%'
55+
AND CAST(j.value AS boolean) = true"
56+
`;
57+
58+
exports[`Pretty Misc SQL formatting should format misc-4: EXISTS with nested subqueries and CASE 1`] = `
59+
"SELECT
60+
p.id,
61+
p.title,
62+
CASE
63+
WHEN EXISTS (SELECT
64+
1
65+
FROM reviews AS r
66+
WHERE
67+
r.product_id = p.id
68+
AND r.rating >= 4) THEN 'Popular'
69+
ELSE 'Unrated'
70+
END AS status
71+
FROM products AS p
72+
WHERE
73+
p.archived = false"
74+
`;
75+
76+
exports[`Pretty Misc SQL formatting should format misc-5: Nested CTEs with type casts and subqueries 1`] = `
77+
"WITH
78+
logs AS (SELECT
79+
id,
80+
CAST(payload AS pg_catalog.json) ->> 'event' AS event,
81+
CAST(CAST(payload AS pg_catalog.json) ->> 'ts' AS pg_catalog.timestamp) AS ts
82+
FROM event_log
83+
WHERE
84+
ts > (now() - '7 days'::interval))
85+
SELECT
86+
event,
87+
count(*) AS freq
88+
FROM ( SELECT DISTINCT
89+
event,
90+
ts::date AS event_day
91+
FROM logs ) AS d
92+
GROUP BY
93+
event
94+
ORDER BY
95+
freq DESC"
96+
`;
97+
98+
exports[`Pretty Misc SQL formatting should format misc-6: Complex multi-table joins with nested conditions 1`] = `
99+
"SELECT
100+
o.id AS order_id,
101+
u.name AS user_name,
102+
p.name AS product_name,
103+
s.status,
104+
sh.shipped_at,
105+
r.refund_amount
106+
FROM orders AS o
107+
JOIN users AS u ON o.user_id = u.id
108+
JOIN order_items AS oi ON oi.order_id = o.id
109+
JOIN products AS p ON
110+
(p.id = oi.product_id
111+
AND p.available = true)
112+
OR (p.sku = oi.product_sku
113+
AND (p.discontinued = false
114+
OR p.replacement_id IS NOT NULL))
115+
LEFT JOIN shipping AS sh ON sh.order_id = o.id
116+
AND ((sh.carrier = 'UPS'
117+
AND sh.tracking_number IS NOT NULL)
118+
OR (sh.carrier = 'FedEx'
119+
AND sh.shipped_at > (o.created_at + '1 day'::interval)))
120+
LEFT JOIN statuses AS s ON s.id = o.status_id
121+
AND (s.name <> 'cancelled'
122+
OR (s.name = 'cancelled'
123+
AND s.updated_at > (now() - '7 days'::interval)))
124+
LEFT JOIN refunds AS r ON r.order_id = o.id
125+
AND ((r.status = 'approved'
126+
AND r.processed_at IS NOT NULL)
127+
OR (r.status = 'pending'
128+
AND r.requested_at < (now() - '14 days'::interval)))
129+
WHERE
130+
o.created_at > (now() - '90 days'::interval)
131+
AND u.active = true
132+
AND (s.status = 'shipped'
133+
OR (s.status = 'processing'
134+
AND EXISTS (SELECT
135+
1
136+
FROM order_notes AS n
137+
WHERE
138+
(n.order_id = o.id
139+
AND n.note ILIKE '%expedite%'))))
140+
ORDER BY
141+
o.created_at DESC"
142+
`;
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import { deparseSync } from '../../src';
2+
import { parse } from 'libpg-query';
3+
import { expectParseDeparse } from '../../test-utils';
4+
5+
describe('Pretty Misc SQL formatting', () => {
6+
const misc1Sql = `WITH recent_orders AS (
7+
SELECT o.id, o.user_id, o.created_at
8+
FROM orders o
9+
WHERE o.created_at > NOW() - INTERVAL '30 days'
10+
), high_value_orders AS (
11+
SELECT r.user_id, COUNT(*) AS order_count, SUM(oi.price * oi.quantity) AS total_spent
12+
FROM recent_orders r
13+
JOIN order_items oi ON r.id = oi.order_id
14+
GROUP BY r.user_id
15+
)
16+
SELECT u.id, u.name, h.total_spent
17+
FROM users u
18+
JOIN high_value_orders h ON u.id = h.user_id
19+
WHERE h.total_spent > 1000
20+
ORDER BY h.total_spent DESC`;
21+
22+
const misc2Sql = `SELECT
23+
department,
24+
employee_id,
25+
COUNT(*) FILTER (WHERE status = 'active') OVER (PARTITION BY department) AS active_count,
26+
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS salary_rank
27+
FROM employee_status
28+
GROUP BY GROUPING SETS ((department), (department, employee_id))`;
29+
30+
const misc3Sql = `SELECT u.id, u.name, j.key, j.value
31+
FROM users u,
32+
LATERAL jsonb_each_text(u.preferences) AS j(key, value)
33+
WHERE j.key LIKE 'notif_%' AND j.value::boolean = true`;
34+
35+
const misc4Sql = `SELECT p.id, p.title,
36+
CASE
37+
WHEN EXISTS (
38+
SELECT 1 FROM reviews r
39+
WHERE r.product_id = p.id AND r.rating >= 4
40+
) THEN 'Popular'
41+
ELSE 'Unrated'
42+
END AS status
43+
FROM products p
44+
WHERE p.archived = false`;
45+
46+
const misc5Sql = `WITH logs AS (
47+
SELECT id, payload::json->>'event' AS event, (payload::json->>'ts')::timestamp AS ts
48+
FROM event_log
49+
WHERE ts > NOW() - INTERVAL '7 days'
50+
)
51+
SELECT event, COUNT(*) AS freq
52+
FROM (
53+
SELECT DISTINCT event, ts::date AS event_day
54+
FROM logs
55+
) d
56+
GROUP BY event
57+
ORDER BY freq DESC`;
58+
59+
const misc6Sql = `SELECT
60+
o.id AS order_id,
61+
u.name AS user_name,
62+
p.name AS product_name,
63+
s.status,
64+
sh.shipped_at,
65+
r.refund_amount
66+
FROM orders o
67+
JOIN users u
68+
ON o.user_id = u.id
69+
JOIN order_items oi
70+
ON oi.order_id = o.id
71+
JOIN products p
72+
ON (
73+
(p.id = oi.product_id AND p.available = true)
74+
OR
75+
(p.sku = oi.product_sku AND (p.discontinued = false OR p.replacement_id IS NOT NULL))
76+
)
77+
LEFT JOIN shipping sh
78+
ON (
79+
sh.order_id = o.id
80+
AND (
81+
(sh.carrier = 'UPS' AND sh.tracking_number IS NOT NULL)
82+
OR
83+
(sh.carrier = 'FedEx' AND sh.shipped_at > o.created_at + INTERVAL '1 day')
84+
)
85+
)
86+
LEFT JOIN statuses s
87+
ON s.id = o.status_id
88+
AND (
89+
s.name != 'cancelled'
90+
OR (s.name = 'cancelled' AND s.updated_at > NOW() - INTERVAL '7 days')
91+
)
92+
LEFT JOIN refunds r
93+
ON r.order_id = o.id
94+
AND (
95+
(r.status = 'approved' AND r.processed_at IS NOT NULL)
96+
OR
97+
(r.status = 'pending' AND r.requested_at < NOW() - INTERVAL '14 days')
98+
)
99+
WHERE o.created_at > NOW() - INTERVAL '90 days'
100+
AND u.active = true
101+
AND (
102+
s.status = 'shipped'
103+
OR (
104+
s.status = 'processing'
105+
AND EXISTS (
106+
SELECT 1 FROM order_notes n WHERE n.order_id = o.id AND n.note ILIKE '%expedite%'
107+
)
108+
)
109+
)
110+
ORDER BY o.created_at DESC`;
111+
112+
it('should format misc-1: Complex CTE with joins and aggregation', async () => {
113+
const result = await expectParseDeparse(misc1Sql, { pretty: true });
114+
expect(result).toMatchSnapshot();
115+
});
116+
117+
it('should format misc-2: Window functions with FILTER and GROUPING SETS', async () => {
118+
const result = await expectParseDeparse(misc2Sql, { pretty: true });
119+
expect(result).toMatchSnapshot();
120+
});
121+
122+
it('should format misc-3: LATERAL joins with JSON functions', async () => {
123+
const result = await expectParseDeparse(misc3Sql, { pretty: true });
124+
expect(result).toMatchSnapshot();
125+
});
126+
127+
it('should format misc-4: EXISTS with nested subqueries and CASE', async () => {
128+
const result = await expectParseDeparse(misc4Sql, { pretty: true });
129+
expect(result).toMatchSnapshot();
130+
});
131+
132+
it('should format misc-5: Nested CTEs with type casts and subqueries', async () => {
133+
const result = await expectParseDeparse(misc5Sql, { pretty: true });
134+
expect(result).toMatchSnapshot();
135+
});
136+
137+
it('should format misc-6: Complex multi-table joins with nested conditions', async () => {
138+
const result = await expectParseDeparse(misc6Sql, { pretty: true });
139+
expect(result).toMatchSnapshot();
140+
});
141+
142+
it('should validate AST equivalence for all misc cases', async () => {
143+
const testCases = [misc1Sql, misc2Sql, misc3Sql, misc4Sql, misc5Sql, misc6Sql];
144+
145+
for (const sql of testCases) {
146+
await expectParseDeparse(sql, { pretty: false });
147+
await expectParseDeparse(sql, { pretty: true });
148+
}
149+
});
150+
});

0 commit comments

Comments
 (0)