Feat/trino sql (#188)
* refactor: prefix trino lexer rule name with KW_ * test: add commentOtherLine function * feat: optimize trino antlr grammar to adapt to c3 * feat: trinosqlParser supports codeCompletion and spliting * test: trinoSql codeCompletion unit tests
This commit is contained in:
@ -0,0 +1,19 @@
|
||||
INSERT INTO db.tb ;
|
||||
|
||||
SELECT ids FROM db.;
|
||||
|
||||
CREATE TABLE db. VALUES;
|
||||
|
||||
DROP TABLE IF EXISTS db.a;
|
||||
|
||||
CREATE OR REPLACE VIEW db.v;
|
||||
|
||||
DROP VIEW db.v ;
|
||||
|
||||
SELECT name, calculate_age(birthday) AS age FROM students;
|
||||
|
||||
CREATE SCHEMA db ;
|
||||
|
||||
DROP SCHEMA IF EXISTS sch;
|
||||
|
||||
SHOW COLUMNS FROM tb ;
|
13
test/parser/trinosql/suggestion/fixtures/tokenSuggestion.sql
Normal file
13
test/parser/trinosql/suggestion/fixtures/tokenSuggestion.sql
Normal file
@ -0,0 +1,13 @@
|
||||
ALTER ;
|
||||
|
||||
CREATE ;
|
||||
|
||||
DEALLOCATE ;
|
||||
|
||||
DELETE ;
|
||||
|
||||
DESCRIBE ;
|
||||
|
||||
DROP ;
|
||||
|
||||
INSERT ;
|
201
test/parser/trinosql/suggestion/syntaxSuggestion.test.ts
Normal file
201
test/parser/trinosql/suggestion/syntaxSuggestion.test.ts
Normal file
@ -0,0 +1,201 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
||||
import TrinoSQL from '../../../../src/parser/trinosql';
|
||||
import { commentOtherLine } from '../../../helper';
|
||||
|
||||
const syntaxSql = fs.readFileSync(
|
||||
path.join(__dirname, 'fixtures', 'syntaxSuggestion.sql'),
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
describe('Trino SQL Syntax Suggestion', () => {
|
||||
const parser = new TrinoSQL();
|
||||
|
||||
test('Validate Syntax SQL', () => {
|
||||
expect(parser.validate(syntaxSql).length).not.toBe(0);
|
||||
expect(parser.validate(syntaxSql).length).not.toBe(0);
|
||||
expect(parser.validate(syntaxSql).length).not.toBe(0);
|
||||
});
|
||||
|
||||
test('Insert table ', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 1,
|
||||
column: 18,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||
pos
|
||||
)?.syntax;
|
||||
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.', 'tb']);
|
||||
});
|
||||
|
||||
test('Select table ', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 3,
|
||||
column: 20,
|
||||
};
|
||||
const syntaxes =
|
||||
parser.getSuggestionAtCaretPosition(commentOtherLine(syntaxSql, pos.lineNumber), pos)
|
||||
?.syntax ?? [];
|
||||
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
|
||||
expect(
|
||||
syntaxes.some((item) => item.syntaxContextType === SyntaxContextType.VIEW)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
syntaxes.some((item) => item.syntaxContextType === SyntaxContextType.FUNCTION)
|
||||
).toBeTruthy();
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.']);
|
||||
});
|
||||
|
||||
test('Create table ', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 5,
|
||||
column: 17,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||
pos
|
||||
)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.']);
|
||||
});
|
||||
|
||||
test('DROP table ', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 7,
|
||||
column: 26,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||
pos
|
||||
)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.', 'a']);
|
||||
});
|
||||
|
||||
test('Create view ', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 9,
|
||||
column: 28,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||
pos
|
||||
)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.', 'v']);
|
||||
});
|
||||
|
||||
test('Drop view ', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 11,
|
||||
column: 15,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||
pos
|
||||
)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.', 'v']);
|
||||
});
|
||||
|
||||
test('Use function', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 13,
|
||||
column: 27,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||
pos
|
||||
)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['calculate_age']);
|
||||
});
|
||||
|
||||
test('Create schema', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 15,
|
||||
column: 17,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||
pos
|
||||
)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db']);
|
||||
});
|
||||
|
||||
test('Drop schema', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 17,
|
||||
column: 26,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||
pos
|
||||
)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['sch']);
|
||||
});
|
||||
|
||||
test('Show Column From', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 19,
|
||||
column: 21,
|
||||
};
|
||||
const syntaxes =
|
||||
parser.getSuggestionAtCaretPosition(commentOtherLine(syntaxSql, pos.lineNumber), pos)
|
||||
?.syntax ?? [];
|
||||
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
expect(
|
||||
syntaxes.some((item) => item.syntaxContextType === SyntaxContextType.VIEW)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
syntaxes.some((item) => item.syntaxContextType === SyntaxContextType.FUNCTION)
|
||||
).toBeTruthy();
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['tb']);
|
||||
});
|
||||
});
|
99
test/parser/trinosql/suggestion/tokenSuggestion.test.ts
Normal file
99
test/parser/trinosql/suggestion/tokenSuggestion.test.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
|
||||
import TrinoSQL from '../../../../src/parser/trinosql';
|
||||
import { commentOtherLine } from '../../../helper';
|
||||
|
||||
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
|
||||
|
||||
describe('Trino SQL Token Suggestion', () => {
|
||||
const parser = new TrinoSQL();
|
||||
|
||||
test('After ALTER', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 1,
|
||||
column: 7,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual(['VIEW', 'MATERIALIZED', 'TABLE', 'SCHEMA']);
|
||||
});
|
||||
|
||||
test('After CREATE', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 3,
|
||||
column: 8,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual(['ROLE', 'VIEW', 'OR', 'MATERIALIZED', 'TABLE', 'SCHEMA']);
|
||||
});
|
||||
|
||||
test('After DEALLOCATE', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 5,
|
||||
column: 12,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual(['PREPARE']);
|
||||
});
|
||||
|
||||
test('After DELETE', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 7,
|
||||
column: 8,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual(['FROM']);
|
||||
});
|
||||
|
||||
test('After DESCRIBE', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 9,
|
||||
column: 10,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual(['OUTPUT', 'INPUT']);
|
||||
});
|
||||
|
||||
test('After DROP', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 11,
|
||||
column: 6,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual(['ROLE', 'VIEW', 'MATERIALIZED', 'TABLE', 'SCHEMA']);
|
||||
});
|
||||
|
||||
test('After INSERT', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 13,
|
||||
column: 8,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual(['INTO']);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user