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:
Hayden 2023-12-13 11:33:47 +08:00 committed by GitHub
parent fd50c09a86
commit 3c7c59fb70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 930 additions and 155 deletions

View File

@ -277,55 +277,74 @@ export default abstract class BasicParser<
/**
* 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);
const statementCount = splitListener.statementsContext?.length;
const statementsContext = splitListener.statementsContext;
// If there are multiple statements.
if (splitListener.statementsContext.length > 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 (statementCount > 1) {
/**
* Find a minimum valid range, reparse the fragment, and provide a new parse tree to C3.
* The boundaries of this range must be statements with no syntax errors.
* This can ensure the stable performance of the C3.
*/
let startStatement: ParserRuleContext;
let stopStatement: ParserRuleContext;
for (let index = 0; index < statementCount; index++) {
const ctx = statementsContext[index];
const isCurrentCtxValid = !ctx.exception;
if (!isCurrentCtxValid) continue;
if (caretStatementContext) {
c3Context = caretStatementContext;
} else {
const lastStatementToken =
splitListener.statementsContext[splitListener?.statementsContext.length - 1]
.start;
/**
* If caretStatementContext is not found and it follows all statements.
* Reparses part of the input following the penultimate statement.
* And c3 will collect candidates in the new parseTreeContext.
* Ensure that the statementContext before the left boundary
* and the last statementContext on the right boundary are qualified SQL statements.
*/
if (caretTokenIndex > lastStatementToken?.tokenIndex) {
/**
* Save offset of the tokenIndex in the partInput
* compared to the tokenIndex in the whole input
*/
tokenIndexOffset = lastStatementToken?.tokenIndex;
// Correct caretTokenIndex
caretTokenIndex = caretTokenIndex - tokenIndexOffset;
const isPrevCtxValid = index === 0 || !statementsContext[index - 1]?.exception;
const isNextCtxValid =
index === statementCount - 1 || !statementsContext[index + 1]?.exception;
const inputSlice = input.slice(lastStatementToken.startIndex);
const lexer = this.createLexer(inputSlice);
lexer.removeErrorListeners();
if (ctx.stop.tokenIndex < caretTokenIndex && isPrevCtxValid) {
startStatement = ctx;
}
const tokenStream = new CommonTokenStream(lexer);
tokenStream.fill();
const parser = this.createParserFromTokenStream(tokenStream);
parser.removeErrorListeners();
parser.buildParseTree = true;
parser.errorHandler = new ErrorStrategy();
sqlParserIns = parser;
c3Context = parser.program();
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
*/
tokenIndexOffset = startStatement?.start?.tokenIndex ?? 0;
caretTokenIndex = caretTokenIndex - tokenIndexOffset;
/**
* 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);
lexer.removeErrorListeners();
const tokenStream = new CommonTokenStream(lexer);
tokenStream.fill();
const parser = this.createParserFromTokenStream(tokenStream);
parser.removeErrorListeners();
parser.buildParseTree = true;
parser.errorHandler = new ErrorStrategy();
sqlParserIns = parser;
c3Context = parser.program();
}
const core = new CodeCompletionCore(sqlParserIns);

View File

@ -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.

View File

@ -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

View 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', '.']);
});
});

View File

@ -8,7 +8,6 @@ const syntaxSql = fs.readFileSync(
path.join(__dirname, 'fixtures', 'syntaxSuggestion.sql'),
'utf-8'
);
const multipleSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'multipleSql.sql'), 'utf-8');
describe('Flink SQL Syntax Suggestion', () => {
const parser = new FlinkSQL();
@ -19,20 +18,6 @@ describe('Flink SQL Syntax Suggestion', () => {
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', () => {
const pos: CaretPosition = {
lineNumber: 1,

View File

@ -2,6 +2,7 @@ import fs from 'fs';
import path from 'path';
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
import FlinkSQL from '../../../../src/parser/flinksql';
import { commentOtherLine } from '../../../helper';
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
@ -13,7 +14,10 @@ describe('Flink SQL Token Suggestion', () => {
lineNumber: 3,
column: 5,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual(['MODULES', 'CATALOG']);
});
@ -23,7 +27,10 @@ describe('Flink SQL Token Suggestion', () => {
lineNumber: 5,
column: 8,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'CATALOG',
@ -40,7 +47,10 @@ describe('Flink SQL Token Suggestion', () => {
lineNumber: 7,
column: 6,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'MODULES',

View 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

View 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([]);
});
});

View File

@ -2,6 +2,7 @@ import fs from 'fs';
import path from 'path';
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
import HiveSQL from '../../../../src/parser/hive';
import { commentOtherLine } from '../../../helper';
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
@ -13,7 +14,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 1,
column: 7,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'APPLICATION',
'GROUP',
@ -37,7 +41,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 3,
column: 8,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'CONNECTOR',
'APPLICATION',
@ -69,7 +76,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 5,
column: 8,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual(['FROM']);
});
@ -78,7 +88,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 7,
column: 10,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'EXTENDED',
'FORMATTED',
@ -94,7 +107,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 9,
column: 6,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'CONNECTOR',
'APPLICATION',
@ -121,7 +137,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 11,
column: 8,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual(['TABLE']);
});
@ -130,7 +149,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 13,
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']);
});
@ -139,7 +161,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 15,
column: 8,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual(['INTO', 'OVERWRITE']);
});
@ -148,7 +173,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 17,
column: 6,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual(['DATA']);
});
@ -157,7 +185,10 @@ describe('Hive SQL Token Suggestion', () => {
lineNumber: 19,
column: 6,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'CURRENT',
'ROLES',

View 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

View 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', '.']);
});
});

View File

@ -2,6 +2,7 @@ import fs from 'fs';
import path from 'path';
import { CaretPosition, SyntaxContextType } from '../../../../src/parser/common/basic-parser-types';
import ImpalaSQL from '../../../../src/parser/impala';
import { commentOtherLine } from '../../../helper';
const syntaxSql = fs.readFileSync(
path.join(__dirname, 'fixtures', 'syntaxSuggestion.sql'),
@ -16,7 +17,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 1,
column: 20,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
);
@ -30,7 +34,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 3,
column: 27,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
);
@ -44,7 +51,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 5,
column: 19,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
);
@ -58,7 +68,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 7,
column: 21,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
);
@ -72,7 +85,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 7,
column: 39,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
);
@ -86,7 +102,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 9,
column: 19,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
);
@ -100,7 +119,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 11,
column: 12,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
);
@ -114,7 +136,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 13,
column: 20,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE
);
@ -128,7 +153,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 15,
column: 20,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
);
@ -142,7 +170,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 17,
column: 22,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
);
@ -156,7 +187,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 19,
column: 21,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
);
@ -170,7 +204,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 21,
column: 15,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW_CREATE
);
@ -184,7 +221,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 23,
column: 20,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE_CREATE
);
@ -198,7 +238,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 25,
column: 20,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION_CREATE
);
@ -212,7 +255,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 27,
column: 25,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.DATABASE_CREATE
);
@ -226,7 +272,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 29,
column: 19,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
);
@ -240,7 +289,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 31,
column: 22,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
);
@ -254,7 +306,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 33,
column: 22,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.TABLE
);
@ -268,7 +323,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 35,
column: 20,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.VIEW
);
@ -282,7 +340,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 37,
column: 22,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
);
@ -296,7 +357,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 39,
column: 22,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
);
@ -310,7 +374,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 41,
column: 36,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
);
@ -324,7 +391,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 43,
column: 36,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
);
@ -338,7 +408,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 45,
column: 45,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
);
@ -352,7 +425,10 @@ describe('Impala SQL Syntax Suggestion', () => {
lineNumber: 47,
column: 49,
};
const syntaxes = parser.getSuggestionAtCaretPosition(syntaxSql, pos)?.syntax;
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN_CREATE
);

View File

@ -14,7 +14,10 @@ describe('Impala SQL Token Suggestion', () => {
lineNumber: 1,
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']);
});

View 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

View 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([]);
});
});

View File

@ -50,23 +50,22 @@ describe('MySQL Syntax Suggestion', () => {
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.']);
});
// TODO: fix bug of basic parser and decomment following test
// 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
// );
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', '.']);
// });
expect(suggestion).not.toBeUndefined();
expect(suggestion?.wordRanges.map((token) => token.text)).toEqual(['db', '.']);
});
test('DROP table ', () => {
const pos: CaretPosition = {

View File

@ -42,7 +42,7 @@ describe('MySQL Database Administration Syntax Tests', () => {
it(sql, () => {
const result = parser.validate(sql);
if (result.length) {
console.log(result, `\n请检查 sql: ${sql}`);
console.log(result, `\nPlease check sql: ${sql}`);
}
expect(result.length).toBe(0);
});

View File

@ -49,7 +49,7 @@ describe('MySQL DDL Syntax Tests', () => {
it(sql, () => {
const result = parser.validate(sql);
if (result.length) {
console.log(result, `\n请检查 sql: ${sql}`);
console.log(result, `\nPlease check sql: ${sql}`);
}
expect(result.length).toBe(0);
});

View File

@ -33,7 +33,7 @@ describe('MySQL DML Syntax Tests', () => {
it(sql, () => {
const result = parser.validate(sql);
if (result.length) {
console.log(result, `\n请检查 sql: ${sql}`);
console.log(result, `\nPlease check sql: ${sql}`);
}
expect(result.length).toBe(0);
});

View File

@ -27,7 +27,7 @@ describe('MySQL Transactional and Locking, Replication, Prepared Compound and Ut
it(sql, () => {
const result = parser.validate(sql);
if (result.length) {
console.log(result, `\n请检查 sql: ${sql}`);
console.log(result, `\nPlease check sql: ${sql}`);
}
expect(result.length).toBe(0);
});

View 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

View 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', '.']);
});
});

View File

@ -638,29 +638,28 @@ describe('Postgre SQL Syntax Suggestion', () => {
lineNumber: 59,
column: 48,
};
// const pos1: CaretPosition = {
// lineNumber: 59,
// column: 93,
// };
const pos1: CaretPosition = {
lineNumber: 59,
column: 93,
};
const syntaxes = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos.lineNumber),
pos
)?.syntax;
// const syntaxes1 = parser.getSuggestionAtCaretPosition(
// commentOtherLine(syntaxSql, pos1.lineNumber),
// pos1
// )?.syntax;
const syntaxes1 = parser.getSuggestionAtCaretPosition(
commentOtherLine(syntaxSql, pos1.lineNumber),
pos1
)?.syntax;
const suggestion = syntaxes?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.COLUMN
);
// const suggestion1 = syntaxes1?.find(
// (syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
// );
const suggestion1 = syntaxes1?.find(
(syn) => syn.syntaxContextType === SyntaxContextType.FUNCTION
);
expect(suggestion).not.toBeUndefined();
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?.wordRanges.map((token) => token.text)).toEqual(['function_name']);
expect(suggestion1).not.toBeUndefined();
expect(suggestion1?.wordRanges.map((token) => token.text)).toEqual(['function_name']);
});
test('GRANT With Column', () => {

View 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

View 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', '.']);
});
});

View File

@ -2,6 +2,7 @@ import fs from 'fs';
import path from 'path';
import { CaretPosition } from '../../../../src/parser/common/basic-parser-types';
import SparkSQL from '../../../../src/parser/spark';
import { commentOtherLine } from '../../../helper';
const tokenSql = fs.readFileSync(path.join(__dirname, 'fixtures', 'tokenSuggestion.sql'), 'utf-8');
@ -13,7 +14,10 @@ describe('Spark SQL Token Suggestion', () => {
lineNumber: 1,
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']);
});
@ -23,7 +27,10 @@ describe('Spark SQL Token Suggestion', () => {
lineNumber: 3,
column: 8,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'TEMPORARY',
@ -46,7 +53,10 @@ describe('Spark SQL Token Suggestion', () => {
lineNumber: 5,
column: 8,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual(['FROM']);
});
@ -56,7 +66,10 @@ describe('Spark SQL Token Suggestion', () => {
lineNumber: 7,
column: 10,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'WITH',
@ -79,7 +92,10 @@ describe('Spark SQL Token Suggestion', () => {
lineNumber: 9,
column: 6,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'TEMPORARY',
@ -99,7 +115,10 @@ describe('Spark SQL Token Suggestion', () => {
lineNumber: 11,
column: 8,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual(['OVERWRITE', 'INTO']);
});
@ -109,7 +128,10 @@ describe('Spark SQL Token Suggestion', () => {
lineNumber: 13,
column: 6,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual(['DATA']);
});
@ -119,7 +141,10 @@ describe('Spark SQL Token Suggestion', () => {
lineNumber: 15,
column: 6,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual([
'LOCKS',
@ -154,7 +179,10 @@ describe('Spark SQL Token Suggestion', () => {
lineNumber: 17,
column: 8,
};
const suggestion = parser.getSuggestionAtCaretPosition(tokenSql, pos)?.keywords;
const suggestion = parser.getSuggestionAtCaretPosition(
commentOtherLine(tokenSql, pos.lineNumber),
pos
)?.keywords;
expect(suggestion).toEqual(['TABLE']);
});

View File

@ -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

View 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', '.']);
});
});

View File

@ -14,7 +14,10 @@ describe('Trino SQL Token Suggestion', () => {
lineNumber: 1,
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']);
});