diff --git a/README-zh_CN.md b/README-zh_CN.md
index 9e3e08a6..35f67510 100644
--- a/README-zh_CN.md
+++ b/README-zh_CN.md
@@ -17,6 +17,7 @@ Monaco SQL Languages 是一个基于 Monaco Editor 的 SQL 语言项目,从 [m
- 代码高亮
- 语法校验
- 自动补全
+- 内置SQL代码片段
> 由 [dt-sql-parser](https://github.com/DTStack/dt-sql-parser) 提供语法解析功能。
@@ -91,7 +92,7 @@ npm install monaco-sql-languages
});
```
- 默认情况下,自动补全功能只提供关键字自动补全, 但你可以通过设置 `completionService` 自定义自动补全项。
+ 默认情况下,自动补全功能只提供关键字自动补全与内置SQL代码片段补全, 但你可以通过设置 `completionService` 自定义自动补全项。
```typescript
import { languages } from 'monaco-editor/esm/vs/editor/editor.api';
@@ -108,7 +109,8 @@ npm install monaco-sql-languages
position,
completionContext,
suggestions, // 语法推荐信息
- entities // 当前编辑器文本的语法上下文中出现的表名、字段名等
+ entities, // 当前编辑器文本的语法上下文中出现的表名、字段名等
+ snippets // 代码片段
) {
return new Promise((resolve, reject) => {
if (!suggestions) {
@@ -160,6 +162,92 @@ npm install monaco-sql-languages
+## 代码片段
+我们为每种SQL语言内置了一部分代码片段, 帮助我们快速编写SQL。
+
+**如何自定义代码片段?**
+
+在进行设置语言功能时, 通过配置`snippets`实现, 当`snippets`传入空数组时, 则关闭内置代码片段。
+
+```typescript
+import { snippets, CompletionSnippetOption } from 'monaco-sql-languages/esm/main.js';
+
+const customSnippets: CompletionSnippetOption[] = [
+ {
+ label: 'INSERT',
+ prefix: 'insert',
+ // Will join the line with `\n`
+ body: [
+ 'INSERT INTO ${1:table_name}',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ],
+ description: "This is an 'insert into select' snippet"
+ }
+];
+
+setupLanguageFeatures(LanguageIdEnum.MYSQL, {
+ completionItems: {
+ enable: true,
+ snippets: [...snippets.mysqlSnippets, ...customSnippets],
+ completionService
+ },
+ preprocessCode
+});
+```
+代码片段详细语法可以参考[vscode-snippet](https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax), 不过与 vscode 代码片段不同的是, 我们仅会在**SQL语句开头**提供 snippets 补全项。
+
+还需要注意的是,如果您提供了自定义的`completionService`方法, 您需要将`snippets`作为补全项手动返回, 以下是一个简单示例:
+
+```typescript
+const completionService: CompletionService = async function (
+ model,
+ position,
+ completionContext,
+ suggestions,
+ entities,
+ snippets
+) {
+ const { keywords } = suggestions;
+
+ const keywordsCompletionItems: ICompletionItem[] = keywords.map((kw) => ({
+ label: kw,
+ kind: languages.CompletionItemKind.Keyword,
+ detail: 'keyword',
+ sortText: '2' + kw
+ }));
+
+ const snippetCompletionItems: ICompletionItem[] =
+ snippets?.map((item) => ({
+ label: item.label || item.prefix,
+ kind: languages.CompletionItemKind.Snippet,
+ filterText: item.prefix,
+ insertText: item.insertText,
+ insertTextRules: languages.CompletionItemInsertTextRule.InsertAsSnippet,
+ sortText: '3' + item.prefix,
+ detail: item.description !== undefined ? item.description : 'SQL Snippet',
+ documentation: item.insertText
+ })) || [];
+
+ return [...keywordsCompletionItems, ...snippetCompletionItems];
+};
+```
+
+**其他注意事项**
+
+当处于代码片段中时, 可以通过`Tab`键移动到下一个输入位置, 但普通的关键字补全功能也是通过`Tab`键接受补全的,这会产生快捷键冲突, 所以 Monaco-Editor 规定, 当处于代码片段上下文时, 不会触发补全功能。
+
+如果想要在代码片段中仍能支持智能补全, 可以通过设置 Monaco-Editor 配置项`suggest.snippetsPreventQuickSuggestions`为`false`来实现。
+```typescript
+editor.create(editorElement, {
+ suggest: {
+ snippetsPreventQuickSuggestions: false
+ }
+})
+```
+
+
## Monaco Theme
> Monaco SQL Languages 计划在未来支持更多的 Monaco Theme.
diff --git a/README.md b/README.md
index e346ed38..03f15121 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ This project is based on the SQL language project of Monaco Editor, which was fo
- Code Highlighting
- Syntax Validation
- Code Completion
+- Built-in SQL Snippets
> Powered By [dt-sql-parser](https://github.com/DTStack/dt-sql-parser)
@@ -91,7 +92,7 @@ npm install monaco-sql-languages
});
```
- By default, Monaco SQL Languages only provides keyword autocompletion, and you can customize your completionItem list via `completionService`.
+ By default, Monaco SQL Languages only provides keyword autocompletion and built-in SQL snippets, and you can customize your completionItem list via `completionService`.
```typescript
import { languages } from 'monaco-editor/esm/vs/editor/editor.api';
@@ -108,7 +109,8 @@ npm install monaco-sql-languages
position,
completionContext,
suggestions, // syntax context info at caretPosition
- entities // tables, columns in the syntax context of the editor text
+ entities, // tables, columns in the syntax context of the editor text
+ snippets // SQL snippets
) {
return new Promise((resolve, reject) => {
if (!suggestions) {
@@ -160,6 +162,86 @@ npm install monaco-sql-languages
+## SQL Snippets
+
+We provide some built-in SQL snippets for each SQL language, which helps us to write SQL quickly.
+
+**How to customize SQL snippets?**
+
+When setting language features, you can customize SQL snippets via `snippets` configuration. When `snippets` is passed in as an empty array, the built-in SQL snippets are disabled.
+
+```typescript
+import { snippets, CompletionSnippetOption } from 'monaco-sql-languages/esm/main.js';
+
+const customSnippets: CompletionSnippetOption[] = [
+ {
+ label: 'INSERT',
+ prefix: 'insert',
+ // Will join the line with `\n`
+ body: [
+ 'INSERT INTO ${1:table_name}',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ],
+ description: "This is an 'insert into select' snippet"
+ }
+];
+```
+
+Snippets syntax can refer to [vscode-snippet](https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax).
+But it is different from vscode code snippets, we only provide snippets completions **at the beginning of the SQL statement**.
+
+Note: If you provide a custom `completionService` method, you need to manually return the `snippets` as completions, as shown in the following example:
+
+```typescript
+const completionService: CompletionService = async function (
+ model,
+ position,
+ completionContext,
+ suggestions,
+ entities,
+ snippets
+) {
+ const { keywords } = suggestions;
+
+ const keywordsCompletionItems: ICompletionItem[] = keywords.map((kw) => ({
+ label: kw,
+ kind: languages.CompletionItemKind.Keyword,
+ detail: 'keyword',
+ sortText: '2' + kw
+ }));
+
+ const snippetCompletionItems: ICompletionItem[] =
+ snippets?.map((item) => ({
+ label: item.label || item.prefix,
+ kind: languages.CompletionItemKind.Snippet,
+ filterText: item.prefix,
+ insertText: item.insertText,
+ insertTextRules: languages.CompletionItemInsertTextRule.InsertAsSnippet,
+ sortText: '3' + item.prefix,
+ detail: item.description !== undefined ? item.description : 'SQL Snippet',
+ documentation: item.insertText
+ })) || [];
+
+ return [...keywordsCompletionItems, ...snippetCompletionItems];
+};
+```
+
+Other Notes:
+
+When in code snippet context, you can use `Tab` key to move to the next input position, but the keywords completions is also triggered by `Tab` key, which will cause a shortcut key conflict. So Monaco-Editor stipulates that when in code snippet context, it will not trigger completion.
+
+If you want to still support intelligent completion in code snippet context, you can set the Monaco-Editor configuration item `suggest.snippetsPreventQuickSuggestions` to `false` to achieve it.
+```typescript
+editor.create(editorElement, {
+ suggest: {
+ snippetsPreventQuickSuggestions: false
+ }
+})
+```
+
+
## Monaco Theme
> Monaco SQL Languages plan to support more themes in the future.
diff --git a/documents/images/snippet-no-prevent-completion.gif b/documents/images/snippet-no-prevent-completion.gif
new file mode 100644
index 00000000..6570c94c
Binary files /dev/null and b/documents/images/snippet-no-prevent-completion.gif differ
diff --git a/documents/images/snippet-prevent-completion.gif b/documents/images/snippet-prevent-completion.gif
new file mode 100644
index 00000000..2e574ff2
Binary files /dev/null and b/documents/images/snippet-prevent-completion.gif differ
diff --git a/package.json b/package.json
index dc75bc76..4ed60883 100644
--- a/package.json
+++ b/package.json
@@ -67,7 +67,7 @@
"pre-commit": "npx pretty-quick --staged"
},
"dependencies": {
- "dt-sql-parser": "4.1.0-beta.4"
+ "dt-sql-parser": "4.2.0"
},
"peerDependencies": {
"monaco-editor": ">=0.31.0"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1c3b1e83..986d2d9f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,8 +9,8 @@ importers:
.:
dependencies:
dt-sql-parser:
- specifier: 4.1.0-beta.4
- version: 4.1.0-beta.4(antlr4ng-cli@1.0.7)
+ specifier: 4.2.0
+ version: 4.2.0(antlr4ng-cli@1.0.7)
devDependencies:
'@commitlint/cli':
specifier: ^17.7.2
@@ -308,6 +308,7 @@ packages:
antlr4ng-cli@1.0.7:
resolution: {integrity: sha512-qN2FsDBmLvsQcA5CWTrPz8I8gNXeS1fgXBBhI78VyxBSBV/EJgqy8ks6IDTC9jyugpl40csCQ4sL5K4i2YZ/2w==}
+ deprecated: 'This package is deprecated and will no longer be updated. Please use the new antlr-ng package instead: https://github.com/mike-lischke/antlr-ng'
hasBin: true
antlr4ng@2.0.11:
@@ -714,8 +715,8 @@ packages:
resolution: {integrity: sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA==}
engines: {node: '>=6'}
- dt-sql-parser@4.1.0-beta.4:
- resolution: {integrity: sha512-L+Qsw+lv7enkMuhy0XXOm7H63gaajwX7X0RUGCNU8h5xw9Pj5DEWvLcKTS0R+YmO4FzVXOpEzH9e1KkqQaKFaQ==}
+ dt-sql-parser@4.2.0:
+ resolution: {integrity: sha512-tsTHGNGIeTd7xACh8FNzSCaQHYyITJeSTMZPxGFkROiccPxj82uEqOeUgJ+bYof9hEacf4h61LsiMyxPy+tl7g==}
engines: {node: '>=18'}
email-addresses@3.1.0:
@@ -2703,7 +2704,7 @@ snapshots:
find-up: 3.0.0
minimatch: 3.1.2
- dt-sql-parser@4.1.0-beta.4(antlr4ng-cli@1.0.7):
+ dt-sql-parser@4.2.0(antlr4ng-cli@1.0.7):
dependencies:
antlr4-c3: 3.3.7(antlr4ng-cli@1.0.7)
antlr4ng: 2.0.11(antlr4ng-cli@1.0.7)
diff --git a/src/baseSQLWorker.ts b/src/baseSQLWorker.ts
index 3d3029cf..4fe0166c 100644
--- a/src/baseSQLWorker.ts
+++ b/src/baseSQLWorker.ts
@@ -2,6 +2,7 @@ import { BasicSQL } from 'dt-sql-parser/dist/parser/common/basicSQL';
import { worker } from './fillers/monaco-editor-core';
import { Suggestions, ParseError, EntityContext } from 'dt-sql-parser';
import { Position } from './fillers/monaco-editor-core';
+import { SemanticContext } from 'dt-sql-parser/dist/parser/common/types';
export interface ICreateData {
languageId: string;
@@ -45,7 +46,11 @@ export abstract class BaseSQLWorker {
async doCompletionWithEntities(
code: string,
position: Position
- ): Promise<[Suggestions | null, EntityContext[] | null]> {
+ ): Promise<{
+ suggestions: Suggestions | null;
+ allEntities: EntityContext[] | null;
+ context: SemanticContext | null;
+ }> {
code = code || this.getTextDocument();
if (code) {
const suggestions = this.parser.getSuggestionAtCaretPosition(code, position);
@@ -53,9 +58,20 @@ export abstract class BaseSQLWorker {
if (suggestions?.syntax?.length) {
allEntities = this.parser.getAllEntities(code, position);
}
- return Promise.resolve([suggestions, allEntities]);
+ const semanticContext = this.parser.getSemanticContextAtCaretPosition(code, position);
+
+ return Promise.resolve({
+ suggestions,
+ allEntities,
+ context: semanticContext
+ });
}
- return Promise.resolve([null, null]);
+
+ return Promise.resolve({
+ suggestions: null,
+ allEntities: null,
+ context: null
+ });
}
async getAllEntities(code: string, position?: Position): Promise {
diff --git a/src/languageFeatures.ts b/src/languageFeatures.ts
index e1325c70..fa684269 100644
--- a/src/languageFeatures.ts
+++ b/src/languageFeatures.ts
@@ -15,7 +15,7 @@ import {
Range,
Uri
} from './fillers/monaco-editor-core';
-import type { LanguageServiceDefaults } from './monaco.contribution';
+import type { CompletionSnippet, LanguageServiceDefaults } from './monaco.contribution';
export interface WorkerAccessor {
(...uris: Uri[]): Promise;
@@ -163,13 +163,22 @@ export class CompletionAdapter
}
return worker.doCompletionWithEntities(code, position);
})
- .then(([suggestions, allEntities]) => {
+ .then(({ suggestions, allEntities, context: semanticContext }) => {
+ let snippets: CompletionSnippet[] = [];
+ if (semanticContext?.isStatementBeginning) {
+ snippets = this._defaults.completionSnippets.map((item) => ({
+ ...item,
+ insertText: typeof item.body === 'string' ? item.body : item.body.join('\n')
+ }));
+ }
+
return this._defaults.completionService(
model,
position,
context,
suggestions,
- allEntities
+ allEntities,
+ snippets
);
})
.then((completions) => {
diff --git a/src/languages/flink/flink.snippet.ts b/src/languages/flink/flink.snippet.ts
new file mode 100644
index 00000000..d9b25eca
--- /dev/null
+++ b/src/languages/flink/flink.snippet.ts
@@ -0,0 +1,115 @@
+import type { CompletionSnippetOption } from 'src/monaco.contribution';
+
+export const flinkSnippets: CompletionSnippetOption[] = [
+ {
+ label: 'create-source-table',
+ prefix: 'CREATE-SOURCE-TABLE',
+ body: [
+ 'CREATE TABLE ${1:source_table} (',
+ '\tid STRING,',
+ '\tval BIGINT,',
+ '\tts TIMESTAMP(3),',
+ "\tWATERMARK FOR ts AS ts - INTERVAL '5' SECOND",
+ ') WITH (',
+ "\t'connector' = 'kafka',",
+ "\t'topic' = 'input_topic',",
+ "\t'properties.bootstrap.servers' = 'localhost:9092',",
+ "\t'format' = 'json',",
+ "\t'scan.startup.mode' = 'earliest-offset'",
+ ');'
+ ]
+ },
+ {
+ label: 'create-sink-table',
+ prefix: 'CREATE-SINK-TABLE',
+ body: [
+ 'CREATE TABLE ${1:sink_table} (',
+ '\tid STRING,',
+ '\tcnt BIGINT',
+ ') WITH (',
+ "\t'connector' = 'jdbc',",
+ "\t'url' = 'jdbc:mysql://localhost:3306/test',",
+ "\t'table-name' = 'output_table',",
+ "\t'username' = 'root',",
+ "\t'password' = 'password'",
+ ');'
+ ]
+ },
+ {
+ label: 'tumble-window',
+ prefix: 'TUMBLE-WINDOW',
+ body: [
+ 'SELECT',
+ '\twindow_start,',
+ '\twindow_end,',
+ '\tSUM(price) as total_price',
+ 'FROM',
+ '\tTABLE(TUMBLE(TABLE table_name2,',
+ '\tDESCRIPTOR(create_time),',
+ "\tINTERVAL '1' MINUTE))",
+ 'GROUP BY',
+ '\twindow_start,',
+ '\twindow_end;'
+ ]
+ },
+ {
+ label: 'hop-window',
+ prefix: 'HOP-WINDOW',
+ body: [
+ 'SELECT',
+ '\twindow_start,',
+ '\twindow_end,',
+ '\tSUM(price) as total_price',
+ 'FROM',
+ '\tTABLE(HOP(TABLE table_name2,',
+ '\tDESCRIPTOR(create_time),',
+ "\tINTERVAL '30' SECONDS,",
+ "\tINTERVAL '1' MINUTE))",
+ 'GROUP BY',
+ '\twindow_start,',
+ '\twindow_end;'
+ ]
+ },
+ {
+ label: 'comulate-window',
+ prefix: 'CUMULATE-WINDOW',
+ body: [
+ 'SELECT',
+ '\twindow_start,',
+ '\twindow_end,',
+ '\tSUM(price) as total_price',
+ 'FROM',
+ '\tTABLE(CUMULATE(TABLE table_name2,',
+ '\tDESCRIPTOR(create_time),',
+ "\tINTERVAL '30' SECONDS,",
+ "\tINTERVAL '1' MINUTE))",
+ 'GROUP BY',
+ '\twindow_start,',
+ '\twindow_end;'
+ ]
+ },
+ {
+ label: 'session-window',
+ prefix: 'SESSION-WINDOW',
+ body: [
+ 'SELECT',
+ "\tSESSION_START(create_time, INTERVAL '10' SECOND) AS session_beg,",
+ "\tSESSION_ROWTIME(create_time, INTERVAL '10' SECOND) AS session_end,",
+ '\tSUM(price) AS total_price',
+ 'FROM',
+ '\ttable_name',
+ 'GROUP BY',
+ "\tSESSION(create_time, INTERVAL '10' SECOND);"
+ ]
+ },
+ {
+ label: 'insert-into-select',
+ prefix: 'INSERT-INTO-SELECT',
+ body: [
+ 'INSERT INTO ${1:table_name}',
+ 'SELECT ${2:column1}, ${3:column2}',
+ 'FROM ${4:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ }
+];
diff --git a/src/languages/hive/hive.snippet.ts b/src/languages/hive/hive.snippet.ts
new file mode 100644
index 00000000..a1fe4ef6
--- /dev/null
+++ b/src/languages/hive/hive.snippet.ts
@@ -0,0 +1,144 @@
+import type { CompletionSnippetOption } from 'src/monaco.contribution';
+
+export const hiveSnippets: CompletionSnippetOption[] = [
+ {
+ label: 'select',
+ prefix: 'SELECT',
+ body: ['SELECT ${2:column1}, ${3:column2} FROM ${1:table_name};\n$4']
+ },
+ {
+ label: 'select-join',
+ prefix: 'SELECT-JOIN',
+ body: [
+ 'SELECT ${8:column1} FROM ${1:table_name} ${2:t1}',
+ '${3:LEFT} JOIN ${4:table2} ${5:t2} ON ${2:t1}.${6:column1} = ${5:t2}.${7:column2};\n$9'
+ ]
+ },
+ {
+ label: 'select-order-by',
+ prefix: 'SELECT-ORDERBY',
+ body: [
+ 'SELECT ${2:column1}, ${3:column2} FROM ${1:table_name} ORDER BY ${4:column1} ${5:desc};\n$6'
+ ]
+ },
+ {
+ label: 'insert',
+ prefix: 'INSERT-INTO',
+ body: [
+ 'INSERT INTO ${1:table_name} (${2:column1}, ${3:column2}) VALUES (${4:value1}, ${5:value2});\n$6'
+ ]
+ },
+ {
+ label: 'insert-into-select',
+ prefix: 'INSERT-INTO-SELECT',
+ body: [
+ 'INSERT INTO TABLE ${1:table_name}',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'insert-overwrite-table',
+ prefix: 'INSERT-OVERWRITE-TABLE',
+ body: [
+ 'INSERT OVERWRITE TABLE ${1:table_name}',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'update',
+ prefix: 'UPDATE',
+ body: [
+ 'UPDATE ${1:table_name}',
+ 'SET ${2:column1} = ${3:value1}',
+ 'WHERE ${4:column2} = ${5:value2};\n$6'
+ ]
+ },
+ {
+ label: 'delete',
+ prefix: 'DELETE',
+ body: ['DELETE FROM ${1:table_name}', 'WHERE ${2:column1} = ${3:value1};\n$4']
+ },
+ {
+ label: 'create-table',
+ prefix: 'CREATE-TABLE',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name} (',
+ '\t${2:column1} ${3:STRING},',
+ '\t${4:column2} ${5:STRING}',
+ ')',
+ "COMMENT '${6:table_comment}'",
+ 'ROW FORMAT ${7:DELIMITED}',
+ "FIELDS TERMINATED BY '${8:\\t}'",
+ 'STORED AS ${9:PARQUET};\n$10'
+ ]
+ },
+ {
+ label: 'create-table-as-select',
+ prefix: 'CREATE-TABLE-AS-SELECT',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name}',
+ 'AS',
+ 'SELECT ${2:column1}, ${3:column2}',
+ 'FROM ${4:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'create-partition-table',
+ prefix: 'CREATE-PARTITION-TABLE',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name} (',
+ '\t${2:column1} ${3:STRING},',
+ '\t${4:column2} ${5:STRING}',
+ ')',
+ "COMMENT '${6:table_comment}'",
+ 'PARTITIONED BY (${7:part_column_name} STRING)',
+ 'ROW FORMAT ${8:DELIMITED}',
+ "FIELDS TERMINATED BY '${9:\\t}'",
+ 'STORED AS ${10:PARQUET};\n$11'
+ ]
+ },
+ {
+ label: 'create-bucket-table',
+ prefix: 'CREATE-BUCKET-TABLE',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name} (',
+ '\t${2:column1} ${3:STRING},',
+ '\t${4:column2} ${5:STRING}',
+ ')',
+ "COMMENT '${6:table_comment}'",
+ 'PARTITIONED BY (${7:part_column_name} STRING)',
+ 'CLUSTERED BY (${8:bucket_column_name}) INTO ${9:1} BUCKETS',
+ 'ROW FORMAT ${10:DELIMITED}',
+ "FIELDS TERMINATED BY '${11:\\t}'",
+ 'STORED AS ${12:PARQUET};\n$13'
+ ]
+ },
+ {
+ label: 'alter-table-partition',
+ prefix: 'ALTER-TABLE-PARTITION',
+ body: [
+ "ALTER TABLE ${1:table_name} ${2:ADD} PARTITION (${3:part_column}='${4:part_value}');\n$5"
+ ]
+ },
+ {
+ label: 'alter-table-properties',
+ prefix: 'ALTER-TABLE-PROPERTIES',
+ body: [
+ "ALTER TABLE ${1:table_name} SET TBLPROPERTIES ('${2:property_name}'='${3:property_value}');\n$4"
+ ]
+ },
+ {
+ label: 'alter-table-columns',
+ prefix: 'ALTER-TABLE-COLUMNS',
+ body: [
+ 'ALTER TABLE ${1:table_name} ADD COLUMNS (',
+ "\t${2:column_name} ${3:STRING} COMMENT '${4:desc}'",
+ ');\n$5'
+ ]
+ }
+];
diff --git a/src/languages/impala/impala.snippet.ts b/src/languages/impala/impala.snippet.ts
new file mode 100644
index 00000000..d0aec317
--- /dev/null
+++ b/src/languages/impala/impala.snippet.ts
@@ -0,0 +1,122 @@
+import type { CompletionSnippetOption } from 'src/monaco.contribution';
+
+export const impalaSnippets: CompletionSnippetOption[] = [
+ {
+ label: 'select',
+ prefix: 'SELECT',
+ body: ['SELECT ${2:column1}, ${3:column2} FROM ${1:table_name};\n$4']
+ },
+ {
+ label: 'select-join',
+ prefix: 'SELECT-JOIN',
+ body: [
+ 'SELECT ${8:column1} FROM ${1:table_name} ${2:t1}',
+ '${3:LEFT} JOIN ${4:table2} ${5:t2} ON ${2:t1}.${6:column1} = ${5:t2}.${7:column2};\n$9'
+ ]
+ },
+ {
+ label: 'select-order-by',
+ prefix: 'SELECT-ORDER-BY',
+ body: [
+ 'SELECT ${2:column1}, ${3:column2} FROM ${1:table_name} ORDER BY ${4:column1} ${5:desc};\n$6'
+ ]
+ },
+ {
+ label: 'insert',
+ prefix: 'INSERT-INTO',
+ body: [
+ 'INSERT INTO ${1:table_name} (${2:column1}, ${3:column2}) VALUES (${4:value1}, ${5:value2});\n$6'
+ ]
+ },
+ {
+ label: 'insert-into-select',
+ prefix: 'INSERT-INTO-SELECT',
+ body: [
+ 'INSERT INTO ${1:table_name}',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'insert-overwrite-table',
+ prefix: 'INSERT-OVERWRITE-TABLE',
+ body: [
+ 'INSERT OVERWRITE TABLE ${1:table_name}',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'update',
+ prefix: 'UPDATE',
+ body: [
+ 'UPDATE ${1:table_name}',
+ 'SET ${2:column1} = ${3:value1}',
+ 'WHERE ${4:column2} = ${5:value2};\n$6'
+ ]
+ },
+ {
+ label: 'delete',
+ prefix: 'DELETE',
+ body: ['DELETE FROM ${1:table_name}', 'WHERE ${2:column1} = ${3:value1};\n$4']
+ },
+ {
+ label: 'create-table',
+ prefix: 'CREATE-TABLE',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name} (',
+ '\t${2:column1} ${3:STRING},',
+ '\t${4:column2} ${5:STRING}',
+ ')',
+ "COMMENT '${6:table_comment}'",
+ 'STORED AS ${7:PARQUET};\n$8'
+ ]
+ },
+ {
+ label: 'create-table-as-select',
+ prefix: 'CREATE-TABLE-AS-SELECT',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name}',
+ 'AS',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'create-partition-table',
+ prefix: 'CREATE-PARTITION-TABLE',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name} (',
+ '\t${2:column1} ${3:STRING},',
+ '\t${4:column2} ${5:STRING}',
+ ')',
+ 'PARTITIONED BY (${6:part_column_name} ${7:STRING})',
+ "COMMENT '${8:table_comment}'",
+ 'STORED AS ${9:PARQUET};\n$10'
+ ]
+ },
+ {
+ label: 'alter-table-partition',
+ prefix: 'ALTER-TABLE-PARTITION',
+ body: [
+ "ALTER TABLE ${1:table_name} ${2:ADD} PARTITION (${3:part_column} = '${4:part_value}');\n$5"
+ ]
+ },
+ {
+ label: 'alter-table-properties',
+ prefix: 'ALTER-TABLE-PROPERTIES',
+ body: [
+ "ALTER TABLE ${1:table_name} SET TBLPROPERTIES ('${2:property_name}' = '${3:property_value}');\n$4"
+ ]
+ },
+ {
+ label: 'alter-table-column',
+ prefix: 'ALTER-TABLE-COLUMN',
+ body: [
+ "ALTER TABLE ${1:table_name} ADD COLUMN ${2:column_name} ${3:STRING} COMMENT '${4:desc}';\n$5"
+ ]
+ }
+];
diff --git a/src/languages/mysql/mysql.snippet.ts b/src/languages/mysql/mysql.snippet.ts
new file mode 100644
index 00000000..b931b909
--- /dev/null
+++ b/src/languages/mysql/mysql.snippet.ts
@@ -0,0 +1,169 @@
+import type { CompletionSnippetOption } from 'src/monaco.contribution';
+
+export const mysqlSnippets: CompletionSnippetOption[] = [
+ {
+ label: 'select',
+ prefix: 'SELECT',
+ body: ['SELECT ${2:column1}, ${3:column2} FROM ${1:table_name};\n$4']
+ },
+ {
+ label: 'select-join',
+ prefix: 'SELECT-JOIN',
+ body: [
+ 'SELECT ${8:column1} FROM ${1:table_name} ${2:t1}',
+ '${3:LEFT} JOIN ${4:table2} ${5:t2} ON ${2:t1}.${6:column1} = ${5:t2}.${7:column2};\n$9'
+ ]
+ },
+ {
+ label: 'select-order-by',
+ prefix: 'SELECT-ORDER-BY',
+ body: [
+ 'SELECT ${2:column1}, ${3:column2} FROM ${1:table_name} ORDER BY ${4:column1} ${5:desc};\n$6'
+ ]
+ },
+ {
+ label: 'insert',
+ prefix: 'INSERT-INTO',
+ body: [
+ 'INSERT INTO ${1:table_name} (${2:column1}, ${3:column2}) VALUES (${4:value1}, ${5:value2});\n$6'
+ ]
+ },
+ {
+ label: 'insert-into-select',
+ prefix: 'INSERT-INTO-SELECT',
+ body: [
+ 'INSERT INTO ${1:table_name}',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'replace-into-table',
+ prefix: 'REPLACE-INTO-TABLE',
+ body: [
+ 'REPLACE INTO ${1:table_name} (${2:column1}, ${3:column2})',
+ 'VALUES (${4:value1}, ${5:value2});\n$6'
+ ]
+ },
+ {
+ label: 'update',
+ prefix: 'UPDATE',
+ body: [
+ 'UPDATE ${1:table_name}',
+ 'SET ${2:column1} = ${3:value1}',
+ 'WHERE ${4:column2} = ${5:value2};\n$6'
+ ]
+ },
+ {
+ label: 'delete',
+ prefix: 'DELETE',
+ body: ['DELETE FROM ${1:table_name}', 'WHERE ${2:column1} = ${3:value1};\n$4']
+ },
+ {
+ label: 'create-table',
+ prefix: 'CREATE-TABLE',
+ body: [
+ 'CREATE TABLE ${1:table_name} (',
+ '\t${2:column1} ${3:INT},',
+ '\t${4:column2} ${5:INT},',
+ '\tPRIMARY KEY (${2:column1})',
+ ')',
+ "COMMENT '${6:table_comment}';\n$7"
+ ]
+ },
+ {
+ label: 'create-table-as-select',
+ prefix: 'CREATE-TABLE-AS-SELECT',
+ body: [
+ 'CREATE TABLE ${1:table_name}',
+ 'AS',
+ 'SELECT ${2:column1}, ${3:column2}',
+ 'FROM ${4:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'create-table-partitioned-by-range',
+ prefix: 'CREATE-TABLE-PARTITIONED-BY-RANGE',
+ body: [
+ 'CREATE TABLE ${1:table_name} (',
+ '\t${2:column1} ${3:INT},',
+ '\t${4:column2} ${5:INT},',
+ '\tPRIMARY KEY (${2:column1})',
+ ')',
+ 'PARTITION BY RANGE (${2:column1}) (',
+ '\tPARTITION ${6:p0} VALUES LESS THAN ($7)',
+ ');\n$8'
+ ]
+ },
+ {
+ label: 'create-table-partitioned-by-list',
+ prefix: 'CREATE-TABLE-PARTITIONED-BY-LIST',
+ body: [
+ 'CREATE TABLE ${1:table_name} (',
+ '\t${2:column1} ${3:INT},',
+ '\t${4:column2} ${5:INT},',
+ '\tPRIMARY KEY (${2:column1})',
+ ')',
+ 'PARTITION BY LIST (${2:column1}) (',
+ '\tPARTITION ${6:p0} VALUES IN ($7)',
+ ');\n$8'
+ ]
+ },
+ {
+ label: 'create-table-partitioned-by-hash',
+ prefix: 'CREATE-TABLE-PARTITIONED-BY-HASH',
+ body: [
+ 'CREATE TABLE ${1:table_name} (',
+ '\t${2:column1} ${3:INT},',
+ '\t${4:column2} ${5:INT},',
+ '\tPRIMARY KEY (${2:column1})',
+ ')',
+ 'PARTITION BY HASH (${2:column1})',
+ 'PARTITIONS ${6:4};\n$7'
+ ]
+ },
+ {
+ label: 'create-table-partitioned-by-key',
+ prefix: 'CREATE-TABLE-PARTITIONED-BY-KEY',
+ body: [
+ 'CREATE TABLE ${1:table_name} (',
+ '\t${2:column1} ${3:INT},',
+ '\t${4:column2} ${5:INT},',
+ '\tPRIMARY KEY (${2:column1})',
+ ')',
+ 'PARTITION BY KEY (${2:column1})',
+ 'PARTITIONS ${6:4};\n$7'
+ ]
+ },
+ {
+ label: 'alter-table-add-column',
+ prefix: 'ALTER-TABLE-ADD-COLUMN',
+ body: ["ALTER TABLE ${1:table_name} ADD ${2:column_name} ${3:INT} COMMENT '${4:desc}';\n$5"]
+ },
+ {
+ label: 'alter-table-add-partition',
+ prefix: 'ALTER-TABLE-ADD-PARTITION',
+ body: ['ALTER TABLE ${1:table_name} ADD PARTITION (', '\t$2', ');\n$4']
+ },
+ {
+ label: 'alter-table-add-index',
+ prefix: 'ALTER-TABLE-ADD-INDEX',
+ body: ['ALTER TABLE ${1:table_name} ADD INDEX ${2:index_name} (${3:column_name});\n$4']
+ },
+ {
+ label: 'alter-table-add-primary-key',
+ prefix: 'ALTER-TABLE-ADD-PRIMARY-KEY',
+ body: ['ALTER TABLE ${1:table_name} ADD PRIMARY KEY (${2:column_name});\n$3']
+ },
+ {
+ label: 'alter-table-add-constraint',
+ prefix: 'ALTER-TABLE-ADD-CONSTRAINT',
+ body: [
+ 'ALTER TABLE ${1:table_name}',
+ 'ADD CONSTRAINT ${2:constraint_name}',
+ 'FOREIGN KEY (${3:foreign_column}) REFERENCES ${4:ref_table} (${5:ref_column});\n$6'
+ ]
+ }
+];
diff --git a/src/languages/pgsql/pgsql.snippet.ts b/src/languages/pgsql/pgsql.snippet.ts
new file mode 100644
index 00000000..5591f6d3
--- /dev/null
+++ b/src/languages/pgsql/pgsql.snippet.ts
@@ -0,0 +1,137 @@
+import type { CompletionSnippetOption } from 'src/monaco.contribution';
+
+export const pgsqlSnippets: CompletionSnippetOption[] = [
+ {
+ label: 'select',
+ prefix: 'SELECT',
+ body: ['SELECT ${2:column1}, ${3:column2} FROM ${1:table_name};\n$4']
+ },
+ {
+ label: 'select-join',
+ prefix: 'SELECT-JOIN',
+ body: [
+ 'SELECT ${8:column1} FROM ${1:table_name} ${2:t1}',
+ '${3:LEFT} JOIN ${4:table2} ${5:t2} ON ${2:t1}.${6:column1} = ${5:t2}.${7:column2};\n$9'
+ ]
+ },
+ {
+ label: 'select-order-by',
+ prefix: 'SELECT-ORDER-BY',
+ body: [
+ 'SELECT ${2:column1}, ${3:column2} FROM ${1:table_name} ORDER BY ${4:column1} ${5:desc};\n$6'
+ ]
+ },
+ {
+ label: 'insert',
+ prefix: 'INSERT-INTO',
+ body: [
+ 'INSERT INTO ${1:table_name} (${2:column1}, ${3:column2}) VALUES (${4:value1}, ${5:value2});\n$6'
+ ]
+ },
+ {
+ label: 'insert-into-select',
+ prefix: 'INSERT-INTO-SELECT',
+ body: [
+ 'INSERT INTO ${1:table_name}',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'update',
+ prefix: 'UPDATE',
+ body: [
+ 'UPDATE ${1:table_name}',
+ 'SET ${2:column1} = ${3:value1}',
+ 'WHERE ${4:column2} = ${5:value2};\n$6'
+ ]
+ },
+ {
+ label: 'delete',
+ prefix: 'DELETE',
+ body: ['DELETE FROM ${1:table_name}', 'WHERE ${2:column1} = ${3:value1};\n$4']
+ },
+ {
+ label: 'create-table',
+ prefix: 'CREATE-TABLE',
+ body: [
+ 'CREATE TABLE ${1:table_name} (',
+ '\t${2:column1} ${3:INT},',
+ '\t${4:column2} ${5:INT},',
+ '\tPRIMARY KEY (${2:column1})',
+ ');\n$6'
+ ]
+ },
+ {
+ label: 'create-table-as-select',
+ prefix: 'CREATE-TABLE-AS-SELECT',
+ body: [
+ 'CREATE TABLE ${1:table_name}',
+ 'AS',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'create-table-partitioned-by-range',
+ prefix: 'CREATE-TABLE-PARTITIONED-BY-RANGE',
+ body: [
+ 'CREATE TABLE ${1:table_name} (',
+ '\t${2:column1} ${3:INT},',
+ '\t${4:column2} ${5:INT}',
+ ')',
+ 'PARTITION BY RANGE (${2:column1});\n',
+ 'CREATE TABLE ${6:p0} PARTITION OF ${1:table_name}',
+ '\tFOR VALUES FROM (${7:start_value}) TO (${8:end_value});\n$9'
+ ]
+ },
+ {
+ label: 'create-table-partitioned-by-list',
+ prefix: 'CREATE-TABLE-PARTITIONED-BY-LIST',
+ body: [
+ 'CREATE TABLE ${1:table_name} (',
+ '\t${2:column1} ${3:INT},',
+ '\t${4:column2} ${5:INT}',
+ ')',
+ 'PARTITION BY LIST (${2:column1});\n',
+ 'CREATE TABLE ${6:p0} PARTITION OF ${1:table_name}',
+ '\tFOR VALUES IN (${7:range_values});\n$8'
+ ]
+ },
+ {
+ label: 'create-table-partitioned-by-hash',
+ prefix: 'CREATE-TABLE-PARTITIONED-BY-HASH',
+ body: [
+ 'CREATE TABLE ${1:table_name} (',
+ '\t${2:column1} ${3:INT},',
+ '\t${4:column2} ${5:INT}',
+ ')',
+ 'PARTITION BY HASH (${2:column1});\n',
+ 'CREATE TABLE ${6:p0} PARTITION OF ${1:table_name}',
+ '\tFOR VALUES WITH (MODULUS ${7:4}, REMAINDER ${8:0});\n$9'
+ ]
+ },
+ {
+ label: 'alter-table-add-column',
+ prefix: 'ALTER-TABLE-ADD-COLUMN',
+ body: ['ALTER TABLE ${1:table_name} ADD COLUMN ${2:column_name} ${3:INT};\n$4']
+ },
+ {
+ label: 'alter-table-add-primary-key',
+ prefix: 'ALTER-TABLE-ADD-PRIMARY-KEY',
+ body: [
+ 'ALTER TABLE ${1:table_name} ADD CONSTRAINT ${2:pk_name} PRIMARY KEY (${3:column_name});\n$4'
+ ]
+ },
+ {
+ label: 'alter-table-add-foreign-key',
+ prefix: 'ALTER-TABLE-ADD-FOREIGN-KEY',
+ body: [
+ 'ALTER TABLE ${1:table_name}',
+ 'ADD CONSTRAINT ${2:fk_name}',
+ 'FOREIGN KEY (${3:foreign_column}) REFERENCES ${4:ref_table} (${5:ref_column});\n$6'
+ ]
+ }
+];
diff --git a/src/languages/spark/spark.snippet.ts b/src/languages/spark/spark.snippet.ts
new file mode 100644
index 00000000..251e4445
--- /dev/null
+++ b/src/languages/spark/spark.snippet.ts
@@ -0,0 +1,135 @@
+import type { CompletionSnippetOption } from 'src/monaco.contribution';
+
+export const sparkSnippets: CompletionSnippetOption[] = [
+ {
+ label: 'select',
+ prefix: 'SELECT',
+ body: ['SELECT ${2:column1}, ${3:column2} FROM ${1:table_name};\n$4']
+ },
+ {
+ label: 'select-join',
+ prefix: 'SELECT-JOIN',
+ body: [
+ 'SELECT ${8:column1} FROM ${1:table_name} ${2:t1}',
+ '${3:LEFT} JOIN ${4:table2} ${5:t2} ON ${2:t1}.${6:column1} = ${5:t2}.${7:column2};\n$9'
+ ]
+ },
+ {
+ label: 'select-order-by',
+ prefix: 'SELECT-ORDER-BY',
+ body: [
+ 'SELECT ${2:column1}, ${3:column2} FROM ${1:table_name} ORDER BY ${4:column1} ${5:desc};\n$6'
+ ]
+ },
+ {
+ label: 'insert',
+ prefix: 'INSERT-INTO',
+ body: [
+ 'INSERT INTO ${1:table_name} (${2:column1}, ${3:column2}) VALUES (${4:value1}, ${5:value2});\n$6'
+ ]
+ },
+ {
+ label: 'insert-into-select',
+ prefix: 'INSERT-INTO-SELECT',
+ body: [
+ 'INSERT INTO ${1:table_name}',
+ 'SELECT ${2:column1}, ${3:column2}',
+ 'FROM ${4:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'insert-overwrite-table',
+ prefix: 'INSERT-OVERWRITE-TABLE',
+ body: [
+ 'INSERT OVERWRITE TABLE ${1:table_name}',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'update',
+ prefix: 'UPDATE',
+ body: [
+ 'UPDATE ${1:table_name}',
+ 'SET ${2:column1} = ${3:value1}',
+ 'WHERE ${4:column2} = ${5:value2};\n$6'
+ ]
+ },
+ {
+ label: 'delete',
+ prefix: 'DELETE',
+ body: ['DELETE FROM ${1:table_name}', 'WHERE ${2:column1} = ${3:value1};\n$4']
+ },
+ {
+ label: 'create-table',
+ prefix: 'CREATE-TABLE',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name} (',
+ '\t${2:column1} ${3:STRING},',
+ '\t${4:column2} ${5:STRING}',
+ ')',
+ 'USING ${6:parquet}',
+ "COMMENT '${7:table_comment}';\n$8"
+ ]
+ },
+ {
+ label: 'create-table-as-select',
+ prefix: 'CREATE-TABLE-AS-SELECT',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name}',
+ 'AS',
+ 'SELECT ${2:column1}, ${3:column2}',
+ 'FROM ${4:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'create-partition-table',
+ prefix: 'CREATE-PARTITION-TABLE',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name} (',
+ '\t${2:column1} ${3:STRING},',
+ '\t${4:column2} ${5:STRING}',
+ ')',
+ 'USING ${6:parquet}',
+ 'PARTITIONED BY (${7:part_column_name} ${8:STRING})',
+ "COMMENT '${9:table_comment}';\n$10"
+ ]
+ },
+ {
+ label: 'create-bucket-table',
+ prefix: 'CREATE-BUCKET-TABLE',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:table_name} (',
+ '\t${2:column1} ${3:STRING},',
+ '\t${4:column2} ${5:STRING}',
+ ')',
+ 'USING ${6:parquet}',
+ 'CLUSTERED BY (${7:bucket_column}) INTO ${8:1} BUCKETS',
+ "COMMENT '${9:table_comment}';\n$10"
+ ]
+ },
+ {
+ label: 'alter-table-partition',
+ prefix: 'ALTER-TABLE-PARTITION',
+ body: [
+ "ALTER TABLE ${1:table_name} ${2:ADD} PARTITION (${3:part_column}='${4:part_value}');\n$5"
+ ]
+ },
+ {
+ label: 'alter-table-properties',
+ prefix: 'ALTER-TABLE-PROPERTIES',
+ body: [
+ "ALTER TABLE ${1:table_name} SET TBLPROPERTIES ('${2:property_name}'='${3:property_value}');\n$4"
+ ]
+ },
+ {
+ label: 'alter-table-column',
+ prefix: 'ALTER-TABLE-COLUMN',
+ body: [
+ "ALTER TABLE ${1:table_name} ADD COLUMN ${2:column_name} ${3:STRING} COMMENT '${4:desc}';\n$5"
+ ]
+ }
+];
diff --git a/src/languages/trino/trino.snippet.ts b/src/languages/trino/trino.snippet.ts
new file mode 100644
index 00000000..0d82d8ad
--- /dev/null
+++ b/src/languages/trino/trino.snippet.ts
@@ -0,0 +1,112 @@
+import type { CompletionSnippetOption } from 'src/monaco.contribution';
+
+export const trinoSnippets: CompletionSnippetOption[] = [
+ {
+ label: 'select',
+ prefix: 'SELECT',
+ body: ['SELECT ${2:column1}, ${3:column2} FROM ${1:hive.schema_name.table_name};\n$4']
+ },
+ {
+ label: 'select-join',
+ prefix: 'SELECT-JOIN',
+ body: [
+ 'SELECT ${8:column1} FROM ${1:hive.schema_name.table_name1} ${2:t1}',
+ '${3:LEFT} JOIN ${4:hive.schema_name.table_name2} ${5:t2} ON ${2:t1}.${6:column1} = ${5:t2}.${7:column2};\n$9'
+ ]
+ },
+ {
+ label: 'select-order-by',
+ prefix: 'SELECT-ORDER-BY',
+ body: [
+ 'SELECT ${2:column1}, ${3:column2} FROM ${1:hive.schema_name.table_name} ORDER BY ${4:column1} ${5:desc};\n$6'
+ ]
+ },
+ {
+ label: 'insert',
+ prefix: 'INSERT-INTO',
+ body: [
+ 'INSERT INTO ${1:hive.schema_name.table_name} (${2:column1}, ${3:column2}) VALUES (${4:value1}, ${5:value2});\n$6'
+ ]
+ },
+ {
+ label: 'insert-into-select',
+ prefix: 'INSERT-INTO-SELECT',
+ body: [
+ 'INSERT INTO ${1:hive.schema_name.table_name}',
+ 'SELECT ${2:column1}, ${3:column2}',
+ 'FROM ${4:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'update',
+ prefix: 'UPDATE',
+ body: [
+ 'UPDATE ${1:hive.schema_name.table_name}',
+ 'SET ${2:column1} = ${3:value1}',
+ 'WHERE ${4:column2} = ${5:value2};\n$6'
+ ]
+ },
+ {
+ label: 'delete',
+ prefix: 'DELETE',
+ body: [
+ 'DELETE FROM ${1:hive.schema_name.table_name}',
+ 'WHERE ${2:column1} = ${3:value1};\n$4'
+ ]
+ },
+ {
+ label: 'create-catalog',
+ prefix: 'CREATE-CATALOG',
+ body: [
+ 'CREATE CATALOG ${1:catalog_name} USING ${2:hive}',
+ 'WITH (',
+ "\t${3:property_name} = '${4:property_value}'",
+ ');\n$5'
+ ]
+ },
+ {
+ label: 'create-schema',
+ prefix: 'CREATE-SCHEMA',
+ body: ["CREATE SCHEMA ${1:hive.schema_name} WITH (LOCATION = '${2:/hive/data/web}');\n$3"]
+ },
+ {
+ label: 'create-table',
+ prefix: 'CREATE-TABLE',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:hive.schema_name.table_name} (',
+ '\t${2:column1} ${3:STRING},',
+ '\t${4:column2} ${5:STRING}',
+ ')',
+ "COMMENT '${6:table_comment}'",
+ 'WITH (',
+ "\tformat = '${7:PARQUET}'",
+ ');\n$8'
+ ]
+ },
+ {
+ label: 'create-table-as-select',
+ prefix: 'CREATE-TABLE-AS-SELECT',
+ body: [
+ 'CREATE TABLE IF NOT EXISTS ${1:hive.schema_name.table_name}',
+ 'AS',
+ 'SELECT ${3:column1}, ${4:column2}',
+ 'FROM ${2:source_table}',
+ 'WHERE ${5:conditions};\n$6'
+ ]
+ },
+ {
+ label: 'alter-table-properties',
+ prefix: 'ALTER-TABLE-PROPERTIES',
+ body: [
+ "ALTER TABLE ${1:hive.schema_name.table_name} SET PROPERTIES ${2:property_name} = '${3:property_value}';\n$4"
+ ]
+ },
+ {
+ label: 'alter-table-columns',
+ prefix: 'ALTER-TABLE-COLUMNS',
+ body: [
+ "ALTER TABLE ${1:hive.schema_name.table_name} ADD COLUMN ${2:column_name} ${3:STRING} COMMENT '${4:desc}';\n$5"
+ ]
+ }
+];
diff --git a/src/main.ts b/src/main.ts
index 45036c2a..900243c0 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -4,6 +4,7 @@ export * from './languageService';
export * from './setupLanguageFeatures';
export * from './common/constants';
export * from './theme';
+export * as snippets from './snippets';
export { EntityContextType, StmtContextType } from 'dt-sql-parser';
diff --git a/src/monaco.contribution.ts b/src/monaco.contribution.ts
index c1a2cdc2..bcb2c6ea 100644
--- a/src/monaco.contribution.ts
+++ b/src/monaco.contribution.ts
@@ -32,7 +32,8 @@ export type CompletionService = (
position: Position,
completionContext: languages.CompletionContext,
suggestions: Suggestions | null,
- entities: EntityContext[] | null
+ entities: EntityContext[] | null,
+ snippets?: CompletionSnippet[]
) => Promise;
export interface CompletionOptions {
@@ -43,8 +44,20 @@ export interface CompletionOptions {
*/
completionService: CompletionService;
triggerCharacters: string[];
+ snippets: CompletionSnippetOption[];
}
+export interface CompletionSnippet {
+ prefix: string;
+ label: string;
+ body: string | string[];
+ // generated by body
+ insertText?: string;
+ description?: string;
+}
+
+export type CompletionSnippetOption = Omit;
+
export interface ModeConfiguration {
/**
* Defines whether the built-in completionItemProvider is enabled.
@@ -91,6 +104,7 @@ export interface LanguageServiceDefaults {
readonly modeConfiguration: ModeConfiguration;
preprocessCode: PreprocessCode | null;
completionService: CompletionService;
+ completionSnippets: CompletionSnippet[];
triggerCharacters: string[];
setModeConfiguration(modeConfiguration: ModeConfiguration): void;
}
@@ -127,6 +141,10 @@ export class LanguageServiceDefaultsImpl implements LanguageServiceDefaults {
return this._modeConfiguration.completionItems.completionService;
}
+ get completionSnippets(): CompletionSnippet[] {
+ return this._modeConfiguration.completionItems.snippets;
+ }
+
get triggerCharacters(): string[] {
return this._modeConfiguration.completionItems.triggerCharacters;
}
@@ -150,7 +168,9 @@ export const defaultCompletionService: CompletionService = function (
_model,
_position,
_context,
- suggestions
+ suggestions,
+ _entities,
+ snippets
) {
if (!suggestions) {
return Promise.resolve([]);
@@ -163,11 +183,23 @@ export const defaultCompletionService: CompletionService = function (
detail: 'keyword'
}));
- return Promise.resolve(keywordsCompletionItems);
+ const snippetCompletionItems: ICompletionItem[] =
+ snippets?.map((item) => ({
+ label: item.label || item.prefix,
+ kind: languages.CompletionItemKind.Snippet,
+ filterText: item.prefix,
+ insertText: item.insertText,
+ insertTextRules: languages.CompletionItemInsertTextRule.InsertAsSnippet,
+ detail: item.description || 'snippet',
+ documentation: item.insertText
+ })) || [];
+
+ return Promise.resolve([...keywordsCompletionItems, ...snippetCompletionItems]);
};
export const modeConfigurationDefault: Required = {
completionItems: {
+ snippets: [],
enable: true,
completionService: defaultCompletionService,
triggerCharacters: ['.', ' ']
diff --git a/src/setupLanguageFeatures.ts b/src/setupLanguageFeatures.ts
index 44cb3f6e..cd3fc5dd 100644
--- a/src/setupLanguageFeatures.ts
+++ b/src/setupLanguageFeatures.ts
@@ -8,6 +8,7 @@ import {
modeConfigurationDefault,
PreprocessCode
} from './monaco.contribution';
+import * as snippets from './snippets';
export interface FeatureConfiguration {
/**
@@ -88,6 +89,27 @@ export function setupLanguageFeatures(
}
}
+function getDefaultSnippets(languageId: LanguageIdEnum) {
+ switch (languageId) {
+ case LanguageIdEnum.HIVE:
+ return snippets.hiveSnippets;
+ case LanguageIdEnum.FLINK:
+ return snippets.flinkSnippets;
+ case LanguageIdEnum.IMPALA:
+ return snippets.impalaSnippets;
+ case LanguageIdEnum.MYSQL:
+ return snippets.mysqlSnippets;
+ case LanguageIdEnum.PG:
+ return snippets.pgsqlSnippets;
+ case LanguageIdEnum.SPARK:
+ return snippets.sparkSnippets;
+ case LanguageIdEnum.TRINO:
+ return snippets.trinoSnippets;
+ default:
+ return [];
+ }
+}
+
function processConfiguration(
languageId: LanguageIdEnum,
configuration: FeatureConfiguration
@@ -127,12 +149,20 @@ function processConfiguration(
? configuration.definitions
: (defaults?.modeConfiguration.definitions ?? modeConfigurationDefault.definitions);
+ const snippets =
+ typeof configuration.completionItems !== 'boolean' &&
+ Array.isArray(configuration.completionItems?.snippets)
+ ? configuration.completionItems!.snippets
+ : (defaults?.modeConfiguration.completionItems.snippets ??
+ getDefaultSnippets(languageId));
+
return {
diagnostics,
completionItems: {
enable: completionEnable,
completionService,
- triggerCharacters
+ triggerCharacters,
+ snippets
},
references,
definitions
diff --git a/src/snippets.ts b/src/snippets.ts
new file mode 100644
index 00000000..997e8f28
--- /dev/null
+++ b/src/snippets.ts
@@ -0,0 +1,7 @@
+export { hiveSnippets } from './languages/hive/hive.snippet';
+export { flinkSnippets } from './languages/flink/flink.snippet';
+export { trinoSnippets } from './languages/trino/trino.snippet';
+export { pgsqlSnippets } from './languages/pgsql/pgsql.snippet';
+export { sparkSnippets } from './languages/spark/spark.snippet';
+export { mysqlSnippets } from './languages/mysql/mysql.snippet';
+export { impalaSnippets } from './languages/impala/impala.snippet';
diff --git a/website/src/App.tsx b/website/src/App.tsx
index 062d598e..ab5cfeac 100644
--- a/website/src/App.tsx
+++ b/website/src/App.tsx
@@ -4,12 +4,26 @@ import { create, Workbench } from '@dtinsight/molecule';
import InstanceService from '@dtinsight/molecule/esm/services/instanceService';
import { ExtendsWorkbench } from './extensions/workbench';
import { version, dependencies } from '../../package.json';
-
+import { editor } from 'monaco-editor';
import './languages';
import '@dtinsight/molecule/esm/style/mo.css';
+
import './App.css';
+/**
+ * Allow code completion when typing in snippets.
+ *
+ * You can also set configurations when creating monaco-editor instance
+ */
+editor.onDidCreateEditor((editor) => {
+ editor.updateOptions({
+ suggest: {
+ snippetsPreventQuickSuggestions: false
+ }
+ });
+});
+
function App(): React.ReactElement {
const refMoInstance = useRef();
const [MyWorkbench, setMyWorkbench] = useState();
diff --git a/website/src/languages/helpers/completionService.ts b/website/src/languages/helpers/completionService.ts
index c6fde960..c060536c 100644
--- a/website/src/languages/helpers/completionService.ts
+++ b/website/src/languages/helpers/completionService.ts
@@ -16,7 +16,9 @@ export const completionService: CompletionService = async function (
model,
_position,
_completionContext,
- suggestions
+ suggestions,
+ _entities,
+ snippets
) {
if (!suggestions) {
return Promise.resolve([]);
@@ -183,5 +185,18 @@ export const completionService: CompletionService = async function (
}
}
}
- return [...syntaxCompletionItems, ...keywordsCompletionItems];
+
+ const snippetCompletionItems: ICompletionItem[] =
+ snippets?.map((item) => ({
+ label: item.label || item.prefix,
+ kind: languages.CompletionItemKind.Snippet,
+ filterText: item.prefix,
+ insertText: item.insertText,
+ insertTextRules: languages.CompletionItemInsertTextRule.InsertAsSnippet,
+ sortText: '3' + item.prefix,
+ detail: item.description !== undefined ? item.description : 'SQL模板',
+ documentation: item.insertText
+ })) || [];
+
+ return [...syntaxCompletionItems, ...keywordsCompletionItems, ...snippetCompletionItems];
};
diff --git a/website/src/languages/index.ts b/website/src/languages/index.ts
index 88c0ccbb..5f64c296 100644
--- a/website/src/languages/index.ts
+++ b/website/src/languages/index.ts
@@ -2,7 +2,6 @@ import 'monaco-sql-languages/esm/all.contributions.js';
import './languageWorker';
import './theme';
import { setupLanguageFeatures, LanguageIdEnum } from 'monaco-sql-languages/esm/main.js';
-
import { completionService } from './helpers/completionService';
/**