|
7 | 7 |
|
8 | 8 | [English](./README.md) | 简体中文 |
9 | 9 |
|
10 | | -dt-sql-parser 是一个基于 [ANTLR4](https://github.com/antlr/antlr4) 开发的, 针对大数据领域的 **SQL Parser** 项目。通过[ANTLR4](https://github.com/antlr/antlr4) 默认生成的 Parser、Visitor 和 Listener 对象,我们可以轻松的做到对 SQL 语句的**语法检查**(Syntax Validation)、**词法分析**(Tokenizer)、 **遍历 AST** 节点等功能。此外,还提供了几个辅助方法, 例如 SQL 切割(Split)、过滤 SQL 语句中的 `--` 和 `/**/` 等类型的注释。 |
| 10 | +dt-sql-parser 是一个基于 [ANTLR4](https://github.com/antlr/antlr4) 开发的, 针对大数据领域的 **SQL Parser** 项目。通过[ANTLR4](https://github.com/antlr/antlr4) 默认生成的 Parser、Visitor 和 Listener 对象,我们可以轻松的做到对 SQL 语句的**语法检查**(Syntax Validation)、**词法分析**(Tokenizer)、 **遍历 AST** 节点等功能。此外,还提供了一些辅助方法, 例如 **SQL 切割(Split)**、**自动补全**等。 |
11 | 11 |
|
12 | | -已支持的 SQL 类型: |
| 12 | +**已支持的 SQL 类型:** |
13 | 13 |
|
14 | | -- MySQL |
| 14 | +- Generic SQL (MySQL) |
15 | 15 | - Flink SQL |
16 | 16 | - Spark SQL |
17 | 17 | - Hive SQL |
18 | 18 | - PL/SQL |
| 19 | +- PostgreSQL |
19 | 20 | - Trino SQL |
20 | 21 |
|
| 22 | +**SQL 辅助方法支持** |
| 23 | + |
| 24 | +| SQL 类型 | SQL 切割 | 自动补全 | |
| 25 | +| ----------- | -------- | -------- | |
| 26 | +| Generic SQL | WIP | WIP | |
| 27 | +| Flink SQL | ✅ | ✅ | |
| 28 | +| Spark SQL | ✅ | ✅ | |
| 29 | +| Hive SQL | ✅ | ✅ | |
| 30 | +| PL/SQL | WIP | WIP | |
| 31 | +| Postgre SQL | WIP | WIP | |
| 32 | +| Trino SQL | WIP | WIP | |
| 33 | + |
21 | 34 | > 提示:当前的 Parser 是 `Javascript` 语言版本,如果有必要,可以尝试编译 Grammar 文件到其他目标语言 |
22 | 35 |
|
| 36 | +<br/> |
| 37 | + |
| 38 | +## 与 MonacoEditor 集成 |
| 39 | +我们提供了一个[monaco-sql-languages](https://github.com/DTStack/monaco-sql-languages)包,你可以轻易的将`dt-sql-parser`与`monaco-editor`集成。 |
| 40 | + |
| 41 | +<br/> |
| 42 | + |
23 | 43 | ## 安装 |
24 | 44 |
|
25 | 45 | ```bash |
26 | | -// use npm |
| 46 | +# use npm |
27 | 47 | npm i dt-sql-parser --save |
28 | 48 |
|
29 | | -// use yarn |
| 49 | +# use yarn |
30 | 50 | yarn add dt-sql-parser |
31 | 51 | ``` |
32 | 52 |
|
| 53 | +<br/> |
| 54 | + |
33 | 55 | ## 使用 |
| 56 | +在开始使用前,需要先了解基本的使用方式。`dt-sql-parser` 为不同类型的 SQL分别提供相应的 SQL Parser 类: |
| 57 | +```javascript |
| 58 | +import { GenericSQL, FlinkSQL, SparkSQL, HiveSQL, PLSQL, PostgresSQL, TrinoSQL } from 'dt-sql-parser'; |
| 59 | +``` |
34 | 60 |
|
35 | | -### 语法校验(Syntax Validation) |
| 61 | +在使用语法校验,自动补全等功能之前,需要先实例化对应 SQL 类型的 Parser,以 `GenericSQL` 为例: |
| 62 | +```javascript |
| 63 | +const parser = new GenericSQL(); |
| 64 | +``` |
36 | 65 |
|
37 | | -首先需要声明相应的 Parser 对象,不同的 SQL 类型需要引入不同的 Parser 对象处理,例如如果是 |
38 | | -针对 **Flink SQL**,则需要单独引入 **FlinkSQL** Parser,这里我们使用 **GenericSQL** 作为示例: |
| 66 | +下文中的使用示例将使用 `GenericSQL`,其他 SQL 类型的 Parser 使用方式与`GenericSQL` 相同。 |
39 | 67 |
|
| 68 | +<br/> |
| 69 | + |
| 70 | +### 语法校验(Syntax Validation) |
40 | 71 | ```javascript |
41 | 72 | import { GenericSQL } from 'dt-sql-parser'; |
42 | 73 |
|
@@ -81,6 +112,8 @@ console.log(errors); |
81 | 112 |
|
82 | 113 | 先实例化 Parser 对象,然后使用 `validate` 方法对 SQL 语句进行校验,如果校验失败,则返回一个包含 `error` 信息的数组。 |
83 | 114 |
|
| 115 | +<br/> |
| 116 | + |
84 | 117 | ### 词法分析(Tokenizer) |
85 | 118 |
|
86 | 119 | 必要场景下,可单独对 SQL 语句进行词法分析,获取所有的 Tokens 对象: |
@@ -110,6 +143,8 @@ console.log(tokens) |
110 | 143 | */ |
111 | 144 | ``` |
112 | 145 |
|
| 146 | +<br/> |
| 147 | + |
113 | 148 | ### 访问者模式(Visitor) |
114 | 149 |
|
115 | 150 | 使用 Visitor 模式访问 AST 中的指定节点 |
@@ -145,9 +180,11 @@ TableName user1 |
145 | 180 |
|
146 | 181 | > 提示:使用 Visitor 模式时,节点的方法名称可以在对应 SQL 目录下的 Visitor 文件中查找 |
147 | 182 |
|
| 183 | +<br/> |
| 184 | + |
148 | 185 | ### 监听器(Listener) |
149 | 186 |
|
150 | | -Listener 模式,利用 [ANTLR4](https://github.com/antlr/antlr4) 提供的 ParseTreeWalker 对象遍历 AST,进入各个节点时调用对应的方法。 |
| 187 | +Listener 模式,利用 [ANTLR4](https://github.com/antlr/antlr4) 提供的 `ParseTreeWalker` 对象遍历 AST,进入各个节点时调用对应的方法。 |
151 | 188 |
|
152 | 189 | ```javascript |
153 | 190 | import { GenericSQL, SqlParserListener } from 'dt-sql-parser'; |
@@ -178,50 +215,112 @@ TableName user1 |
178 | 215 |
|
179 | 216 | > 提示:使用 Listener 模式时,节点的方法名称可以在对应 SQL 目录下的 Listener 文件中查找 |
180 | 217 |
|
181 | | -### 清理注释内容 |
182 | | - |
183 | | -清除注释和前后空格 |
| 218 | +<br/> |
184 | 219 |
|
| 220 | +### SQL 按语句切割 |
| 221 | +以 `FlinkSQL` 为例: |
185 | 222 | ```javascript |
186 | | -import { cleanSql } from 'dt-sql-parser'; |
187 | | - |
188 | | -const sql = `-- comment comment |
189 | | -select id,name from user1; ` |
190 | | -const cleanedSql = cleanSql(sql) |
191 | | -console.log(cleanedSql) |
| 223 | +import { FlinkSQL } from 'dt-sql-parser'; |
| 224 | +const parser = new FlinkSQL(); |
| 225 | +const sql = 'SHOW TABLES;\nSELECT * FROM tb;'; |
| 226 | +const sqlSlices = parser.splitSQLByStatement(sql); |
| 227 | +console.log(sqlSlices) |
192 | 228 |
|
193 | 229 | /* |
194 | | -select id,name from user1; |
| 230 | +[ |
| 231 | + { |
| 232 | + startIndex: 0, |
| 233 | + endIndex: 11, |
| 234 | + startLine: 1, |
| 235 | + endLine: 1, |
| 236 | + startColumn: 1, |
| 237 | + endColumn: 12, |
| 238 | + text: 'SHOW TABLES;' |
| 239 | + }, |
| 240 | + { |
| 241 | + startIndex: 13, |
| 242 | + endIndex: 29, |
| 243 | + startLine: 2, |
| 244 | + endLine: 2, |
| 245 | + startColumn: 1, |
| 246 | + endColumn: 17, |
| 247 | + text: 'SELECT * FROM tb;' |
| 248 | + } |
| 249 | +] |
195 | 250 | */ |
196 | | -``` |
197 | | - |
198 | | -### 切割 SQL (Split) |
199 | 251 |
|
200 | | -SQL 太大的情况下,我们可以先将SQL语句按 `;` 切割,然后逐句处理。 |
201 | | - |
202 | | -```javascript |
203 | | -import { splitSql } from 'dt-sql-parser'; |
204 | | - |
205 | | -const sql = `select id,name from user1; |
206 | | -select id,name from user2;` |
207 | | -const sqlList = splitSql(sql) |
208 | | -console.log(sqlList) |
209 | | - |
210 | | -/* |
211 | | -["select id,name from user1;", "\nselect id,name from user2;"] |
212 | | -*/ |
213 | 252 | ``` |
214 | 253 |
|
215 | | -### 其他 API |
216 | | - |
217 | | -- parserTreeToString (input: string) |
| 254 | +<br/> |
| 255 | + |
| 256 | +### 自动补全(Auto Complete) |
| 257 | +在 sql 的指定位置上获取自动补全信息,以 `FlinkSQL` 为例: |
| 258 | + |
| 259 | +调用 `getSuggestionAtCaretPosition` 方法,传入 sql 内容和需要自动补全的位置的行列号。 |
| 260 | ++ 获取关键字候选项列表 |
| 261 | + |
| 262 | + ```javascript |
| 263 | + import { FlinkSQL } from 'dt-sql-parser'; |
| 264 | + const parser = new FlinkSQL(); |
| 265 | + const sql = 'CREATE '; |
| 266 | + const pos = { lineNumber: 1, column: 16 }; // 最后一个位置 |
| 267 | + const keywords = parser.getSuggestionAtCaretPosition(sql, pos)?.keywords; |
| 268 | + console.log(keywords); |
| 269 | + |
| 270 | + /* |
| 271 | + [ 'CATALOG', 'FUNCTION', 'TEMPORARY', 'VIEW', 'DATABASE', 'TABLE' ] |
| 272 | + */ |
| 273 | + ``` |
| 274 | ++ 获取语法相关自动补全信息 |
| 275 | + ```javascript |
| 276 | + const parser = new FlinkSQL(); |
| 277 | + const sql = 'SELECT * FROM tb'; |
| 278 | + const pos = { lineNumber: 1, column: 16 }; // tb 的后面 |
| 279 | + const syntaxSuggestions = parser.getSuggestionAtCaretPosition(sql, pos)?.syntax; |
| 280 | + console.log(syntaxSuggestions); |
| 281 | + |
| 282 | + /* |
| 283 | + [ |
| 284 | + { |
| 285 | + syntaxContextType: 'table', |
| 286 | + wordRanges: [ |
| 287 | + { |
| 288 | + text: 'tb', |
| 289 | + startIndex: 14, |
| 290 | + stopIndex: 15, |
| 291 | + line: 1, |
| 292 | + startColumn: 15, |
| 293 | + stopColumn: 16 |
| 294 | + } |
| 295 | + ] |
| 296 | + }, |
| 297 | + { |
| 298 | + syntaxContextType: 'view', |
| 299 | + wordRanges: [ |
| 300 | + { |
| 301 | + text: 'tb', |
| 302 | + startIndex: 14, |
| 303 | + stopIndex: 15, |
| 304 | + line: 1, |
| 305 | + startColumn: 15, |
| 306 | + stopColumn: 16 |
| 307 | + } |
| 308 | + ] |
| 309 | + } |
| 310 | + ] |
| 311 | + */ |
| 312 | + ``` |
| 313 | +语法相关自动补全信息返回一个数组,数组中每一项代表该位置可以填写什么语法,比如上例中的输出结果代表该位置可以填写**表名**或者**视图名称**。其中 `syntaxContextType` 是可以补全的语法类型,`wordRanges` 则是已经填写的内容。 |
| 314 | +
|
| 315 | +<br/> |
218 | 316 |
|
219 | | -将 SQL 解析成 `List-like` 风格的树形字符串, 一般用于测试 |
| 317 | +### 其他 API |
220 | 318 |
|
221 | | -## 路线图 |
| 319 | +- `createLexer` 创建一个 Antlr4 Lexer 实例并返回; |
| 320 | +- `createParser` 创建一个 Antlr4 Parser 实例并返回; |
| 321 | +- `parse` 解析输入的 sql,并返回解析树; |
222 | 322 |
|
223 | | -- Auto-complete |
224 | | -- Format code |
| 323 | +<br/> |
225 | 324 |
|
226 | 325 | ## 许可证 |
227 | 326 |
|
|
0 commit comments