-
Notifications
You must be signed in to change notification settings - Fork 446
Expand file tree
/
Copy pathbehavesLikeSqlFormatter.ts
More file actions
282 lines (262 loc) · 7.23 KB
/
behavesLikeSqlFormatter.ts
File metadata and controls
282 lines (262 loc) · 7.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
import dedent from 'dedent-js';
import { FormatFn } from '../src/sqlFormatter.js';
import supportsCase from './features/case.js';
import supportsWith from './features/with.js';
import supportsTabWidth from './options/tabWidth.js';
import supportsUseTabs from './options/useTabs.js';
import supportsExpressionWidth from './options/expressionWidth.js';
import supportsKeywordCase from './options/keywordCase.js';
import supportsIdentifierCase from './options/identifierCase.js';
import supportsIndentStyle from './options/indentStyle.js';
import supportsLinesBetweenQueries from './options/linesBetweenQueries.js';
import supportsNewlineBeforeSemicolon from './options/newlineBeforeSemicolon.js';
import supportsLogicalOperatorNewline from './options/logicalOperatorNewline.js';
import supportsCommaNewline from './options/commaNewline.js';
import supportsParamTypes from './options/paramTypes.js';
import supportsWindowFunctions from './features/windowFunctions.js';
import supportsFunctionCase from './options/functionCase.js';
import supportsDisableComment from './features/disableComment.js';
/**
* Core tests for all SQL formatters
*/
export default function behavesLikeSqlFormatter(format: FormatFn) {
supportsDisableComment(format);
supportsCase(format);
supportsWith(format);
supportsTabWidth(format);
supportsUseTabs(format);
supportsKeywordCase(format);
supportsIdentifierCase(format);
supportsFunctionCase(format);
supportsIndentStyle(format);
supportsLinesBetweenQueries(format);
supportsExpressionWidth(format);
supportsNewlineBeforeSemicolon(format);
supportsLogicalOperatorNewline(format);
supportsCommaNewline(format);
supportsParamTypes(format);
supportsWindowFunctions(format);
it('formats SELECT with asterisks', () => {
const result = format('SELECT tbl.*, count(*), col1 * col2 FROM tbl;');
expect(result).toBe(dedent`
SELECT
tbl.*,
count(*),
col1 * col2
FROM
tbl;
`);
});
it('formats complex SELECT', () => {
const result = format(
"SELECT DISTINCT name, ROUND(age/7) field1, 18 + 20 AS field2, 'some string' FROM foo;"
);
expect(result).toBe(dedent`
SELECT DISTINCT
name,
ROUND(age / 7) field1,
18 + 20 AS field2,
'some string'
FROM
foo;
`);
});
it('formats SELECT with complex WHERE', () => {
const result = format(`
SELECT * FROM foo WHERE Column1 = 'testing'
AND ( (Column2 = Column3 OR Column4 >= ABS(5)) );
`);
expect(result).toBe(dedent`
SELECT
*
FROM
foo
WHERE
Column1 = 'testing'
AND (
(
Column2 = Column3
OR Column4 >= ABS(5)
)
);
`);
});
it('formats SELECT with top level reserved words', () => {
const result = format(`
SELECT * FROM foo WHERE name = 'John' GROUP BY some_column
HAVING column > 10 ORDER BY other_column;
`);
expect(result).toBe(dedent`
SELECT
*
FROM
foo
WHERE
name = 'John'
GROUP BY
some_column
HAVING
column > 10
ORDER BY
other_column;
`);
});
it('allows keywords as column names in tbl.col syntax', () => {
const result = format(
'SELECT mytable.update, mytable.select FROM mytable WHERE mytable.from > 10;'
);
expect(result).toBe(dedent`
SELECT
mytable.update,
mytable.select
FROM
mytable
WHERE
mytable.from > 10;
`);
});
it('formats ORDER BY', () => {
const result = format(`
SELECT * FROM foo ORDER BY col1 ASC, col2 DESC;
`);
expect(result).toBe(dedent`
SELECT
*
FROM
foo
ORDER BY
col1 ASC,
col2 DESC;
`);
});
it('formats SELECT query with SELECT query inside it', () => {
const result = format(
'SELECT *, SUM(*) AS total FROM (SELECT * FROM Posts WHERE age > 10) WHERE a > b'
);
expect(result).toBe(dedent`
SELECT
*,
SUM(*) AS total
FROM
(
SELECT
*
FROM
Posts
WHERE
age > 10
)
WHERE
a > b
`);
});
it('formats open paren after comma', () => {
const result = format('INSERT INTO TestIds (id) VALUES (4),(5), (6),(7),(9),(10),(11);');
expect(result).toBe(dedent`
INSERT INTO
TestIds (id)
VALUES
(4),
(5),
(6),
(7),
(9),
(10),
(11);
`);
});
it('keeps short parenthesized list with nested parenthesis on single line', () => {
const result = format('SELECT (a + b * (c - SIN(1)));');
expect(result).toBe(dedent`
SELECT
(a + b * (c - SIN(1)));
`);
});
it('breaks long parenthesized lists to multiple lines', () => {
const result = format(`
INSERT INTO some_table (id_product, id_shop, id_currency, id_country, id_registration) (
SELECT COALESCE(dq.id_discounter_shopping = 2, dq.value, dq.value / 100),
COALESCE (dq.id_discounter_shopping = 2, 'amount', 'percentage') FROM foo);
`);
expect(result).toBe(dedent`
INSERT INTO
some_table (
id_product,
id_shop,
id_currency,
id_country,
id_registration
) (
SELECT
COALESCE(
dq.id_discounter_shopping = 2,
dq.value,
dq.value / 100
),
COALESCE(
dq.id_discounter_shopping = 2,
'amount',
'percentage'
)
FROM
foo
);
`);
});
it('formats top-level and newline multi-word reserved words with inconsistent spacing', () => {
const result = format('SELECT * FROM foo LEFT \t \n JOIN mycol ORDER \n BY blah');
expect(result).toBe(dedent`
SELECT
*
FROM
foo
LEFT JOIN mycol
ORDER BY
blah
`);
});
it('formats long double parenthized queries to multiple lines', () => {
const result = format("((foo = '0123456789-0123456789-0123456789-0123456789'))");
expect(result).toBe(dedent`
(
(
foo = '0123456789-0123456789-0123456789-0123456789'
)
)
`);
});
it('formats short double parenthized queries to one line', () => {
const result = format("((foo = 'bar'))");
expect(result).toBe("((foo = 'bar'))");
});
it('supports unicode letters in identifiers', () => {
const result = format('SELECT 结合使用, тест FROM töörõõm;');
expect(result).toBe(dedent`
SELECT
结合使用,
тест
FROM
töörõõm;
`);
});
// Using Myanmar and Tibetan digits 1, 2, 3
it('supports unicode numbers in identifiers', () => {
const result = format('SELECT my၁၂၃ FROM tbl༡༢༣;');
expect(result).toBe(dedent`
SELECT
my၁၂၃
FROM
tbl༡༢༣;
`);
});
it('supports unicode diacritical marks in identifiers', () => {
const COMBINING_TILDE = String.fromCodePoint(0x0303);
const result = format('SELECT o' + COMBINING_TILDE + ' FROM tbl;');
expect(result).toBe(dedent`
SELECT
õ
FROM
tbl;
`);
});
}