Skip to content

Commit 80f6e1e

Browse files
committed
Add preliminary Clickhouse formatter
1 parent f676e37 commit 80f6e1e

File tree

7 files changed

+2670
-1
lines changed

7 files changed

+2670
-1
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,6 @@ We provide **JSON Schema** for `.sql-formatter.json` configuration file, enablin
209209
- [Using the schema in VSCode](https://code.visualstudio.com/docs/languages/json#_mapping-in-the-user-settings)
210210
- [Using the schema in Zed](https://zed.dev/docs/languages/json#schema-specification-via-settings)
211211

212-
213212
### Usage as ESLint plugin
214213

215214
- Inside `eslint-plugin-sql` by using the rule [eslint-plugin-sql#format](https://github.com/gajus/eslint-plugin-sql#format).

src/allDialects.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { bigquery } from './languages/bigquery/bigquery.formatter.js';
2+
export { clickhouse } from './languages/clickhouse/clickhouse.formatter.js';
23
export { db2 } from './languages/db2/db2.formatter.js';
34
export { db2i } from './languages/db2i/db2i.formatter.js';
45
export { duckdb } from './languages/duckdb/duckdb.formatter.js';

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export { ConfigError } from './validateConfig.js';
44

55
// When adding a new dialect, be sure to add it to the list of exports below.
66
export { bigquery } from './languages/bigquery/bigquery.formatter.js';
7+
export { clickhouse } from './languages/clickhouse/clickhouse.formatter.js';
78
export { db2 } from './languages/db2/db2.formatter.js';
89
export { db2i } from './languages/db2i/db2i.formatter.js';
910
export { duckdb } from './languages/duckdb/duckdb.formatter.js';
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import { DialectOptions } from '../../dialect.js';
2+
import { expandPhrases } from '../../expandPhrases.js';
3+
import { functions } from './clickhouse.functions.js';
4+
import { dataTypes, keywords, keywordPhrases } from './clickhouse.keywords.js';
5+
6+
const reservedSelect = expandPhrases(['SELECT [DISTINCT]']);
7+
8+
const reservedClauses = expandPhrases([
9+
// https://clickhouse.com/docs/sql-reference/statements/explain
10+
'EXPLAIN [AST | SYNTAX | QUERY TREE | PLAN | PIPELINE | ESTIMATE | TABLE OVERRIDE]',
11+
]);
12+
13+
const standardOnelineClauses = expandPhrases([
14+
// https://clickhouse.com/docs/sql-reference/statements/create
15+
'CREATE [OR REPLACE] [TEMPORARY] TABLE [IF NOT EXISTS]',
16+
// https://clickhouse.com/docs/sql-reference/statements/update
17+
'UPDATE',
18+
// https://clickhouse.com/docs/sql-reference/statements/system
19+
'SYSTEM RELOAD {DICTIONARIES | DICTIONARY | FUNCTIONS | FUNCTION | ASYNCHRONOUS METRICS} [ON CLUSTER]',
20+
'SYSTEM DROP {DNS CACHE | MARK CACHE | ICEBERG METADATA CACHE | TEXT INDEX DICTIONARY CACHE | TEXT INDEX HEADER CACHE | TEXT INDEX POSTINGS CACHE | REPLICA | DATABASE REPLICA | UNCOMPRESSED CACHE | COMPILED EXPRESSION CACHE | QUERY CONDITION CACHE | QUERY CACHE | FORMAT SCHEMA CACHE | DROP FILESYSTEM CACHE}',
21+
'SYSTEM FLUSH LOGS',
22+
'SYSTEM RELOAD {CONFIG | USERS}',
23+
'SYSTEM SHUTDOWN',
24+
'SYSTEM KILL',
25+
'SYSTEM FLUSH DISTRIBUTED',
26+
'SYSTEM START DISTRIBUTED SENDS',
27+
'SYSTEM {STOP | START} {LISTEN | MERGES | TTL MERGES | MOVES | FETCHES | REPLICATED SENDS | REPLICATION QUEUES | PULLING REPLICATION LOG}',
28+
'SYSTEM {SYNC | RESTART | RESTORE} REPLICA',
29+
'SYSTEM {SYNC | RESTORE} DATABASE REPLICA',
30+
'SYSTEM RESTART REPLICAS',
31+
'SYSTEM UNFREEZE',
32+
'SYSTEM WAIT LOADING PARTS',
33+
'SYSTEM {LOAD | UNLOAD} PRIMARY KEY',
34+
'SYSTEM {STOP | START} [REPLICATED] VIEW',
35+
'SYSTEM {STOP | START} VIEWS',
36+
'SYSTEM {REFRESH | CANCEL | WAIT} VIEW',
37+
// https://clickhouse.com/docs/sql-reference/statements/show
38+
'SHOW [CREATE] {TABLE | TEMPORARY TABLE | DICTIONARY | VIEW | DATABASE}',
39+
'SHOW DATABASES [[NOT] {LIKE | ILIKE}]',
40+
'SHOW [FULL] [TEMPORARY] TABLES [FROM | IN]',
41+
'SHOW [EXTENDED] [FULL] COLUMNS {FROM | IN}',
42+
// https://clickhouse.com/docs/sql-reference/statements/attach
43+
'ATTACH {TABLE | DICTIONARY | DATABASE} [IF NOT EXISTS]',
44+
// https://clickhouse.com/docs/sql-reference/statements/detach
45+
'DETACH {TABLE | DICTIONARY | DATABASE} [IF EXISTS]',
46+
// https://clickhouse.com/docs/sql-reference/statements/drop
47+
'DROP {DICTIONARY | DATABASE | USER | ROLE | QUOTA | PROFILE | SETTINGS PROFILE | VIEW | FUNCTION | NAMED COLLECTION | ROW POLICY | POLICY} [IF EXISTS]',
48+
'DROP [TEMPORARY] TABLE [IF EXISTS] [IF EMPTY]',
49+
// https://clickhouse.com/docs/sql-reference/statements/exists
50+
'EXISTS [TEMPORARY] {TABLE | DICTIONARY | DATABASE}',
51+
// https://clickhouse.com/docs/sql-reference/statements/kill
52+
'KILL QUERY [ON CLUSTER]',
53+
// https://clickhouse.com/docs/sql-reference/statements/optimize
54+
'OPTIMIZE TABLE',
55+
// https://clickhouse.com/docs/sql-reference/statements/rename
56+
'RENAME [TABLE | DICTIONARY | DATABASE]',
57+
// https://clickhouse.com/docs/sql-reference/statements/exchange
58+
'EXCHANGE {TABLES | DICTIONARIES}',
59+
// https://clickhouse.com/docs/sql-reference/statements/set
60+
'SET',
61+
// https://clickhouse.com/docs/sql-reference/statements/set-role
62+
'SET ROLE [DEFAULT | NONE | ALL | ALL EXCEPT]',
63+
'SET DEFAULT ROLE [NONE]',
64+
// https://clickhouse.com/docs/sql-reference/statements/truncate
65+
'TRUNCATE TABLE [IF EXISTS]',
66+
// https://clickhouse.com/docs/sql-reference/statements/execute_as
67+
'EXECUTE AS',
68+
// https://clickhouse.com/docs/sql-reference/statements/use
69+
'USE',
70+
// https://clickhouse.com/docs/sql-reference/statements/move
71+
'MOVE {USER | ROLE | QUOTA | SETTINGS PROFILE | ROW POLICY}',
72+
// https://clickhouse.com/docs/sql-reference/statements/check-grant
73+
'CHECK GRANT',
74+
// https://clickhouse.com/docs/sql-reference/statements/undrop
75+
'UNDROP TABLE',
76+
]);
77+
const tabularOnelineClauses = expandPhrases([
78+
// https://clickhouse.com/docs/sql-reference/statements/create
79+
'CREATE {DATABASE | NAMED COLLECTION} [IF NOT EXISTS]',
80+
'CREATE [OR REPLACE] {VIEW | DICTIONARY} [IF NOT EXISTS]',
81+
'CREATE MATERIALIZED VIEW [IF NOT EXISTS]',
82+
'CREATE FUNCTION',
83+
'CREATE {USER | ROLE | QUOTA | SETTINGS PROFILE} [IF NOT EXISTS | OR REPLACE]',
84+
'CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE]',
85+
// https://clickhouse.com/docs/sql-reference/statements/create/table#replace-table
86+
'REPLACE [TEMPORARY] TABLE [IF NOT EXISTS]',
87+
// https://clickhouse.com/docs/sql-reference/statements/alter
88+
'ALTER [TEMPORARY] TABLE',
89+
'ALTER {USER | ROLE | QUOTA | SETTINGS PROFILE} [IF EXISTS]',
90+
'ALTER [ROW] POLICY [IF EXISTS]',
91+
'ALTER NAMED COLLECTION [IF EXISTS]',
92+
// https://clickhouse.com/docs/sql-reference/statements/delete
93+
'DELETE FROM',
94+
// https://clickhouse.com/docs/sql-reference/statements/grant
95+
'GRANT [ON CLUSTER]',
96+
// https://clickhouse.com/docs/sql-reference/statements/revoke
97+
'REVOKE [ON CLUSTER]',
98+
// https://clickhouse.com/docs/sql-reference/statements/check-table
99+
'CHECK TABLE',
100+
// https://clickhouse.com/docs/sql-reference/statements/describe-table
101+
'{DESC | DESCRIBE} TABLE',
102+
]);
103+
104+
const reservedSetOperations = expandPhrases([
105+
// https://clickhouse.com/docs/sql-reference/statements/select/set-operations
106+
'UNION [ALL | DISTINCT]',
107+
// https://clickhouse.com/docs/sql-reference/statements/parallel_with
108+
'PARALLEL WITH',
109+
]);
110+
111+
const reservedJoins = expandPhrases([
112+
// https://clickhouse.com/docs/sql-reference/statements/select/join
113+
'[GLOBAL] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI|ANY|ALL|ASOF] JOIN',
114+
]);
115+
116+
// https://clickhouse.com/docs/sql-reference/syntax
117+
export const clickhouse: DialectOptions = {
118+
name: 'clickhouse',
119+
tokenizerOptions: {
120+
reservedSelect,
121+
reservedClauses: [...reservedClauses, ...standardOnelineClauses, ...tabularOnelineClauses],
122+
reservedSetOperations,
123+
reservedJoins,
124+
reservedKeywordPhrases: keywordPhrases,
125+
126+
reservedKeywords: keywords,
127+
reservedDataTypes: dataTypes,
128+
reservedFunctionNames: functions,
129+
nestedBlockComments: false,
130+
underscoresInNumbers: true,
131+
stringTypes: ['$$', "''-qq", "''-qq-bs"],
132+
identTypes: ['""-qq', '``'],
133+
paramTypes: {
134+
// https://clickhouse.com/docs/sql-reference/syntax#defining-and-using-query-parameters
135+
custom: [
136+
{
137+
regex: String.raw`\{\s*[a-zA-Z0-9_]+\s*:\s*[a-zA-Z0-9_]+\s*\}`,
138+
key: v => {
139+
const [key] = v.split(':');
140+
return key.trim();
141+
},
142+
},
143+
],
144+
},
145+
operators: [
146+
// Arithmetic
147+
'%', // modulo
148+
149+
// Ternary
150+
'?',
151+
':',
152+
153+
// Lambda creation
154+
'->',
155+
],
156+
},
157+
formatOptions: {
158+
onelineClauses: standardOnelineClauses,
159+
tabularOnelineClauses,
160+
},
161+
};

0 commit comments

Comments
 (0)