feat: support impala (#184)
* feat(impala): add impala sqlLexer * feat(impala): add impala grammar * feat(impala): add alter table sql * feat(impala): update alter table sql * feat(impala): add alter db sql * feat(impala): add alter view sql * feat(impala): add compute stats/comment statement and update partition_desc for alter table * feat(impala): add drop statement sql * feat(impala): add revoke and grant sql * feat(impala): add create db/function/role/view sql * feat(impala): add describe/explain/invalidata_metadata/load_data sql * feat(impala): add refresh/set/shutdown sql * feat(impala): add truncate_table/use/values sql * fix(impala): update shutdown and invaliddate_metadata * feat(impala): add show/update/upsert sql * feat(impala): add create/insert sql * feat(impala): add select and delete sql * feat(impala): add impala tokens and fix todo * feat(impala): update impalaparser and some test unit * feat(impala): add syntax suggestion * feat(impala): add syntax suggestion * feat(impala): update test unit * feat(impala): remove reference * fix(impala): add statement for sqlname and collect tableName * fix(impala): fix syntax suggestion unit test * fix(impala): update syntax suggestion and collect column * feat(impala): add collect column create
This commit is contained in:
45
test/parser/impala/suggestion/fixtures/syntaxSuggestion.sql
Normal file
45
test/parser/impala/suggestion/fixtures/syntaxSuggestion.sql
Normal file
@ -0,0 +1,45 @@
|
||||
SELECT * FROM cat.a;
|
||||
|
||||
SELECT name, calculate_age(birthdate) AS age FROM students;
|
||||
|
||||
ALTER DATABASE cat;
|
||||
|
||||
ALTER TABLE my_table CHANGE COLUMN age;
|
||||
|
||||
ALTER VIEW my_view;
|
||||
|
||||
DROP VIEW v;
|
||||
|
||||
DROP DATABASE my_db;
|
||||
|
||||
DROP TABLE my_table;
|
||||
|
||||
DROP FUNCTION my_func;
|
||||
|
||||
DELETE FROM my_table WHERE col1 LIKE 'prefix%';
|
||||
|
||||
CREATE VIEW cv;
|
||||
|
||||
CREATE TABLE cat.db ;
|
||||
|
||||
CREATE FUNCTION fnc;
|
||||
|
||||
CREATE DATABASE FIRST_DB;
|
||||
|
||||
SHOW TABLES in cat;
|
||||
|
||||
SHOW COLUMN STATS vie;
|
||||
|
||||
SHOW CREATE TABLE tb1;
|
||||
|
||||
SHOW CREATE VIEW v1;
|
||||
|
||||
SELECT id GROUP BY id;
|
||||
|
||||
SELECT id ORDER BY id;
|
||||
|
||||
CREATE TABLE census_data (last_name STRING);
|
||||
|
||||
ALTER TABLE my_table ADD COLUMN age INT COMMENT 'Updated Age';
|
||||
|
||||
CREATE TABLE kudu_no_partition_by_clause (id bigint PRIMARY KEY, s STRING, b BOOLEAN ) STORED AS KUDU;
|
@ -0,0 +1,9 @@
|
||||
ALTER ;
|
||||
|
||||
CREATE ;
|
||||
|
||||
DROP ;
|
||||
|
||||
INSERT ;
|
||||
|
||||
SHOW ;
|
349
test/parser/impala/suggestion/syntaxSuggestion.test.ts
Normal file
349
test/parser/impala/suggestion/syntaxSuggestion.test.ts
Normal file
@ -0,0 +1,349 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
||||
import ImpalaSQL from '../../../../src/parser/impala';
|
||||
|
||||
const syntaxSql = fs.readFileSync(
|
||||
path.join(__dirname, 'fixtures', 'syntaxSuggestion.sql'),
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
describe('Impala SQL Syntax Suggestion', () => {
|
||||
const parser = new ImpalaSQL();
|
||||
|
||||
test('Select table', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 1,
|
||||
column: 20,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['cat', '.', 'a']);
|
||||
});
|
||||
|
||||
test('Function call', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 3,
|
||||
column: 27,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, 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('Alter database', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 5,
|
||||
column: 19,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['cat']);
|
||||
});
|
||||
|
||||
test('Alter table', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 7,
|
||||
column: 21,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['my_table']);
|
||||
});
|
||||
|
||||
test('Alter table column', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 7,
|
||||
column: 39,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['age']);
|
||||
});
|
||||
|
||||
test('Alter view', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 9,
|
||||
column: 19,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['my_view']);
|
||||
});
|
||||
|
||||
test('Drop view', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 11,
|
||||
column: 12,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['v']);
|
||||
});
|
||||
|
||||
test('Drop database', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 13,
|
||||
column: 20,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['my_db']);
|
||||
});
|
||||
|
||||
test('Drop table', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 15,
|
||||
column: 20,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['my_table']);
|
||||
});
|
||||
|
||||
test('Drop function', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 17,
|
||||
column: 22,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['my_func']);
|
||||
});
|
||||
|
||||
test('DELETE table', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 19,
|
||||
column: 21,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['my_table']);
|
||||
});
|
||||
|
||||
test('Create view', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 21,
|
||||
column: 15,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['cv']);
|
||||
});
|
||||
|
||||
test('Create table', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 23,
|
||||
column: 20,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['cat', '.', 'db']);
|
||||
});
|
||||
|
||||
test('Create Function', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 25,
|
||||
column: 20,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['fnc']);
|
||||
});
|
||||
|
||||
test('Create database', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 27,
|
||||
column: 25,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['FIRST_DB']);
|
||||
});
|
||||
|
||||
test('Show tables in', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 29,
|
||||
column: 19,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['cat']);
|
||||
});
|
||||
|
||||
test('Show column stats table', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 31,
|
||||
column: 22,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['vie']);
|
||||
});
|
||||
|
||||
test('Show create table', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 33,
|
||||
column: 22,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['tb1']);
|
||||
});
|
||||
|
||||
test('Show create view', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 35,
|
||||
column: 20,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['v1']);
|
||||
});
|
||||
|
||||
test('Select group by', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 37,
|
||||
column: 22,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['id']);
|
||||
});
|
||||
|
||||
test('Select order by', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 39,
|
||||
column: 22,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['id']);
|
||||
});
|
||||
|
||||
test('Create Table column', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 41,
|
||||
column: 36,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['last_name']);
|
||||
});
|
||||
|
||||
test('Alert Table column', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 43,
|
||||
column: 36,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['age']);
|
||||
});
|
||||
|
||||
test('Create Table kudu', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 45,
|
||||
column: 45,
|
||||
};
|
||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
||||
const suggestion = syntaxes?.find(
|
||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
||||
);
|
||||
|
||||
expect(suggestion).not.toBeUndefined();
|
||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['id']);
|
||||
});
|
||||
});
|
109
test/parser/impala/suggestion/tokenSuggestion.test.ts
Normal file
109
test/parser/impala/suggestion/tokenSuggestion.test.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
|
||||
import impalaSQL from '../../../../src/parser/impala';
|
||||
import { commentOtherLine } from '../../../helper';
|
||||
|
||||
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
|
||||
|
||||
describe('Impala SQL Token Suggestion', () => {
|
||||
const parser = new impalaSQL();
|
||||
|
||||
test('After ALTER', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 1,
|
||||
column: 7,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual(['TABLE', 'VIEW', 'DATABASE']);
|
||||
});
|
||||
|
||||
test('After CREATE', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 3,
|
||||
column: 8,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual([
|
||||
'TABLE',
|
||||
'EXTERNAL',
|
||||
'VIEW',
|
||||
'FUNCTION',
|
||||
'AGGREGATE',
|
||||
'ROLE',
|
||||
'DATABASE',
|
||||
'SCHEMA',
|
||||
]);
|
||||
});
|
||||
|
||||
test('After DROP', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 5,
|
||||
column: 6,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual([
|
||||
'DATABASE',
|
||||
'SCHEMA',
|
||||
'TABLE',
|
||||
'VIEW',
|
||||
'STATS',
|
||||
'INCREMENTAL',
|
||||
'FUNCTION',
|
||||
'AGGREGATE',
|
||||
'ROLE',
|
||||
]);
|
||||
});
|
||||
|
||||
test('After INSERT', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 7,
|
||||
column: 8,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual(['INTO', 'OVERWRITE']);
|
||||
});
|
||||
|
||||
test('After SHOW', () => {
|
||||
const pos: CaretPosition = {
|
||||
lineNumber: 9,
|
||||
column: 6,
|
||||
};
|
||||
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||
commentOtherLine(tokenSql, pos.lineNumber),
|
||||
pos
|
||||
)?.keywords;
|
||||
|
||||
expect(suggestion).toEqual([
|
||||
'DATABASES',
|
||||
'SCHEMAS',
|
||||
'TABLES',
|
||||
'FUNCTIONS',
|
||||
'ANALYTIC',
|
||||
'AGGREGATE',
|
||||
'CREATE',
|
||||
'TABLE',
|
||||
'COLUMN',
|
||||
'PARTITIONS',
|
||||
'RANGE',
|
||||
'FILES',
|
||||
'GRANT',
|
||||
'ROLE',
|
||||
'ROLES',
|
||||
'CURRENT',
|
||||
]);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user