feat: optimize suggestion (#231)
* feat: optimize the strategy of finding the right range * test: apply commentOtherLine util to all suggestion tests * test: decomment suggestion test cases * test: add suggestion test cases in multiple statements * chore: improve comments * test: update log info in test
This commit is contained in:
parent
fd50c09a86
commit
3c7c59fb70
@ -277,46 +277,67 @@ export default abstract class BasicParser<
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Split sql by statement.
|
* Split sql by statement.
|
||||||
* Try to collect candidates from the caret statement only.
|
* Try to collect candidates in as small a range as possible.
|
||||||
*/
|
*/
|
||||||
this.listen(splitListener, this._parseTree);
|
this.listen(splitListener, this._parseTree);
|
||||||
|
const statementCount = splitListener.statementsContext?.length;
|
||||||
|
const statementsContext = splitListener.statementsContext;
|
||||||
|
|
||||||
// If there are multiple statements.
|
// If there are multiple statements.
|
||||||
if (splitListener.statementsContext.length > 1) {
|
if (statementCount > 1) {
|
||||||
// find statement rule context where caretPosition is located.
|
|
||||||
const caretStatementContext = splitListener?.statementsContext.find((ctx) => {
|
|
||||||
return (
|
|
||||||
caretTokenIndex <= ctx.stop?.tokenIndex &&
|
|
||||||
caretTokenIndex >= ctx.start.tokenIndex
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (caretStatementContext) {
|
|
||||||
c3Context = caretStatementContext;
|
|
||||||
} else {
|
|
||||||
const lastStatementToken =
|
|
||||||
splitListener.statementsContext[splitListener?.statementsContext.length - 1]
|
|
||||||
.start;
|
|
||||||
/**
|
/**
|
||||||
* If caretStatementContext is not found and it follows all statements.
|
* Find a minimum valid range, reparse the fragment, and provide a new parse tree to C3.
|
||||||
* Reparses part of the input following the penultimate statement.
|
* The boundaries of this range must be statements with no syntax errors.
|
||||||
* And c3 will collect candidates in the new parseTreeContext.
|
* This can ensure the stable performance of the C3.
|
||||||
*/
|
*/
|
||||||
if (caretTokenIndex > lastStatementToken?.tokenIndex) {
|
let startStatement: ParserRuleContext;
|
||||||
|
let stopStatement: ParserRuleContext;
|
||||||
|
|
||||||
|
for (let index = 0; index < statementCount; index++) {
|
||||||
|
const ctx = statementsContext[index];
|
||||||
|
const isCurrentCtxValid = !ctx.exception;
|
||||||
|
if (!isCurrentCtxValid) continue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save offset of the tokenIndex in the partInput
|
* Ensure that the statementContext before the left boundary
|
||||||
|
* and the last statementContext on the right boundary are qualified SQL statements.
|
||||||
|
*/
|
||||||
|
const isPrevCtxValid = index === 0 || !statementsContext[index - 1]?.exception;
|
||||||
|
const isNextCtxValid =
|
||||||
|
index === statementCount - 1 || !statementsContext[index + 1]?.exception;
|
||||||
|
|
||||||
|
if (ctx.stop.tokenIndex < caretTokenIndex && isPrevCtxValid) {
|
||||||
|
startStatement = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stopStatement && ctx.start.tokenIndex > caretTokenIndex && isNextCtxValid) {
|
||||||
|
stopStatement = ctx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A boundary consisting of the index of the input.
|
||||||
|
const startIndex = startStatement?.start?.startIndex ?? 0;
|
||||||
|
const stopIndex = stopStatement?.stop?.stopIndex ?? input.length - 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save offset of the tokenIndex in the range of input
|
||||||
* compared to the tokenIndex in the whole input
|
* compared to the tokenIndex in the whole input
|
||||||
*/
|
*/
|
||||||
tokenIndexOffset = lastStatementToken?.tokenIndex;
|
tokenIndexOffset = startStatement?.start?.tokenIndex ?? 0;
|
||||||
// Correct caretTokenIndex
|
|
||||||
caretTokenIndex = caretTokenIndex - tokenIndexOffset;
|
caretTokenIndex = caretTokenIndex - tokenIndexOffset;
|
||||||
|
|
||||||
const inputSlice = input.slice(lastStatementToken.startIndex);
|
/**
|
||||||
|
* Reparse the input fragment,
|
||||||
|
* and c3 will collect candidates in the newly generated parseTree.
|
||||||
|
*/
|
||||||
|
const inputSlice = input.slice(startIndex, stopIndex);
|
||||||
|
|
||||||
const lexer = this.createLexer(inputSlice);
|
const lexer = this.createLexer(inputSlice);
|
||||||
lexer.removeErrorListeners();
|
lexer.removeErrorListeners();
|
||||||
|
|
||||||
const tokenStream = new CommonTokenStream(lexer);
|
const tokenStream = new CommonTokenStream(lexer);
|
||||||
tokenStream.fill();
|
tokenStream.fill();
|
||||||
|
|
||||||
const parser = this.createParserFromTokenStream(tokenStream);
|
const parser = this.createParserFromTokenStream(tokenStream);
|
||||||
parser.removeErrorListeners();
|
parser.removeErrorListeners();
|
||||||
parser.buildParseTree = true;
|
parser.buildParseTree = true;
|
||||||
@ -325,8 +346,6 @@ export default abstract class BasicParser<
|
|||||||
sqlParserIns = parser;
|
sqlParserIns = parser;
|
||||||
c3Context = parser.program();
|
c3Context = parser.program();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const core = new CodeCompletionCore(sqlParserIns);
|
const core = new CodeCompletionCore(sqlParserIns);
|
||||||
core.preferredRules = this.preferredRules;
|
core.preferredRules = this.preferredRules;
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
CREATE TABLE orders (
|
|
||||||
order_uid BIGINT,
|
|
||||||
product_id BIGINT,
|
|
||||||
price DECIMAL(32, 2),
|
|
||||||
order_time TIMESTAMP(3)
|
|
||||||
) WITH (
|
|
||||||
'connector' = 'datagen'
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE orders (
|
|
||||||
order_uid BIGINT,
|
|
||||||
product_id BIGINT,
|
|
||||||
price DECIMAL(32, 2),
|
|
||||||
order_time TIMESTAMP(3)
|
|
||||||
) WITH (
|
|
||||||
'connector' = 'datagen'
|
|
||||||
);
|
|
||||||
|
|
||||||
use cat1.
|
|
@ -0,0 +1,31 @@
|
|||||||
|
SELECT * FROM -- unfinished
|
||||||
|
|
||||||
|
CREATE TEMPORARY VIEW IF NOT EXISTS v AS SELECT col1 FROM tbl;
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE client_errors (
|
||||||
|
log_time TIMESTAMP(3),
|
||||||
|
request_line STRING,
|
||||||
|
status_code STRING,
|
||||||
|
size INT
|
||||||
|
) WITH (
|
||||||
|
'connector' = 'stream-x'
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER VIEW v1 RENAME TO v2;
|
||||||
|
|
||||||
|
CREATE TABLE db. ; -- unfinished
|
||||||
|
|
||||||
|
LOAD MODULE CORE;
|
||||||
|
|
||||||
|
REMOVE JAR '<path_to_filename>.jar'
|
||||||
|
|
||||||
|
INSERT INTO VALUES (100, 99.9 / 10, 'abc', true, now ()); -- unfinished
|
||||||
|
|
||||||
|
CREATE DATABASE IF NOT EXISTS dataApi COMMENT 'test create database' WITH ('key1' = 'value1', 'key2.a' = 'value2.a');
|
||||||
|
|
||||||
|
DROP DATABASE IF EXISTS Orders RESTRICT;
|
||||||
|
|
||||||
|
INSERT INTO country_page_view
|
||||||
|
SELECT `user`,
|
||||||
|
cnt
|
||||||
|
FROM db. ; -- unfinished
|
69
test/parser/flinksql/suggestion/multipleStatement.test.ts
Normal file
69
test/parser/flinksql/suggestion/multipleStatement.test.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
||||||
|
import FlinkSQL from '../../../../src/parser/flinksql';
|
||||||
|
|
||||||
|
const syntaxSql = fs.readFileSync(
|
||||||
|
path.join(__dirname, 'fixtures', 'multipleStatement.sql'),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('FlinkSQL Multiple Statements Syntax Suggestion', () => {
|
||||||
|
const parser = new FlinkSQL();
|
||||||
|
|
||||||
|
test('Select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 1,
|
||||||
|
column: 15,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Create table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 16,
|
||||||
|
column: 17,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 22,
|
||||||
|
column: 13,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 31,
|
||||||
|
column: 9,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
});
|
@ -8,7 +8,6 @@ const syntaxSql = fs.readFileSync(
|
|||||||
path.join(__dirname, 'fixtures', 'syntaxSuggestion.sql'),
|
path.join(__dirname, 'fixtures', 'syntaxSuggestion.sql'),
|
||||||
'utf-8'
|
'utf-8'
|
||||||
);
|
);
|
||||||
const multipleSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'multipleSql.sql'), 'utf-8');
|
|
||||||
|
|
||||||
describe('Flink SQL Syntax Suggestion', () => {
|
describe('Flink SQL Syntax Suggestion', () => {
|
||||||
const parser = new FlinkSQL();
|
const parser = new FlinkSQL();
|
||||||
@ -19,20 +18,6 @@ describe('Flink SQL Syntax Suggestion', () => {
|
|||||||
expect(parser.validate(syntaxSql).length).not.toBe(0);
|
expect(parser.validate(syntaxSql).length).not.toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Multiple SQL use database', () => {
|
|
||||||
const pos: CaretPosition = {
|
|
||||||
lineNumber: 19,
|
|
||||||
column: 10,
|
|
||||||
};
|
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(multipleSql, pos)?.syntax;
|
|
||||||
const suggestion = syntaxes?.find(
|
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(suggestion).not.toBeUndefined();
|
|
||||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['cat1', '.']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Drop catalog', () => {
|
test('Drop catalog', () => {
|
||||||
const pos: CaretPosition = {
|
const pos: CaretPosition = {
|
||||||
lineNumber: 1,
|
lineNumber: 1,
|
||||||
|
@ -2,6 +2,7 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
|
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
|
||||||
import FlinkSQL from '../../../../src/parser/flinksql';
|
import FlinkSQL from '../../../../src/parser/flinksql';
|
||||||
|
import { commentOtherLine } from '../../../helper';
|
||||||
|
|
||||||
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
|
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
|
||||||
|
|
||||||
@ -13,7 +14,10 @@ describe('Flink SQL Token Suggestion', () => {
|
|||||||
lineNumber: 3,
|
lineNumber: 3,
|
||||||
column: 5,
|
column: 5,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual(['MODULES', 'CATALOG']);
|
expect(suggestion).toEqual(['MODULES', 'CATALOG']);
|
||||||
});
|
});
|
||||||
@ -23,7 +27,10 @@ describe('Flink SQL Token Suggestion', () => {
|
|||||||
lineNumber: 5,
|
lineNumber: 5,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'CATALOG',
|
'CATALOG',
|
||||||
@ -40,7 +47,10 @@ describe('Flink SQL Token Suggestion', () => {
|
|||||||
lineNumber: 7,
|
lineNumber: 7,
|
||||||
column: 6,
|
column: 6,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'MODULES',
|
'MODULES',
|
||||||
|
21
test/parser/hive/suggestion/fixtures/multipleStatement.sql
Normal file
21
test/parser/hive/suggestion/fixtures/multipleStatement.sql
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
SELECT * FROM -- unfinished
|
||||||
|
|
||||||
|
CREATE VIEW mydb.bro_view AS SELECT * FROM mydb.sale_tbl;
|
||||||
|
|
||||||
|
CREATE TEMPORARY EXTERNAL TABLE list_bucket_multiple (col1 STRING, col2 INT, col3 STRING);
|
||||||
|
|
||||||
|
ALTER VIEW myview1 SET TBLPROPERTIES ('author'='hayden','date'='2023-09-04')
|
||||||
|
|
||||||
|
CREATE TABLE db. ; -- unfinished
|
||||||
|
|
||||||
|
DROP CONNECTOR connector1;
|
||||||
|
|
||||||
|
SET ROLE `admin`;
|
||||||
|
|
||||||
|
INSERT INTO VALUES (100, 99.9 / 10, 'abc', true, now ()); -- unfinished
|
||||||
|
|
||||||
|
ALTER TABLE tbl1 RENAME TO tbl2;
|
||||||
|
|
||||||
|
ALTER SCHEMA database_name SET OWNER USER `admin`;
|
||||||
|
|
||||||
|
INSERT OVERWRITE LOCAL DIRECTORY '/path/to/output' SELECT col1, col2 FROM ; -- unfinished
|
69
test/parser/hive/suggestion/multipleStatement.test.ts
Normal file
69
test/parser/hive/suggestion/multipleStatement.test.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
||||||
|
import HiveSQL from '../../../../src/parser/hive';
|
||||||
|
|
||||||
|
const syntaxSql = fs.readFileSync(
|
||||||
|
path.join(__dirname, 'fixtures', 'multipleStatement.sql'),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('HiveSQL Multiple Statements Syntax Suggestion', () => {
|
||||||
|
const parser = new HiveSQL();
|
||||||
|
|
||||||
|
test('Select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 1,
|
||||||
|
column: 15,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Create table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 9,
|
||||||
|
column: 17,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 15,
|
||||||
|
column: 13,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 21,
|
||||||
|
column: 75,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
});
|
@ -2,6 +2,7 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
|
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
|
||||||
import HiveSQL from '../../../../src/parser/hive';
|
import HiveSQL from '../../../../src/parser/hive';
|
||||||
|
import { commentOtherLine } from '../../../helper';
|
||||||
|
|
||||||
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
|
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
|
||||||
|
|
||||||
@ -13,7 +14,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 1,
|
lineNumber: 1,
|
||||||
column: 7,
|
column: 7,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'APPLICATION',
|
'APPLICATION',
|
||||||
'GROUP',
|
'GROUP',
|
||||||
@ -37,7 +41,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 3,
|
lineNumber: 3,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'CONNECTOR',
|
'CONNECTOR',
|
||||||
'APPLICATION',
|
'APPLICATION',
|
||||||
@ -69,7 +76,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 5,
|
lineNumber: 5,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual(['FROM']);
|
expect(suggestion).toEqual(['FROM']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -78,7 +88,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 7,
|
lineNumber: 7,
|
||||||
column: 10,
|
column: 10,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'EXTENDED',
|
'EXTENDED',
|
||||||
'FORMATTED',
|
'FORMATTED',
|
||||||
@ -94,7 +107,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 9,
|
lineNumber: 9,
|
||||||
column: 6,
|
column: 6,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'CONNECTOR',
|
'CONNECTOR',
|
||||||
'APPLICATION',
|
'APPLICATION',
|
||||||
@ -121,7 +137,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 11,
|
lineNumber: 11,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual(['TABLE']);
|
expect(suggestion).toEqual(['TABLE']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -130,7 +149,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 13,
|
lineNumber: 13,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual(['FROM', 'TABLE', 'EXTERNAL']);
|
expect(suggestion).toEqual(['FROM', 'TABLE', 'EXTERNAL']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -139,7 +161,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 15,
|
lineNumber: 15,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual(['INTO', 'OVERWRITE']);
|
expect(suggestion).toEqual(['INTO', 'OVERWRITE']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -148,7 +173,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 17,
|
lineNumber: 17,
|
||||||
column: 6,
|
column: 6,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual(['DATA']);
|
expect(suggestion).toEqual(['DATA']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -157,7 +185,10 @@ describe('Hive SQL Token Suggestion', () => {
|
|||||||
lineNumber: 19,
|
lineNumber: 19,
|
||||||
column: 6,
|
column: 6,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'CURRENT',
|
'CURRENT',
|
||||||
'ROLES',
|
'ROLES',
|
||||||
|
21
test/parser/impala/suggestion/fixtures/multipleStatement.sql
Normal file
21
test/parser/impala/suggestion/fixtures/multipleStatement.sql
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
SELECT * FROM -- unfinished
|
||||||
|
|
||||||
|
CREATE VIEW my_view AS SELECT * FROM my_table;
|
||||||
|
|
||||||
|
create table census (name string, census_year int) partitioned by (year int);
|
||||||
|
|
||||||
|
ALTER VIEW v1 RENAME TO db2.v2;
|
||||||
|
|
||||||
|
CREATE TABLE db. ; -- unfinished
|
||||||
|
|
||||||
|
INSERT INTO target_table (col1, col2, col3) PARTITION (year = 2016, month IN (10, 11, 12)) SELECT * FROM dual;
|
||||||
|
|
||||||
|
EXPLAIN INSERT INTO t1 VALUES (1, 'one'), (2, 'two'), (3, 'three');
|
||||||
|
|
||||||
|
INSERT INTO VALUES (100, 99.9 / 10, 'abc', true, now ()); -- unfinished
|
||||||
|
|
||||||
|
ALTER TABLE my_table REPLACE COLUMNS (age INT COMMENT 'Updated Age');
|
||||||
|
|
||||||
|
ALTER DATABASE my_db SET OWNER USER 'impala';
|
||||||
|
|
||||||
|
INSERT INTO t2 (c1) SELECT c1 FROM t1.; -- unfinished
|
69
test/parser/impala/suggestion/multipleStatement.test.ts
Normal file
69
test/parser/impala/suggestion/multipleStatement.test.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
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', 'multipleStatement.sql'),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('ImpalaSQL Multiple Statements Syntax Suggestion', () => {
|
||||||
|
const parser = new ImpalaSQL();
|
||||||
|
|
||||||
|
test('Select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 1,
|
||||||
|
column: 15,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Create table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 9,
|
||||||
|
column: 17,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 15,
|
||||||
|
column: 13,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 21,
|
||||||
|
column: 39,
|
||||||
|
};
|
||||||
|
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(['t1', '.']);
|
||||||
|
});
|
||||||
|
});
|
@ -2,6 +2,7 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
||||||
import ImpalaSQL from '../../../../src/parser/impala';
|
import ImpalaSQL from '../../../../src/parser/impala';
|
||||||
|
import { commentOtherLine } from '../../../helper';
|
||||||
|
|
||||||
const syntaxSql = fs.readFileSync(
|
const syntaxSql = fs.readFileSync(
|
||||||
path.join(__dirname, 'fixtures', 'syntaxSuggestion.sql'),
|
path.join(__dirname, 'fixtures', 'syntaxSuggestion.sql'),
|
||||||
@ -16,7 +17,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 1,
|
lineNumber: 1,
|
||||||
column: 20,
|
column: 20,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||||
);
|
);
|
||||||
@ -30,7 +34,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 3,
|
lineNumber: 3,
|
||||||
column: 27,
|
column: 27,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
|
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
|
||||||
);
|
);
|
||||||
@ -44,7 +51,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 5,
|
lineNumber: 5,
|
||||||
column: 19,
|
column: 19,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
|
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
|
||||||
);
|
);
|
||||||
@ -58,7 +68,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 7,
|
lineNumber: 7,
|
||||||
column: 21,
|
column: 21,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||||
);
|
);
|
||||||
@ -72,7 +85,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 7,
|
lineNumber: 7,
|
||||||
column: 39,
|
column: 39,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
||||||
);
|
);
|
||||||
@ -86,7 +102,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 9,
|
lineNumber: 9,
|
||||||
column: 19,
|
column: 19,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
||||||
);
|
);
|
||||||
@ -100,7 +119,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 11,
|
lineNumber: 11,
|
||||||
column: 12,
|
column: 12,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
||||||
);
|
);
|
||||||
@ -114,7 +136,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 13,
|
lineNumber: 13,
|
||||||
column: 20,
|
column: 20,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
|
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
|
||||||
);
|
);
|
||||||
@ -128,7 +153,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 15,
|
lineNumber: 15,
|
||||||
column: 20,
|
column: 20,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||||
);
|
);
|
||||||
@ -142,7 +170,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 17,
|
lineNumber: 17,
|
||||||
column: 22,
|
column: 22,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
|
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
|
||||||
);
|
);
|
||||||
@ -156,7 +187,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 19,
|
lineNumber: 19,
|
||||||
column: 21,
|
column: 21,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||||
);
|
);
|
||||||
@ -170,7 +204,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 21,
|
lineNumber: 21,
|
||||||
column: 15,
|
column: 15,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW_CREATE
|
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW_CREATE
|
||||||
);
|
);
|
||||||
@ -184,7 +221,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 23,
|
lineNumber: 23,
|
||||||
column: 20,
|
column: 20,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE_CREATE
|
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE_CREATE
|
||||||
);
|
);
|
||||||
@ -198,7 +238,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 25,
|
lineNumber: 25,
|
||||||
column: 20,
|
column: 20,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION_CREATE
|
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION_CREATE
|
||||||
);
|
);
|
||||||
@ -212,7 +255,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 27,
|
lineNumber: 27,
|
||||||
column: 25,
|
column: 25,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE_CREATE
|
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE_CREATE
|
||||||
);
|
);
|
||||||
@ -226,7 +272,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 29,
|
lineNumber: 29,
|
||||||
column: 19,
|
column: 19,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||||
);
|
);
|
||||||
@ -240,7 +289,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 31,
|
lineNumber: 31,
|
||||||
column: 22,
|
column: 22,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||||
);
|
);
|
||||||
@ -254,7 +306,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 33,
|
lineNumber: 33,
|
||||||
column: 22,
|
column: 22,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
|
||||||
);
|
);
|
||||||
@ -268,7 +323,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 35,
|
lineNumber: 35,
|
||||||
column: 20,
|
column: 20,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
|
||||||
);
|
);
|
||||||
@ -282,7 +340,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 37,
|
lineNumber: 37,
|
||||||
column: 22,
|
column: 22,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
||||||
);
|
);
|
||||||
@ -296,7 +357,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 39,
|
lineNumber: 39,
|
||||||
column: 22,
|
column: 22,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
||||||
);
|
);
|
||||||
@ -310,7 +374,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 41,
|
lineNumber: 41,
|
||||||
column: 36,
|
column: 36,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
||||||
);
|
);
|
||||||
@ -324,7 +391,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 43,
|
lineNumber: 43,
|
||||||
column: 36,
|
column: 36,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
||||||
);
|
);
|
||||||
@ -338,7 +408,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 45,
|
lineNumber: 45,
|
||||||
column: 45,
|
column: 45,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
||||||
);
|
);
|
||||||
@ -352,7 +425,10 @@ describe('Impala SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 47,
|
lineNumber: 47,
|
||||||
column: 49,
|
column: 49,
|
||||||
};
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
|
||||||
);
|
);
|
||||||
|
@ -14,7 +14,10 @@ describe('Impala SQL Token Suggestion', () => {
|
|||||||
lineNumber: 1,
|
lineNumber: 1,
|
||||||
column: 7,
|
column: 7,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual(['TABLE', 'VIEW', 'DATABASE']);
|
expect(suggestion).toEqual(['TABLE', 'VIEW', 'DATABASE']);
|
||||||
});
|
});
|
||||||
|
21
test/parser/mysql/suggestion/fixtures/multipleStatement.sql
Normal file
21
test/parser/mysql/suggestion/fixtures/multipleStatement.sql
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
SELECT * FROM -- unfinished
|
||||||
|
|
||||||
|
CREATE SCHEMA IF NOT EXISTS db_name DEFAULT ENCRYPTION 'Y';
|
||||||
|
|
||||||
|
CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (a), KEY(b)) ENGINE=InnoDB SELECT b,c FROM test2;
|
||||||
|
|
||||||
|
ALTER LOGFILE GROUP lg_3 ADD UNDOFILE 'undo_10.dat' INITIAL_SIZE=32M ENGINE=NDBCLUSTER;
|
||||||
|
|
||||||
|
CREATE TABLE db. LIKE orig_tbl; -- unfinished
|
||||||
|
|
||||||
|
INSERT HIGH_PRIORITY IGNORE INTO tbl_temp2 (fld_id) VALUES ROW(1,-2,3), ROW(5,7,9), ROW(4,6,8);
|
||||||
|
|
||||||
|
CHANGE REPLICATION FILTER REPLICATE_DO_DB = (db3, db4);
|
||||||
|
|
||||||
|
INSERT INTO VALUES (1,2,3),(4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b); -- unfinished
|
||||||
|
|
||||||
|
ALTER FUNCTION function_name LANGUAGE SQL;
|
||||||
|
|
||||||
|
ALTER FUNCTION function_name NOT DETERMINISTIC;
|
||||||
|
|
||||||
|
INSERT LOW_PRIORITY IGNORE INTO tbl_temp2 (fld_id) SELECT tbl_temp1.fld_order_id FROM -- unfinished
|
69
test/parser/mysql/suggestion/multipleStatement.test.ts
Normal file
69
test/parser/mysql/suggestion/multipleStatement.test.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
||||||
|
import MySQL from '../../../../src/parser/mysql';
|
||||||
|
|
||||||
|
const syntaxSql = fs.readFileSync(
|
||||||
|
path.join(__dirname, 'fixtures', 'multipleStatement.sql'),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('MySQL Multiple Statements Syntax Suggestion', () => {
|
||||||
|
const parser = new MySQL();
|
||||||
|
|
||||||
|
test('Select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 1,
|
||||||
|
column: 15,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Create table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 9,
|
||||||
|
column: 17,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 15,
|
||||||
|
column: 13,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 21,
|
||||||
|
column: 87,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
});
|
@ -50,23 +50,22 @@ describe('MySQL Syntax Suggestion', () => {
|
|||||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.']);
|
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.']);
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: fix bug of basic parser and decomment following test
|
test('Create table ', () => {
|
||||||
// test('Create table ', () => {
|
const pos: CaretPosition = {
|
||||||
// const pos: CaretPosition = {
|
lineNumber: 5,
|
||||||
// lineNumber: 5,
|
column: 17,
|
||||||
// column: 17,
|
};
|
||||||
// };
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
// const syntaxes = parser.getSuggestionAtCaretPosition(
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
// commentOtherLine(syntaxSql, pos.lineNumber),
|
pos
|
||||||
// pos
|
)?.syntax;
|
||||||
// )?.syntax;
|
const suggestion = syntaxes?.find(
|
||||||
// const suggestion = syntaxes?.find(
|
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE_CREATE
|
||||||
// (syn) => syn.syntaxContextType === SyntaxContextType.TABLE_CREATE
|
);
|
||||||
// );
|
|
||||||
|
|
||||||
// expect(suggestion).not.toBeUndefined();
|
expect(suggestion).not.toBeUndefined();
|
||||||
// expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.']);
|
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.']);
|
||||||
// });
|
});
|
||||||
|
|
||||||
test('DROP table ', () => {
|
test('DROP table ', () => {
|
||||||
const pos: CaretPosition = {
|
const pos: CaretPosition = {
|
||||||
|
@ -42,7 +42,7 @@ describe('MySQL Database Administration Syntax Tests', () => {
|
|||||||
it(sql, () => {
|
it(sql, () => {
|
||||||
const result = parser.validate(sql);
|
const result = parser.validate(sql);
|
||||||
if (result.length) {
|
if (result.length) {
|
||||||
console.log(result, `\n请检查 sql: ${sql}`);
|
console.log(result, `\nPlease check sql: ${sql}`);
|
||||||
}
|
}
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -49,7 +49,7 @@ describe('MySQL DDL Syntax Tests', () => {
|
|||||||
it(sql, () => {
|
it(sql, () => {
|
||||||
const result = parser.validate(sql);
|
const result = parser.validate(sql);
|
||||||
if (result.length) {
|
if (result.length) {
|
||||||
console.log(result, `\n请检查 sql: ${sql}`);
|
console.log(result, `\nPlease check sql: ${sql}`);
|
||||||
}
|
}
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -33,7 +33,7 @@ describe('MySQL DML Syntax Tests', () => {
|
|||||||
it(sql, () => {
|
it(sql, () => {
|
||||||
const result = parser.validate(sql);
|
const result = parser.validate(sql);
|
||||||
if (result.length) {
|
if (result.length) {
|
||||||
console.log(result, `\n请检查 sql: ${sql}`);
|
console.log(result, `\nPlease check sql: ${sql}`);
|
||||||
}
|
}
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,7 @@ describe('MySQL Transactional and Locking, Replication, Prepared Compound and Ut
|
|||||||
it(sql, () => {
|
it(sql, () => {
|
||||||
const result = parser.validate(sql);
|
const result = parser.validate(sql);
|
||||||
if (result.length) {
|
if (result.length) {
|
||||||
console.log(result, `\n请检查 sql: ${sql}`);
|
console.log(result, `\nPlease check sql: ${sql}`);
|
||||||
}
|
}
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
21
test/parser/pgsql/suggestion/fixtures/multipleStatement.sql
Normal file
21
test/parser/pgsql/suggestion/fixtures/multipleStatement.sql
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
CREATE TABLE VALUES -- unfinished
|
||||||
|
|
||||||
|
CREATE UNLOGGED TABLE table1 (col1 int) INHERITS (table_parent) WITHOUT OIDS ON COMMIT DROP;
|
||||||
|
|
||||||
|
CREATE SCHEMA schemaname AUTHORIZATION username;
|
||||||
|
|
||||||
|
ALTER TABLE products ADD FOREIGN KEY (product_group_id) REFERENCES product_groups;
|
||||||
|
|
||||||
|
SELECT * FROM db. ; -- unfinished
|
||||||
|
|
||||||
|
INSERT INTO weather (date, city, temp_hi, temp_lo) VALUES ('1994-11-29', 'Hayward', 54, 37);
|
||||||
|
|
||||||
|
ANALYZE VERBOSE table_name ( column_name, column_name2);
|
||||||
|
|
||||||
|
INSERT INTO weather (date, city, temp_hi, temp_lo) VALUES ('1994-11-29', 'Hayward', 54, 37); -- unfinished
|
||||||
|
|
||||||
|
DROP TABLE products CASCADE;
|
||||||
|
|
||||||
|
DROP AGGREGATE aggname2(int);
|
||||||
|
|
||||||
|
INSERT INTO products (product_no, name, price) SELECT * FROM db. ; -- unfinished
|
69
test/parser/pgsql/suggestion/multipleStatement.test.ts
Normal file
69
test/parser/pgsql/suggestion/multipleStatement.test.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
||||||
|
import PgSQL from '../../../../src/parser/pgsql';
|
||||||
|
|
||||||
|
const syntaxSql = fs.readFileSync(
|
||||||
|
path.join(__dirname, 'fixtures', 'multipleStatement.sql'),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('PgSQL Multiple Statements Syntax Suggestion', () => {
|
||||||
|
const parser = new PgSQL();
|
||||||
|
|
||||||
|
test('Create table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 1,
|
||||||
|
column: 14,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Select from table', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 9,
|
||||||
|
column: 18,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 15,
|
||||||
|
column: 13,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 21,
|
||||||
|
column: 65,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
});
|
@ -638,29 +638,28 @@ describe('Postgre SQL Syntax Suggestion', () => {
|
|||||||
lineNumber: 59,
|
lineNumber: 59,
|
||||||
column: 48,
|
column: 48,
|
||||||
};
|
};
|
||||||
// const pos1: CaretPosition = {
|
const pos1: CaretPosition = {
|
||||||
// lineNumber: 59,
|
lineNumber: 59,
|
||||||
// column: 93,
|
column: 93,
|
||||||
// };
|
};
|
||||||
const syntaxes = parser.getSuggestionAtCaretPosition(
|
const syntaxes = parser.getSuggestionAtCaretPosition(
|
||||||
commentOtherLine(syntaxSql, pos.lineNumber),
|
commentOtherLine(syntaxSql, pos.lineNumber),
|
||||||
pos
|
pos
|
||||||
)?.syntax;
|
)?.syntax;
|
||||||
// const syntaxes1 = parser.getSuggestionAtCaretPosition(
|
const syntaxes1 = parser.getSuggestionAtCaretPosition(
|
||||||
// commentOtherLine(syntaxSql, pos1.lineNumber),
|
commentOtherLine(syntaxSql, pos1.lineNumber),
|
||||||
// pos1
|
pos1
|
||||||
// )?.syntax;
|
)?.syntax;
|
||||||
const suggestion = syntaxes?.find(
|
const suggestion = syntaxes?.find(
|
||||||
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
|
||||||
);
|
);
|
||||||
// const suggestion1 = syntaxes1?.find(
|
const suggestion1 = syntaxes1?.find(
|
||||||
// (syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
|
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
|
||||||
// );
|
);
|
||||||
expect(suggestion).not.toBeUndefined();
|
expect(suggestion).not.toBeUndefined();
|
||||||
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['column_name']);
|
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['column_name']);
|
||||||
// TODO: fix bug of basic parser and decomment following case
|
expect(suggestion1).not.toBeUndefined();
|
||||||
// expect(suggestion1).not.toBeUndefined();
|
expect(suggestion1?.wordRanges.map((token) => token.text)).toEqual(['function_name']);
|
||||||
// expect(suggestion1?.wordRanges.map((token) => token.text)).toEqual(['function_name']);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GRANT With Column', () => {
|
test('GRANT With Column', () => {
|
||||||
|
21
test/parser/spark/suggestion/fixtures/multipleStatement.sql
Normal file
21
test/parser/spark/suggestion/fixtures/multipleStatement.sql
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
CREATE TABLE VALUES -- unfinished
|
||||||
|
|
||||||
|
CREATE TABLE student (id INT, name STRING, age INT) STORED AS ORC;
|
||||||
|
|
||||||
|
CREATE SCHEMA customer_db WITH DBPROPERTIES (ID=001, Name='John');
|
||||||
|
|
||||||
|
ALTER TABLE StudentInfo ADD COLUMNS (LastName string, DOB timestamp);
|
||||||
|
|
||||||
|
SELECT * FROM db. ; -- unfinished
|
||||||
|
|
||||||
|
INSERT INTO weather (date, city, temp_hi, temp_lo) VALUES ('1994-11-29', 'Hayward', 54, 37);
|
||||||
|
|
||||||
|
DESC EXTENDED students name;
|
||||||
|
|
||||||
|
INSERT INTO weather (date, city, temp_hi, temp_lo) VALUES ('1994-11-29', 'Hayward', 54, 37); -- unfinished
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS employable;
|
||||||
|
|
||||||
|
DROP TEMPORARY FUNCTION test_avg;
|
||||||
|
|
||||||
|
INSERT INTO products (product_no, name, price) SELECT * FROM db. ; -- unfinished
|
69
test/parser/spark/suggestion/multipleStatement.test.ts
Normal file
69
test/parser/spark/suggestion/multipleStatement.test.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
||||||
|
import SparkSQL from '../../../../src/parser/spark';
|
||||||
|
|
||||||
|
const syntaxSql = fs.readFileSync(
|
||||||
|
path.join(__dirname, 'fixtures', 'multipleStatement.sql'),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('SparkSQL Multiple Statements Syntax Suggestion', () => {
|
||||||
|
const parser = new SparkSQL();
|
||||||
|
|
||||||
|
test('Create table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 1,
|
||||||
|
column: 14,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Select from table', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 9,
|
||||||
|
column: 18,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 15,
|
||||||
|
column: 13,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 21,
|
||||||
|
column: 65,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
});
|
@ -2,6 +2,7 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
|
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
|
||||||
import SparkSQL from '../../../../src/parser/spark';
|
import SparkSQL from '../../../../src/parser/spark';
|
||||||
|
import { commentOtherLine } from '../../../helper';
|
||||||
|
|
||||||
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
|
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
|
||||||
|
|
||||||
@ -13,7 +14,10 @@ describe('Spark SQL Token Suggestion', () => {
|
|||||||
lineNumber: 1,
|
lineNumber: 1,
|
||||||
column: 7,
|
column: 7,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual(['TABLE', 'INDEX', 'VIEW', 'DATABASE', 'NAMESPACE', 'SCHEMA']);
|
expect(suggestion).toEqual(['TABLE', 'INDEX', 'VIEW', 'DATABASE', 'NAMESPACE', 'SCHEMA']);
|
||||||
});
|
});
|
||||||
@ -23,7 +27,10 @@ describe('Spark SQL Token Suggestion', () => {
|
|||||||
lineNumber: 3,
|
lineNumber: 3,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'TEMPORARY',
|
'TEMPORARY',
|
||||||
@ -46,7 +53,10 @@ describe('Spark SQL Token Suggestion', () => {
|
|||||||
lineNumber: 5,
|
lineNumber: 5,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual(['FROM']);
|
expect(suggestion).toEqual(['FROM']);
|
||||||
});
|
});
|
||||||
@ -56,7 +66,10 @@ describe('Spark SQL Token Suggestion', () => {
|
|||||||
lineNumber: 7,
|
lineNumber: 7,
|
||||||
column: 10,
|
column: 10,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'WITH',
|
'WITH',
|
||||||
@ -79,7 +92,10 @@ describe('Spark SQL Token Suggestion', () => {
|
|||||||
lineNumber: 9,
|
lineNumber: 9,
|
||||||
column: 6,
|
column: 6,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'TEMPORARY',
|
'TEMPORARY',
|
||||||
@ -99,7 +115,10 @@ describe('Spark SQL Token Suggestion', () => {
|
|||||||
lineNumber: 11,
|
lineNumber: 11,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual(['OVERWRITE', 'INTO']);
|
expect(suggestion).toEqual(['OVERWRITE', 'INTO']);
|
||||||
});
|
});
|
||||||
@ -109,7 +128,10 @@ describe('Spark SQL Token Suggestion', () => {
|
|||||||
lineNumber: 13,
|
lineNumber: 13,
|
||||||
column: 6,
|
column: 6,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual(['DATA']);
|
expect(suggestion).toEqual(['DATA']);
|
||||||
});
|
});
|
||||||
@ -119,7 +141,10 @@ describe('Spark SQL Token Suggestion', () => {
|
|||||||
lineNumber: 15,
|
lineNumber: 15,
|
||||||
column: 6,
|
column: 6,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual([
|
expect(suggestion).toEqual([
|
||||||
'LOCKS',
|
'LOCKS',
|
||||||
@ -154,7 +179,10 @@ describe('Spark SQL Token Suggestion', () => {
|
|||||||
lineNumber: 17,
|
lineNumber: 17,
|
||||||
column: 8,
|
column: 8,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual(['TABLE']);
|
expect(suggestion).toEqual(['TABLE']);
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
CREATE TABLE VALUES -- unfinished
|
||||||
|
|
||||||
|
ALTER SCHEMA foo RENAME TO bar;
|
||||||
|
|
||||||
|
DELETE FROM t;
|
||||||
|
|
||||||
|
DENY SELECT ON SCHEMA s TO USER u;
|
||||||
|
|
||||||
|
SELECT ids FROM db. ; -- unfinished
|
||||||
|
|
||||||
|
INSERT INTO weather (date, city, temp_hi, temp_lo) VALUES ('1994-11-29', 'Hayward', 54, 37);
|
||||||
|
|
||||||
|
EXPLAIN ANALYZE VERBOSE SELECT * FROM t;
|
||||||
|
|
||||||
|
INSERT INTO weather (date, city, temp_hi, temp_lo) VALUES ('1994-11-29', 'Hayward', 54, 37); -- unfinished
|
||||||
|
|
||||||
|
DENY SELECT ON SCHEMA s TO USER u;
|
||||||
|
|
||||||
|
CALL catalog.schema.test();
|
||||||
|
|
||||||
|
INSERT INTO products (product_no, name, price) SELECT * FROM db. ; -- unfinished
|
||||||
|
|
69
test/parser/trinosql/suggestion/multipleStatement.test.ts
Normal file
69
test/parser/trinosql/suggestion/multipleStatement.test.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
|
||||||
|
import TrinoSQL from '../../../../src/parser/trinosql';
|
||||||
|
|
||||||
|
const syntaxSql = fs.readFileSync(
|
||||||
|
path.join(__dirname, 'fixtures', 'multipleStatement.sql'),
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('TrinoSQL Multiple Statements Syntax Suggestion', () => {
|
||||||
|
const parser = new TrinoSQL();
|
||||||
|
|
||||||
|
test('Create table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 1,
|
||||||
|
column: 14,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Select from table', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 9,
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 15,
|
||||||
|
column: 13,
|
||||||
|
};
|
||||||
|
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([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Insert into select from table ', () => {
|
||||||
|
const pos: CaretPosition = {
|
||||||
|
lineNumber: 21,
|
||||||
|
column: 65,
|
||||||
|
};
|
||||||
|
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(['db', '.']);
|
||||||
|
});
|
||||||
|
});
|
@ -14,7 +14,10 @@ describe('Trino SQL Token Suggestion', () => {
|
|||||||
lineNumber: 1,
|
lineNumber: 1,
|
||||||
column: 7,
|
column: 7,
|
||||||
};
|
};
|
||||||
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
|
const suggestion = parser.getSuggestionAtCaretPosition(
|
||||||
|
commentOtherLine(tokenSql, pos.lineNumber),
|
||||||
|
pos
|
||||||
|
)?.keywords;
|
||||||
|
|
||||||
expect(suggestion).toEqual(['VIEW', 'MATERIALIZED', 'TABLE', 'SCHEMA']);
|
expect(suggestion).toEqual(['VIEW', 'MATERIALIZED', 'TABLE', 'SCHEMA']);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user