From 8b6b2c43bc17b71ff83b5fcedc045dc68b9014d6 Mon Sep 17 00:00:00 2001 From: roberthovsepyan <33484604+roberthovsepyan@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:12:36 +0100 Subject: [PATCH] feat: extend StatementPart, make TestCase fields optional, migrate location tests to typescript and move files to select folder (#107) * refactor: extend StatementPart, make TestCase fields optional * refactor: migrate generic location tests to typescript and move file to select folder * refactor: migrate clickhouse location tests to typescript and move file to select folder * refactor: migrate postgresql location tests to typescript and move file to select folder --------- Co-authored-by: robhovsepyan --- src/autocomplete/index.ts | 38 +- ...khouseAutocompleteParser.locations.test.js | 1328 ---------------- .../grammar/select/locations.test.ts | 1327 ++++++++++++++++ ...enericAutocompleteParser.locations.test.js | 1347 ----------------- .../generic/grammar/select/locations.test.ts | 1346 ++++++++++++++++ .../grammar/select/locations.test.ts | 1316 ++++++++++++++++ ...gresqlAutocompleteParser.locations.test.js | 1317 ---------------- src/autocomplete/test/testing.ts | 14 +- 8 files changed, 4033 insertions(+), 4000 deletions(-) delete mode 100644 src/autocomplete/parsers/clickhouse/clickhouseAutocompleteParser.locations.test.js create mode 100644 src/autocomplete/parsers/clickhouse/grammar/select/locations.test.ts delete mode 100644 src/autocomplete/parsers/generic/genericAutocompleteParser.locations.test.js create mode 100644 src/autocomplete/parsers/generic/grammar/select/locations.test.ts create mode 100644 src/autocomplete/parsers/postgresql/grammar/select/locations.test.ts delete mode 100644 src/autocomplete/parsers/postgresql/postgresqlAutocompleteParser.locations.test.js diff --git a/src/autocomplete/index.ts b/src/autocomplete/index.ts index 12125ca4..b2339ef5 100644 --- a/src/autocomplete/index.ts +++ b/src/autocomplete/index.ts @@ -88,8 +88,43 @@ export type StatementPart = location: Location; missing: boolean; subquery?: true; + } + | { + type: 'function'; + location: Location; + function: string; + } + | { + type: 'functionArgument'; + location: Location; + function: string; + argumentPosition: number; + identifierChain: IdentifierChainEntry[]; + expression: Expression; + } + | { + type: 'alias'; + alias: string; + location: Location; + source?: string; + parentLocation?: Location; + target?: string; + identifierChain?: IdentifierChainEntry[]; + } + | { + type: 'complex'; + location: Location; + identifierChain: IdentifierChainEntry[]; + tables: Table[]; + qualified: boolean; }; +interface Expression { + types?: string[]; + text?: string; + columnReference?: IdentifierChainEntry[]; +} + export interface TablesSuggestion { prependFrom?: boolean; prependQuestionMark?: boolean; @@ -164,8 +199,9 @@ export interface Location { } export interface Table { + identifierChain?: IdentifierChainEntry[]; alias?: string; - identifierChain: IdentifierChainEntry[]; + subQuery?: string; } export interface IdentifierChainEntry { diff --git a/src/autocomplete/parsers/clickhouse/clickhouseAutocompleteParser.locations.test.js b/src/autocomplete/parsers/clickhouse/clickhouseAutocompleteParser.locations.test.js deleted file mode 100644 index b3886a4e..00000000 --- a/src/autocomplete/parsers/clickhouse/clickhouseAutocompleteParser.locations.test.js +++ /dev/null @@ -1,1328 +0,0 @@ -// Copyright 2023 YANDEX LLC -// -// Licensed under the Apache License, Version 2.0 (the "License") -// You may not use this file except in compliance with the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software distributed under -// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -// either express or implied. See the License for the specific language governing permissions -// and limitations under the License. - -import {beforeAll, describe, expect, it} from '@jest/globals'; - -import {clickhouseAutocompleteParser} from './clickhouseAutocompleteParser'; - -// prettier-ignore-start - -describe('clickhouseAutocompleteParser.js locations', () => { - beforeAll(() => { - clickhouseAutocompleteParser.yy.parseError = function (msg) { - throw Error(msg); - }; - }); - - const assertAutoComplete = (testDefinition) => { - const debug = false; - expect( - clickhouseAutocompleteParser.parseSql( - testDefinition.beforeCursor, - testDefinition.afterCursor, - debug, - ), - ).toEqualDefinition(testDefinition); - }; - - const assertLocations = function (options) { - assertAutoComplete({ - beforeCursor: options.beforeCursor, - afterCursor: options.afterCursor || '', - locationsOnly: true, - noErrors: true, - expectedLocations: options.expectedLocations, - expectedDefinitions: options.expectedDefinitions, - }); - }; - - it('should report locations for "select cos(1) as foo from customers order by foo;"', () => { - assertLocations({ - beforeCursor: 'select cos(1) as foo from customers order by foo; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 49}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 21}, - }, - { - type: 'function', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - function: 'cos', - }, - { - type: 'functionArgument', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, - function: 'cos', - argumentPosition: 0, - identifierChain: [{name: 'cos'}], - expression: {types: ['NUMBER'], text: '1'}, - }, - { - type: 'alias', - source: 'column', - alias: 'foo', - location: {first_line: 1, last_line: 1, first_column: 18, last_column: 21}, - parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 27, last_column: 36}, - identifierChain: [{name: 'customers'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 36, last_column: 36}, - }, - { - type: 'alias', - location: {first_line: 1, last_line: 1, first_column: 46, last_column: 49}, - alias: 'foo', - source: 'column', - parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 49, last_column: 49}, - }, - ], - }); - }); - - it('should report locations for "WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; |"', () => { - assertLocations({ - beforeCursor: 'WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 50}, - }, - { - type: 'alias', - source: 'cte', - alias: 'boo', - location: {first_line: 1, last_line: 1, first_column: 6, last_column: 9}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, - subquery: true, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, - tables: [{identifierChain: [{name: 'tbl'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 28, last_column: 31}, - identifierChain: [{name: 'tbl'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - subquery: true, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - subquery: true, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, - tables: [{identifierChain: [{name: 'boo'}]}], - }, - { - type: 'alias', - target: 'cte', - alias: 'boo', - location: {first_line: 1, last_line: 1, first_column: 47, last_column: 50}, - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, - }, - ], - }); - }); - - it('should report locations for "SELECT * FROM testTable1 JOIN db1.table2; |"', () => { - assertLocations({ - beforeCursor: 'SELECT * FROM testTable1 JOIN db1.table2; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 41}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - tables: [ - {identifierChain: [{name: 'testTable1'}]}, - {identifierChain: [{name: 'db1'}, {name: 'table2'}]}, - ], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 25}, - identifierChain: [{name: 'testTable1'}], - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 34}, - identifierChain: [{name: 'db1'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 35, last_column: 41}, - identifierChain: [{name: 'db1'}, {name: 'table2'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, - }, - ], - }); - }); - - it('should report locations for "SELECT a.col FROM db.tbl a; |"', () => { - assertLocations({ - beforeCursor: 'SELECT a.col FROM db.tbl a; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 27}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 10, last_column: 13}, - identifierChain: [{name: 'col'}], - tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], - qualified: true, - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 21}, - identifierChain: [{name: 'db'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 22, last_column: 25}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'alias', - source: 'table', - alias: 'a', - location: {first_line: 1, last_line: 1, first_column: 26, last_column: 27}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, - }, - ], - }); - }); - - it('should report locations for "SELECT tbl.col FROM db.tbl a; |"', () => { - assertLocations({ - beforeCursor: 'SELECT tbl.col FROM db.tbl a; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 29}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 15}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, - identifierChain: [{name: 'tbl'}], - tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], - qualified: false, - }, - { - type: 'complex', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 15}, - identifierChain: [{name: 'tbl'}, {name: 'col'}], - tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], - qualified: true, - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 23}, - identifierChain: [{name: 'db'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 24, last_column: 27}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'alias', - source: 'table', - alias: 'a', - location: {first_line: 1, last_line: 1, first_column: 28, last_column: 29}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, - }, - ], - }); - }); - - it('should report locations for "select x from x;"', () => { - assertLocations({ - beforeCursor: 'select x from x;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - ], - }); - }); - - it('should report locations for "select x from x;select y from y;"', () => { - assertLocations({ - beforeCursor: 'select x from x;select y from y;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 17, last_column: 32}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, - identifierChain: [{name: 'y'}], - tables: [{identifierChain: [{name: 'y'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 32}, - identifierChain: [{name: 'y'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, - }, - ], - }); - }); - - it('should report locations for "-- comment\nselect x from x;\n\n\nselect y from y;"', () => { - assertLocations({ - beforeCursor: '-- comment\nselect x from x;\n\n\nselect y from y;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 2, first_column: 1, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, - }, - { - type: 'statement', - location: {first_line: 2, last_line: 5, first_column: 17, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, - identifierChain: [{name: 'y'}], - tables: [{identifierChain: [{name: 'y'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 15, last_column: 16}, - identifierChain: [{name: 'y'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, - }, - ], - }); - }); - - it('should report locations for "select x from x, y;"', () => { - assertLocations({ - beforeCursor: 'select x from x, y;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 19}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}, {identifierChain: [{name: 'y'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 18, last_column: 19}, - identifierChain: [{name: 'y'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, - }, - ], - }); - }); - - it('should report locations for "SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;|"', () => { - assertLocations({ - beforeCursor: 'SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 63}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 17}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - identifierChain: [{name: 'testTable3'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 11, last_column: 13}, - identifierChain: [{name: 'id'}], - tables: [{identifierChain: [{name: 'testTable3'}], alias: 't3'}], - qualified: true, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 17}, - identifierChain: [{name: 'id'}], - tables: [ - {identifierChain: [{name: 'testTable1'}]}, - {identifierChain: [{name: 'db'}, {name: 'testTable2'}]}, - {identifierChain: [{name: 'testTable3'}], alias: 't3'}, - ], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 23, last_column: 33}, - identifierChain: [{name: 'testTable1'}], - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 35, last_column: 37}, - identifierChain: [{name: 'db'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 38, last_column: 48}, - identifierChain: [{name: 'db'}, {name: 'testTable2'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 50, last_column: 60}, - identifierChain: [{name: 'testTable3'}], - }, - { - type: 'alias', - source: 'table', - alias: 't3', - location: {first_line: 1, last_line: 1, first_column: 61, last_column: 63}, - identifierChain: [{name: 'testTable3'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, - }, - ], - }); - }); - - it('should report locations for "SELECT * FROM foo WHERE bar IN (1+1, 2+2);|"', () => { - assertLocations({ - beforeCursor: 'SELECT * FROM foo WHERE bar IN (1+1, 2+2);', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 42}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - tables: [{identifierChain: [{name: 'foo'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, - identifierChain: [{name: 'foo'}], - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 42}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, - identifierChain: [{name: 'bar'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 42, last_column: 42}, - }, - ], - }); - }); - - it('should report locations for "SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);|"', () => { - assertLocations({ - beforeCursor: 'SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 48}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - tables: [{identifierChain: [{name: 'foo'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, - identifierChain: [{name: 'foo'}], - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 48}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, - identifierChain: [{name: 'bar'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 33, last_column: 35}, - identifierChain: [{name: 'id'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 43}, - identifierChain: [{name: 'id'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 48, last_column: 48}, - }, - ], - }); - }); - - it( - 'should report locations for "SELECT s07.description, s07.salary, s08.salary,\\r\\n' + - ' s08.salary - s07.salary\\r\\n' + - 'FROM\\r\\n' + - ' sample_07 s07 JOIN sample_08 s08\\r\\n' + - 'ON ( s07.code = s08.code)\\r\\n' + - 'WHERE\\r\\n' + - ' s07.salary < s08.salary\\r\\n' + - 'ORDER BY s08.salary-s07.salary DESC\\r\\n' + - 'LIMIT 1000;|"', - () => { - assertLocations({ - beforeCursor: - 'SELECT s07.description, s07.salary, s08.salary,\r\n' + - ' s08.salary - s07.salary\r\n' + - 'FROM\r\n' + - ' sample_07 s07 JOIN sample_08 s08\r\n' + - 'ON ( s07.code = s08.code)\r\n' + - 'WHERE\r\n' + - ' s07.salary < s08.salary\r\n' + - 'ORDER BY s08.salary-s07.salary DESC\r\n' + - 'LIMIT 1000;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 9, first_column: 1, last_column: 11}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 2, first_column: 8, last_column: 26}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 23}, - identifierChain: [{name: 'description'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 29, last_column: 35}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 37, last_column: 40}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 47}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 3, last_column: 6}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 7, last_column: 13}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 16, last_column: 19}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 20, last_column: 26}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 3, last_column: 12}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'alias', - source: 'table', - alias: 's07', - location: {first_line: 4, last_line: 4, first_column: 13, last_column: 16}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 22, last_column: 31}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'alias', - source: 'table', - alias: 's08', - location: {first_line: 4, last_line: 4, first_column: 32, last_column: 35}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 6, last_column: 9}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 10, last_column: 14}, - identifierChain: [{name: 'code'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 17, last_column: 20}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 21, last_column: 25}, - identifierChain: [{name: 'code'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 6, last_line: 7, first_column: 1, last_column: 26}, - }, - { - type: 'table', - location: {first_line: 7, last_line: 7, first_column: 3, last_column: 6}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 7, last_line: 7, first_column: 7, last_column: 13}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 7, last_line: 7, first_column: 16, last_column: 19}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 7, last_line: 7, first_column: 20, last_column: 26}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 8, last_line: 8, first_column: 10, last_column: 13}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 8, last_line: 8, first_column: 14, last_column: 20}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 8, last_line: 8, first_column: 21, last_column: 24}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 8, last_line: 8, first_column: 25, last_column: 31}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'limitClause', - missing: false, - location: {first_line: 9, last_line: 9, first_column: 1, last_column: 11}, - }, - ], - }); - }, - ); - - it('should handle "select bl from blablabla join (select * from blablabla) s1;', () => { - assertLocations({ - beforeCursor: 'select bl from blablabla join (select * from blablabla) s1;', - afterCursor: '', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 59}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - identifierChain: [{name: 'bl'}], - tables: [{identifierChain: [{name: 'blablabla'}]}, {subQuery: 's1'}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 25}, - identifierChain: [{name: 'blablabla'}], - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, - subquery: true, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, - tables: [{identifierChain: [{name: 'blablabla'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 46, last_column: 55}, - identifierChain: [{name: 'blablabla'}], - }, - { - type: 'whereClause', - subquery: true, - missing: true, - location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, - }, - { - type: 'limitClause', - subquery: true, - missing: true, - location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, - }, - { - type: 'alias', - source: 'subquery', - alias: 's1', - location: {first_line: 1, last_line: 1, first_column: 57, last_column: 59}, - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, - }, - ], - }); - }); - - it( - 'should report locations for "SELECT CASE cos(boo.a) > baa.boo \\n' + - '\\tWHEN baa.b THEN true \\n' + - '\\tWHEN boo.c THEN false \\n' + - '\\tWHEN baa.blue THEN boo.d \\n' + - '\\tELSE baa.e END \\n' + - '\\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);|"', - () => { - assertLocations({ - beforeCursor: - 'SELECT CASE cos(boo.a) > baa.boo \n\tWHEN baa.b THEN true \n\tWHEN boo.c THEN false \n\tWHEN baa.blue THEN boo.d \n\tELSE baa.e END \n\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 6, first_column: 1, last_column: 67}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 5, first_column: 8, last_column: 16}, - }, - { - type: 'function', - location: {first_line: 1, last_line: 1, first_column: 13, last_column: 15}, - function: 'cos', - }, - { - type: 'functionArgument', - location: {first_line: 1, last_line: 1, first_column: 17, last_column: 22}, - function: 'cos', - argumentPosition: 0, - identifierChain: [{name: 'cos'}], - expression: { - types: ['COLREF'], - columnReference: [{name: 'boo'}, {name: 'a'}], - }, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 17, last_column: 20}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, - identifierChain: [{name: 'a'}], - tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 26, last_column: 29}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, - identifierChain: [{name: 'boo'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 7, last_column: 10}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 11, last_column: 12}, - identifierChain: [{name: 'b'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 3, last_line: 3, first_column: 7, last_column: 10}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'column', - location: {first_line: 3, last_line: 3, first_column: 11, last_column: 12}, - identifierChain: [{name: 'c'}], - tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 7, last_column: 10}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 4, last_line: 4, first_column: 11, last_column: 15}, - identifierChain: [{name: 'blue'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 21, last_column: 24}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'column', - location: {first_line: 4, last_line: 4, first_column: 25, last_column: 26}, - identifierChain: [{name: 'd'}], - tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 7, last_column: 10}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 11, last_column: 12}, - identifierChain: [{name: 'e'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'database', - location: {first_line: 6, last_line: 6, first_column: 8, last_column: 11}, - identifierChain: [{name: 'db1'}], - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 12, last_column: 15}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'alias', - source: 'table', - alias: 'boo', - location: {first_line: 6, last_line: 6, first_column: 16, last_column: 19}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 21, last_column: 24}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'alias', - source: 'table', - alias: 'baa', - location: {first_line: 6, last_line: 6, first_column: 25, last_column: 28}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 6, last_line: 6, first_column: 29, last_column: 67}, - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 35, last_column: 38}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 6, last_line: 6, first_column: 39, last_column: 42}, - identifierChain: [{name: 'bla'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, - subquery: true, - }, - { - type: 'column', - location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, - identifierChain: [{name: 'ble'}], - tables: [{identifierChain: [{name: 'bla'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 63, last_column: 66}, - identifierChain: [{name: 'bla'}], - }, - { - type: 'whereClause', - subquery: true, - missing: true, - location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, - }, - { - type: 'limitClause', - subquery: true, - missing: true, - location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 6, last_line: 6, first_column: 67, last_column: 67}, - }, - ], - }); - }, - ); - - it('should report locations for "SELECT tta.* FROM testTableA tta, testTableB; |"', () => { - assertLocations({ - beforeCursor: 'SELECT tta.* FROM testTableA tta, testTableB; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 45}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, - identifierChain: [{name: 'testTableA'}], - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, - tables: [{alias: 'tta', identifierChain: [{name: 'testTableA'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 29}, - identifierChain: [{name: 'testTableA'}], - }, - { - type: 'alias', - source: 'table', - alias: 'tta', - location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, - identifierChain: [{name: 'testTableA'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 35, last_column: 45}, - identifierChain: [{name: 'testTableB'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, - }, - ], - }); - }); - - it('should report locations for "SELECT COUNT(*) FROM testTable; |"', () => { - assertLocations({ - beforeCursor: 'SELECT COUNT(*) FROM testTable;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 31}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 16}, - }, - { - type: 'function', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 12}, - function: 'count', - }, - { - type: 'functionArgument', - location: {first_line: 1, last_line: 1, first_column: 14, last_column: 15}, - function: 'count', - argumentPosition: 0, - identifierChain: [{name: 'count'}], - expression: {text: '*'}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 22, last_column: 31}, - identifierChain: [{name: 'testTable'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - }, - ], - }); - }); -}); - -// prettier-ignore-end diff --git a/src/autocomplete/parsers/clickhouse/grammar/select/locations.test.ts b/src/autocomplete/parsers/clickhouse/grammar/select/locations.test.ts new file mode 100644 index 00000000..346140ca --- /dev/null +++ b/src/autocomplete/parsers/clickhouse/grammar/select/locations.test.ts @@ -0,0 +1,1327 @@ +// Copyright 2023 YANDEX LLC +// +// Licensed under the Apache License, Version 2.0 (the "License") +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed under +// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +import {beforeAll, expect, it} from '@jest/globals'; + +import {TestCase} from '../../../../test/testing'; +import {clickhouseAutocompleteParser} from '../../clickhouseAutocompleteParser'; + +// prettier-ignore-start + +beforeAll(() => { + clickhouseAutocompleteParser.yy.parseError = function (msg: string): void { + throw Error(msg); + }; +}); + +const assertAutoComplete = (testDefinition: TestCase): void => { + const debug = false; + expect( + clickhouseAutocompleteParser.parseSql( + testDefinition.beforeCursor, + testDefinition.afterCursor, + debug, + ), + ).toEqualDefinition(testDefinition); +}; + +const assertLocations = function (options: TestCase): void { + assertAutoComplete({ + beforeCursor: options.beforeCursor, + afterCursor: options.afterCursor || '', + locationsOnly: true, + noErrors: true, + expectedLocations: options.expectedLocations, + expectedDefinitions: options.expectedDefinitions, + }); +}; + +it('should report locations for "select cos(1) as foo from customers order by foo;"', () => { + assertLocations({ + beforeCursor: 'select cos(1) as foo from customers order by foo; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 49}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 21}, + }, + { + type: 'function', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + function: 'cos', + }, + { + type: 'functionArgument', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, + function: 'cos', + argumentPosition: 0, + identifierChain: [{name: 'cos'}], + expression: {types: ['NUMBER'], text: '1'}, + }, + { + type: 'alias', + source: 'column', + alias: 'foo', + location: {first_line: 1, last_line: 1, first_column: 18, last_column: 21}, + parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 27, last_column: 36}, + identifierChain: [{name: 'customers'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 36, last_column: 36}, + }, + { + type: 'alias', + location: {first_line: 1, last_line: 1, first_column: 46, last_column: 49}, + alias: 'foo', + source: 'column', + parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 49, last_column: 49}, + }, + ], + }); +}); + +it('should report locations for "WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; |"', () => { + assertLocations({ + beforeCursor: 'WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 50}, + }, + { + type: 'alias', + source: 'cte', + alias: 'boo', + location: {first_line: 1, last_line: 1, first_column: 6, last_column: 9}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, + subquery: true, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, + tables: [{identifierChain: [{name: 'tbl'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 28, last_column: 31}, + identifierChain: [{name: 'tbl'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + subquery: true, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + subquery: true, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, + tables: [{identifierChain: [{name: 'boo'}]}], + }, + { + type: 'alias', + target: 'cte', + alias: 'boo', + location: {first_line: 1, last_line: 1, first_column: 47, last_column: 50}, + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, + }, + ], + }); +}); + +it('should report locations for "SELECT * FROM testTable1 JOIN db1.table2; |"', () => { + assertLocations({ + beforeCursor: 'SELECT * FROM testTable1 JOIN db1.table2; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 41}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + tables: [ + {identifierChain: [{name: 'testTable1'}]}, + {identifierChain: [{name: 'db1'}, {name: 'table2'}]}, + ], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 25}, + identifierChain: [{name: 'testTable1'}], + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 34}, + identifierChain: [{name: 'db1'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 35, last_column: 41}, + identifierChain: [{name: 'db1'}, {name: 'table2'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, + }, + ], + }); +}); + +it('should report locations for "SELECT a.col FROM db.tbl a; |"', () => { + assertLocations({ + beforeCursor: 'SELECT a.col FROM db.tbl a; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 27}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 10, last_column: 13}, + identifierChain: [{name: 'col'}], + tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], + qualified: true, + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 21}, + identifierChain: [{name: 'db'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 22, last_column: 25}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'alias', + source: 'table', + alias: 'a', + location: {first_line: 1, last_line: 1, first_column: 26, last_column: 27}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, + }, + ], + }); +}); + +it('should report locations for "SELECT tbl.col FROM db.tbl a; |"', () => { + assertLocations({ + beforeCursor: 'SELECT tbl.col FROM db.tbl a; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 29}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 15}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, + identifierChain: [{name: 'tbl'}], + tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], + qualified: false, + }, + { + type: 'complex', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 15}, + identifierChain: [{name: 'tbl'}, {name: 'col'}], + tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], + qualified: true, + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 23}, + identifierChain: [{name: 'db'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 24, last_column: 27}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'alias', + source: 'table', + alias: 'a', + location: {first_line: 1, last_line: 1, first_column: 28, last_column: 29}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, + }, + ], + }); +}); + +it('should report locations for "select x from x;"', () => { + assertLocations({ + beforeCursor: 'select x from x;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + ], + }); +}); + +it('should report locations for "select x from x;select y from y;"', () => { + assertLocations({ + beforeCursor: 'select x from x;select y from y;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 17, last_column: 32}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, + identifierChain: [{name: 'y'}], + tables: [{identifierChain: [{name: 'y'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 32}, + identifierChain: [{name: 'y'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, + }, + ], + }); +}); + +it('should report locations for "-- comment\nselect x from x;\n\n\nselect y from y;"', () => { + assertLocations({ + beforeCursor: '-- comment\nselect x from x;\n\n\nselect y from y;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 2, first_column: 1, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, + }, + { + type: 'statement', + location: {first_line: 2, last_line: 5, first_column: 17, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, + identifierChain: [{name: 'y'}], + tables: [{identifierChain: [{name: 'y'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 15, last_column: 16}, + identifierChain: [{name: 'y'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, + }, + ], + }); +}); + +it('should report locations for "select x from x, y;"', () => { + assertLocations({ + beforeCursor: 'select x from x, y;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 19}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}, {identifierChain: [{name: 'y'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 18, last_column: 19}, + identifierChain: [{name: 'y'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, + }, + ], + }); +}); + +it('should report locations for "SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;|"', () => { + assertLocations({ + beforeCursor: 'SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 63}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 17}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + identifierChain: [{name: 'testTable3'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 11, last_column: 13}, + identifierChain: [{name: 'id'}], + tables: [{identifierChain: [{name: 'testTable3'}], alias: 't3'}], + qualified: true, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 17}, + identifierChain: [{name: 'id'}], + tables: [ + {identifierChain: [{name: 'testTable1'}]}, + {identifierChain: [{name: 'db'}, {name: 'testTable2'}]}, + {identifierChain: [{name: 'testTable3'}], alias: 't3'}, + ], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 23, last_column: 33}, + identifierChain: [{name: 'testTable1'}], + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 35, last_column: 37}, + identifierChain: [{name: 'db'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 38, last_column: 48}, + identifierChain: [{name: 'db'}, {name: 'testTable2'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 50, last_column: 60}, + identifierChain: [{name: 'testTable3'}], + }, + { + type: 'alias', + source: 'table', + alias: 't3', + location: {first_line: 1, last_line: 1, first_column: 61, last_column: 63}, + identifierChain: [{name: 'testTable3'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, + }, + ], + }); +}); + +it('should report locations for "SELECT * FROM foo WHERE bar IN (1+1, 2+2);|"', () => { + assertLocations({ + beforeCursor: 'SELECT * FROM foo WHERE bar IN (1+1, 2+2);', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 42}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + tables: [{identifierChain: [{name: 'foo'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, + identifierChain: [{name: 'foo'}], + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 42}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, + identifierChain: [{name: 'bar'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 42, last_column: 42}, + }, + ], + }); +}); + +it('should report locations for "SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);|"', () => { + assertLocations({ + beforeCursor: 'SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 48}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + tables: [{identifierChain: [{name: 'foo'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, + identifierChain: [{name: 'foo'}], + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 48}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, + identifierChain: [{name: 'bar'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 33, last_column: 35}, + identifierChain: [{name: 'id'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 43}, + identifierChain: [{name: 'id'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 48, last_column: 48}, + }, + ], + }); +}); + +it( + 'should report locations for "SELECT s07.description, s07.salary, s08.salary,\\r\\n' + + ' s08.salary - s07.salary\\r\\n' + + 'FROM\\r\\n' + + ' sample_07 s07 JOIN sample_08 s08\\r\\n' + + 'ON ( s07.code = s08.code)\\r\\n' + + 'WHERE\\r\\n' + + ' s07.salary < s08.salary\\r\\n' + + 'ORDER BY s08.salary-s07.salary DESC\\r\\n' + + 'LIMIT 1000;|"', + () => { + assertLocations({ + beforeCursor: + 'SELECT s07.description, s07.salary, s08.salary,\r\n' + + ' s08.salary - s07.salary\r\n' + + 'FROM\r\n' + + ' sample_07 s07 JOIN sample_08 s08\r\n' + + 'ON ( s07.code = s08.code)\r\n' + + 'WHERE\r\n' + + ' s07.salary < s08.salary\r\n' + + 'ORDER BY s08.salary-s07.salary DESC\r\n' + + 'LIMIT 1000;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 9, first_column: 1, last_column: 11}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 2, first_column: 8, last_column: 26}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 23}, + identifierChain: [{name: 'description'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 29, last_column: 35}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 37, last_column: 40}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 47}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 3, last_column: 6}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 7, last_column: 13}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 16, last_column: 19}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 20, last_column: 26}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 3, last_column: 12}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'alias', + source: 'table', + alias: 's07', + location: {first_line: 4, last_line: 4, first_column: 13, last_column: 16}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 22, last_column: 31}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'alias', + source: 'table', + alias: 's08', + location: {first_line: 4, last_line: 4, first_column: 32, last_column: 35}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 6, last_column: 9}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 10, last_column: 14}, + identifierChain: [{name: 'code'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 17, last_column: 20}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 21, last_column: 25}, + identifierChain: [{name: 'code'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 6, last_line: 7, first_column: 1, last_column: 26}, + }, + { + type: 'table', + location: {first_line: 7, last_line: 7, first_column: 3, last_column: 6}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 7, last_line: 7, first_column: 7, last_column: 13}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 7, last_line: 7, first_column: 16, last_column: 19}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 7, last_line: 7, first_column: 20, last_column: 26}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 8, last_line: 8, first_column: 10, last_column: 13}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 8, last_line: 8, first_column: 14, last_column: 20}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 8, last_line: 8, first_column: 21, last_column: 24}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 8, last_line: 8, first_column: 25, last_column: 31}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'limitClause', + missing: false, + location: {first_line: 9, last_line: 9, first_column: 1, last_column: 11}, + }, + ], + }); + }, +); + +it('should handle "select bl from blablabla join (select * from blablabla) s1;', () => { + assertLocations({ + beforeCursor: 'select bl from blablabla join (select * from blablabla) s1;', + afterCursor: '', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 59}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + identifierChain: [{name: 'bl'}], + tables: [{identifierChain: [{name: 'blablabla'}]}, {subQuery: 's1'}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 25}, + identifierChain: [{name: 'blablabla'}], + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, + subquery: true, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, + tables: [{identifierChain: [{name: 'blablabla'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 46, last_column: 55}, + identifierChain: [{name: 'blablabla'}], + }, + { + type: 'whereClause', + subquery: true, + missing: true, + location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, + }, + { + type: 'limitClause', + subquery: true, + missing: true, + location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, + }, + { + type: 'alias', + source: 'subquery', + alias: 's1', + location: {first_line: 1, last_line: 1, first_column: 57, last_column: 59}, + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, + }, + ], + }); +}); + +it( + 'should report locations for "SELECT CASE cos(boo.a) > baa.boo \\n' + + '\\tWHEN baa.b THEN true \\n' + + '\\tWHEN boo.c THEN false \\n' + + '\\tWHEN baa.blue THEN boo.d \\n' + + '\\tELSE baa.e END \\n' + + '\\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);|"', + () => { + assertLocations({ + beforeCursor: + 'SELECT CASE cos(boo.a) > baa.boo \n\tWHEN baa.b THEN true \n\tWHEN boo.c THEN false \n\tWHEN baa.blue THEN boo.d \n\tELSE baa.e END \n\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 6, first_column: 1, last_column: 67}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 5, first_column: 8, last_column: 16}, + }, + { + type: 'function', + location: {first_line: 1, last_line: 1, first_column: 13, last_column: 15}, + function: 'cos', + }, + { + type: 'functionArgument', + location: {first_line: 1, last_line: 1, first_column: 17, last_column: 22}, + function: 'cos', + argumentPosition: 0, + identifierChain: [{name: 'cos'}], + expression: { + types: ['COLREF'], + columnReference: [{name: 'boo'}, {name: 'a'}], + }, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 17, last_column: 20}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, + identifierChain: [{name: 'a'}], + tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 26, last_column: 29}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, + identifierChain: [{name: 'boo'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 7, last_column: 10}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 11, last_column: 12}, + identifierChain: [{name: 'b'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 3, last_line: 3, first_column: 7, last_column: 10}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'column', + location: {first_line: 3, last_line: 3, first_column: 11, last_column: 12}, + identifierChain: [{name: 'c'}], + tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 7, last_column: 10}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 4, last_line: 4, first_column: 11, last_column: 15}, + identifierChain: [{name: 'blue'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 21, last_column: 24}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'column', + location: {first_line: 4, last_line: 4, first_column: 25, last_column: 26}, + identifierChain: [{name: 'd'}], + tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 7, last_column: 10}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 11, last_column: 12}, + identifierChain: [{name: 'e'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'database', + location: {first_line: 6, last_line: 6, first_column: 8, last_column: 11}, + identifierChain: [{name: 'db1'}], + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 12, last_column: 15}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'alias', + source: 'table', + alias: 'boo', + location: {first_line: 6, last_line: 6, first_column: 16, last_column: 19}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 21, last_column: 24}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'alias', + source: 'table', + alias: 'baa', + location: {first_line: 6, last_line: 6, first_column: 25, last_column: 28}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 6, last_line: 6, first_column: 29, last_column: 67}, + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 35, last_column: 38}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 6, last_line: 6, first_column: 39, last_column: 42}, + identifierChain: [{name: 'bla'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, + subquery: true, + }, + { + type: 'column', + location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, + identifierChain: [{name: 'ble'}], + tables: [{identifierChain: [{name: 'bla'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 63, last_column: 66}, + identifierChain: [{name: 'bla'}], + }, + { + type: 'whereClause', + subquery: true, + missing: true, + location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, + }, + { + type: 'limitClause', + subquery: true, + missing: true, + location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 6, last_line: 6, first_column: 67, last_column: 67}, + }, + ], + }); + }, +); + +it('should report locations for "SELECT tta.* FROM testTableA tta, testTableB; |"', () => { + assertLocations({ + beforeCursor: 'SELECT tta.* FROM testTableA tta, testTableB; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 45}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, + identifierChain: [{name: 'testTableA'}], + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, + tables: [{alias: 'tta', identifierChain: [{name: 'testTableA'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 29}, + identifierChain: [{name: 'testTableA'}], + }, + { + type: 'alias', + source: 'table', + alias: 'tta', + location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, + identifierChain: [{name: 'testTableA'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 35, last_column: 45}, + identifierChain: [{name: 'testTableB'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, + }, + ], + }); +}); + +it('should report locations for "SELECT COUNT(*) FROM testTable; |"', () => { + assertLocations({ + beforeCursor: 'SELECT COUNT(*) FROM testTable;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 31}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 16}, + }, + { + type: 'function', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 12}, + function: 'count', + }, + { + type: 'functionArgument', + location: {first_line: 1, last_line: 1, first_column: 14, last_column: 15}, + function: 'count', + argumentPosition: 0, + identifierChain: [{name: 'count'}], + expression: {text: '*'}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 22, last_column: 31}, + identifierChain: [{name: 'testTable'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + }, + ], + }); +}); + +// prettier-ignore-end diff --git a/src/autocomplete/parsers/generic/genericAutocompleteParser.locations.test.js b/src/autocomplete/parsers/generic/genericAutocompleteParser.locations.test.js deleted file mode 100644 index 34bb5704..00000000 --- a/src/autocomplete/parsers/generic/genericAutocompleteParser.locations.test.js +++ /dev/null @@ -1,1347 +0,0 @@ -// Licensed to Cloudera, Inc. under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. Cloudera, Inc. licenses this file -// to you under the Apache License, Version 2.0 (the -// 'License'); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Please note that the code below is the modified code distributed on the terms, mentioned below. -// The copyright for the changes belongs to YANDEX LLC. -// -// Copyright 2023 YANDEX LLC -// -// Licensed under the Apache License, Version 2.0 (the "License") -// You may not use this file except in compliance with the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software distributed under -// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -// either express or implied. See the License for the specific language governing permissions -// and limitations under the License. - -import {beforeAll, describe, expect, it} from '@jest/globals'; - -import {genericAutocompleteParser} from './genericAutocompleteParser'; - -// prettier-ignore-start - -describe('genericAutocompleteParser.js locations', () => { - beforeAll(() => { - genericAutocompleteParser.yy.parseError = function (msg) { - throw Error(msg); - }; - }); - - const assertAutoComplete = (testDefinition) => { - const debug = false; - expect( - genericAutocompleteParser.parseSql( - testDefinition.beforeCursor, - testDefinition.afterCursor, - debug, - ), - ).toEqualDefinition(testDefinition); - }; - - const assertLocations = function (options) { - assertAutoComplete({ - beforeCursor: options.beforeCursor, - afterCursor: options.afterCursor || '', - locationsOnly: true, - noErrors: true, - expectedLocations: options.expectedLocations, - expectedDefinitions: options.expectedDefinitions, - }); - }; - - it('should report locations for "select cos(1) as foo from customers order by foo;"', () => { - assertLocations({ - beforeCursor: 'select cos(1) as foo from customers order by foo; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 49}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 21}, - }, - { - type: 'function', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - function: 'cos', - }, - { - type: 'functionArgument', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, - function: 'cos', - argumentPosition: 0, - identifierChain: [{name: 'cos'}], - expression: {types: ['NUMBER'], text: '1'}, - }, - { - type: 'alias', - source: 'column', - alias: 'foo', - location: {first_line: 1, last_line: 1, first_column: 18, last_column: 21}, - parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 27, last_column: 36}, - identifierChain: [{name: 'customers'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 36, last_column: 36}, - }, - { - type: 'alias', - location: {first_line: 1, last_line: 1, first_column: 46, last_column: 49}, - alias: 'foo', - source: 'column', - parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 49, last_column: 49}, - }, - ], - }); - }); - - it('should report locations for "WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; |"', () => { - assertLocations({ - beforeCursor: 'WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 50}, - }, - { - type: 'alias', - source: 'cte', - alias: 'boo', - location: {first_line: 1, last_line: 1, first_column: 6, last_column: 9}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, - subquery: true, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, - tables: [{identifierChain: [{name: 'tbl'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 28, last_column: 31}, - identifierChain: [{name: 'tbl'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - subquery: true, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - subquery: true, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, - tables: [{identifierChain: [{name: 'boo'}]}], - }, - { - type: 'alias', - target: 'cte', - alias: 'boo', - location: {first_line: 1, last_line: 1, first_column: 47, last_column: 50}, - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, - }, - ], - }); - }); - - it('should report locations for "SELECT * FROM testTable1 JOIN db1.table2; |"', () => { - assertLocations({ - beforeCursor: 'SELECT * FROM testTable1 JOIN db1.table2; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 41}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - tables: [ - {identifierChain: [{name: 'testTable1'}]}, - {identifierChain: [{name: 'db1'}, {name: 'table2'}]}, - ], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 25}, - identifierChain: [{name: 'testTable1'}], - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 34}, - identifierChain: [{name: 'db1'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 35, last_column: 41}, - identifierChain: [{name: 'db1'}, {name: 'table2'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, - }, - ], - }); - }); - - it('should report locations for "SELECT a.col FROM db.tbl a; |"', () => { - assertLocations({ - beforeCursor: 'SELECT a.col FROM db.tbl a; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 27}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 10, last_column: 13}, - identifierChain: [{name: 'col'}], - tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], - qualified: true, - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 21}, - identifierChain: [{name: 'db'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 22, last_column: 25}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'alias', - source: 'table', - alias: 'a', - location: {first_line: 1, last_line: 1, first_column: 26, last_column: 27}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, - }, - ], - }); - }); - - it('should report locations for "SELECT tbl.col FROM db.tbl a; |"', () => { - assertLocations({ - beforeCursor: 'SELECT tbl.col FROM db.tbl a; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 29}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 15}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, - identifierChain: [{name: 'tbl'}], - tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], - qualified: false, - }, - { - type: 'complex', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 15}, - identifierChain: [{name: 'tbl'}, {name: 'col'}], - tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], - qualified: true, - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 23}, - identifierChain: [{name: 'db'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 24, last_column: 27}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'alias', - source: 'table', - alias: 'a', - location: {first_line: 1, last_line: 1, first_column: 28, last_column: 29}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, - }, - ], - }); - }); - - it('should report locations for "select x from x;"', () => { - assertLocations({ - beforeCursor: 'select x from x;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - ], - }); - }); - - it('should report locations for "select x from x;select y from y;"', () => { - assertLocations({ - beforeCursor: 'select x from x;select y from y;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 17, last_column: 32}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, - identifierChain: [{name: 'y'}], - tables: [{identifierChain: [{name: 'y'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 32}, - identifierChain: [{name: 'y'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, - }, - ], - }); - }); - - it('should report locations for "-- comment\nselect x from x;\n\n\nselect y from y;"', () => { - assertLocations({ - beforeCursor: '-- comment\nselect x from x;\n\n\nselect y from y;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 2, first_column: 1, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, - }, - { - type: 'statement', - location: {first_line: 2, last_line: 5, first_column: 17, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, - identifierChain: [{name: 'y'}], - tables: [{identifierChain: [{name: 'y'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 15, last_column: 16}, - identifierChain: [{name: 'y'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, - }, - ], - }); - }); - - it('should report locations for "select x from x, y;"', () => { - assertLocations({ - beforeCursor: 'select x from x, y;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 19}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}, {identifierChain: [{name: 'y'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 18, last_column: 19}, - identifierChain: [{name: 'y'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, - }, - ], - }); - }); - - it('should report locations for "SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;|"', () => { - assertLocations({ - beforeCursor: 'SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 63}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 17}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - identifierChain: [{name: 'testTable3'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 11, last_column: 13}, - identifierChain: [{name: 'id'}], - tables: [{identifierChain: [{name: 'testTable3'}], alias: 't3'}], - qualified: true, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 17}, - identifierChain: [{name: 'id'}], - tables: [ - {identifierChain: [{name: 'testTable1'}]}, - {identifierChain: [{name: 'db'}, {name: 'testTable2'}]}, - {identifierChain: [{name: 'testTable3'}], alias: 't3'}, - ], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 23, last_column: 33}, - identifierChain: [{name: 'testTable1'}], - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 35, last_column: 37}, - identifierChain: [{name: 'db'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 38, last_column: 48}, - identifierChain: [{name: 'db'}, {name: 'testTable2'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 50, last_column: 60}, - identifierChain: [{name: 'testTable3'}], - }, - { - type: 'alias', - source: 'table', - alias: 't3', - location: {first_line: 1, last_line: 1, first_column: 61, last_column: 63}, - identifierChain: [{name: 'testTable3'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, - }, - ], - }); - }); - - it('should report locations for "SELECT * FROM foo WHERE bar IN (1+1, 2+2);|"', () => { - assertLocations({ - beforeCursor: 'SELECT * FROM foo WHERE bar IN (1+1, 2+2);', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 42}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - tables: [{identifierChain: [{name: 'foo'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, - identifierChain: [{name: 'foo'}], - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 42}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, - identifierChain: [{name: 'bar'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 42, last_column: 42}, - }, - ], - }); - }); - - it('should report locations for "SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);|"', () => { - assertLocations({ - beforeCursor: 'SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 48}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - tables: [{identifierChain: [{name: 'foo'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, - identifierChain: [{name: 'foo'}], - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 48}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, - identifierChain: [{name: 'bar'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 33, last_column: 35}, - identifierChain: [{name: 'id'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 43}, - identifierChain: [{name: 'id'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 48, last_column: 48}, - }, - ], - }); - }); - - it( - 'should report locations for "SELECT s07.description, s07.salary, s08.salary,\\r\\n' + - ' s08.salary - s07.salary\\r\\n' + - 'FROM\\r\\n' + - ' sample_07 s07 JOIN sample_08 s08\\r\\n' + - 'ON ( s07.code = s08.code)\\r\\n' + - 'WHERE\\r\\n' + - ' s07.salary < s08.salary\\r\\n' + - 'ORDER BY s08.salary-s07.salary DESC\\r\\n' + - 'LIMIT 1000;|"', - () => { - assertLocations({ - beforeCursor: - 'SELECT s07.description, s07.salary, s08.salary,\r\n' + - ' s08.salary - s07.salary\r\n' + - 'FROM\r\n' + - ' sample_07 s07 JOIN sample_08 s08\r\n' + - 'ON ( s07.code = s08.code)\r\n' + - 'WHERE\r\n' + - ' s07.salary < s08.salary\r\n' + - 'ORDER BY s08.salary-s07.salary DESC\r\n' + - 'LIMIT 1000;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 9, first_column: 1, last_column: 11}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 2, first_column: 8, last_column: 26}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 23}, - identifierChain: [{name: 'description'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 29, last_column: 35}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 37, last_column: 40}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 47}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 3, last_column: 6}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 7, last_column: 13}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 16, last_column: 19}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 20, last_column: 26}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 3, last_column: 12}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'alias', - source: 'table', - alias: 's07', - location: {first_line: 4, last_line: 4, first_column: 13, last_column: 16}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 22, last_column: 31}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'alias', - source: 'table', - alias: 's08', - location: {first_line: 4, last_line: 4, first_column: 32, last_column: 35}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 6, last_column: 9}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 10, last_column: 14}, - identifierChain: [{name: 'code'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 17, last_column: 20}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 21, last_column: 25}, - identifierChain: [{name: 'code'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 6, last_line: 7, first_column: 1, last_column: 26}, - }, - { - type: 'table', - location: {first_line: 7, last_line: 7, first_column: 3, last_column: 6}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 7, last_line: 7, first_column: 7, last_column: 13}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 7, last_line: 7, first_column: 16, last_column: 19}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 7, last_line: 7, first_column: 20, last_column: 26}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 8, last_line: 8, first_column: 10, last_column: 13}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 8, last_line: 8, first_column: 14, last_column: 20}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 8, last_line: 8, first_column: 21, last_column: 24}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 8, last_line: 8, first_column: 25, last_column: 31}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'limitClause', - missing: false, - location: {first_line: 9, last_line: 9, first_column: 1, last_column: 11}, - }, - ], - }); - }, - ); - - it('should handle "select bl from blablabla join (select * from blablabla) s1;', () => { - assertLocations({ - beforeCursor: 'select bl from blablabla join (select * from blablabla) s1;', - afterCursor: '', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 59}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - identifierChain: [{name: 'bl'}], - tables: [{identifierChain: [{name: 'blablabla'}]}, {subQuery: 's1'}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 25}, - identifierChain: [{name: 'blablabla'}], - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, - subquery: true, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, - tables: [{identifierChain: [{name: 'blablabla'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 46, last_column: 55}, - identifierChain: [{name: 'blablabla'}], - }, - { - type: 'whereClause', - subquery: true, - missing: true, - location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, - }, - { - type: 'limitClause', - subquery: true, - missing: true, - location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, - }, - { - type: 'alias', - source: 'subquery', - alias: 's1', - location: {first_line: 1, last_line: 1, first_column: 57, last_column: 59}, - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, - }, - ], - }); - }); - - it( - 'should report locations for "SELECT CASE cos(boo.a) > baa.boo \\n' + - '\\tWHEN baa.b THEN true \\n' + - '\\tWHEN boo.c THEN false \\n' + - '\\tWHEN baa.blue THEN boo.d \\n' + - '\\tELSE baa.e END \\n' + - '\\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);|"', - () => { - assertLocations({ - beforeCursor: - 'SELECT CASE cos(boo.a) > baa.boo \n\tWHEN baa.b THEN true \n\tWHEN boo.c THEN false \n\tWHEN baa.blue THEN boo.d \n\tELSE baa.e END \n\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 6, first_column: 1, last_column: 67}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 5, first_column: 8, last_column: 16}, - }, - { - type: 'function', - location: {first_line: 1, last_line: 1, first_column: 13, last_column: 15}, - function: 'cos', - }, - { - type: 'functionArgument', - location: {first_line: 1, last_line: 1, first_column: 17, last_column: 22}, - function: 'cos', - argumentPosition: 0, - identifierChain: [{name: 'cos'}], - expression: { - types: ['COLREF'], - columnReference: [{name: 'boo'}, {name: 'a'}], - }, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 17, last_column: 20}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, - identifierChain: [{name: 'a'}], - tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 26, last_column: 29}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, - identifierChain: [{name: 'boo'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 7, last_column: 10}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 11, last_column: 12}, - identifierChain: [{name: 'b'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 3, last_line: 3, first_column: 7, last_column: 10}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'column', - location: {first_line: 3, last_line: 3, first_column: 11, last_column: 12}, - identifierChain: [{name: 'c'}], - tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 7, last_column: 10}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 4, last_line: 4, first_column: 11, last_column: 15}, - identifierChain: [{name: 'blue'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 21, last_column: 24}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'column', - location: {first_line: 4, last_line: 4, first_column: 25, last_column: 26}, - identifierChain: [{name: 'd'}], - tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 7, last_column: 10}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 11, last_column: 12}, - identifierChain: [{name: 'e'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'database', - location: {first_line: 6, last_line: 6, first_column: 8, last_column: 11}, - identifierChain: [{name: 'db1'}], - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 12, last_column: 15}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'alias', - source: 'table', - alias: 'boo', - location: {first_line: 6, last_line: 6, first_column: 16, last_column: 19}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 21, last_column: 24}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'alias', - source: 'table', - alias: 'baa', - location: {first_line: 6, last_line: 6, first_column: 25, last_column: 28}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 6, last_line: 6, first_column: 29, last_column: 67}, - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 35, last_column: 38}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 6, last_line: 6, first_column: 39, last_column: 42}, - identifierChain: [{name: 'bla'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, - subquery: true, - }, - { - type: 'column', - location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, - identifierChain: [{name: 'ble'}], - tables: [{identifierChain: [{name: 'bla'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 63, last_column: 66}, - identifierChain: [{name: 'bla'}], - }, - { - type: 'whereClause', - subquery: true, - missing: true, - location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, - }, - { - type: 'limitClause', - subquery: true, - missing: true, - location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 6, last_line: 6, first_column: 67, last_column: 67}, - }, - ], - }); - }, - ); - - it('should report locations for "SELECT tta.* FROM testTableA tta, testTableB; |"', () => { - assertLocations({ - beforeCursor: 'SELECT tta.* FROM testTableA tta, testTableB; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 45}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, - identifierChain: [{name: 'testTableA'}], - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, - tables: [{alias: 'tta', identifierChain: [{name: 'testTableA'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 29}, - identifierChain: [{name: 'testTableA'}], - }, - { - type: 'alias', - source: 'table', - alias: 'tta', - location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, - identifierChain: [{name: 'testTableA'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 35, last_column: 45}, - identifierChain: [{name: 'testTableB'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, - }, - ], - }); - }); - - it('should report locations for "SELECT COUNT(*) FROM testTable; |"', () => { - assertLocations({ - beforeCursor: 'SELECT COUNT(*) FROM testTable;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 31}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 16}, - }, - { - type: 'function', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 12}, - function: 'count', - }, - { - type: 'functionArgument', - location: {first_line: 1, last_line: 1, first_column: 14, last_column: 15}, - function: 'count', - argumentPosition: 0, - identifierChain: [{name: 'count'}], - expression: {text: '*'}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 22, last_column: 31}, - identifierChain: [{name: 'testTable'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - }, - ], - }); - }); -}); - -// prettier-ignore-end diff --git a/src/autocomplete/parsers/generic/grammar/select/locations.test.ts b/src/autocomplete/parsers/generic/grammar/select/locations.test.ts new file mode 100644 index 00000000..64d29ace --- /dev/null +++ b/src/autocomplete/parsers/generic/grammar/select/locations.test.ts @@ -0,0 +1,1346 @@ +// Licensed to Cloudera, Inc. under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. Cloudera, Inc. licenses this file +// to you under the Apache License, Version 2.0 (the +// 'License'); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Please note that the code below is the modified code distributed on the terms, mentioned below. +// The copyright for the changes belongs to YANDEX LLC. +// +// Copyright 2023 YANDEX LLC +// +// Licensed under the Apache License, Version 2.0 (the "License") +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed under +// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. + +import {beforeAll, expect, it} from '@jest/globals'; + +import {TestCase} from '../../../../test/testing'; +import {genericAutocompleteParser} from '../../genericAutocompleteParser'; + +// prettier-ignore-start + +beforeAll(() => { + genericAutocompleteParser.yy.parseError = function (msg: string): void { + throw Error(msg); + }; +}); + +const assertAutoComplete = (testDefinition: TestCase): void => { + const debug = false; + expect( + genericAutocompleteParser.parseSql( + testDefinition.beforeCursor, + testDefinition.afterCursor, + debug, + ), + ).toEqualDefinition(testDefinition); +}; + +const assertLocations = function (options: TestCase): void { + assertAutoComplete({ + beforeCursor: options.beforeCursor, + afterCursor: options.afterCursor || '', + locationsOnly: true, + noErrors: true, + expectedLocations: options.expectedLocations, + expectedDefinitions: options.expectedDefinitions, + }); +}; + +it('should report locations for "select cos(1) as foo from customers order by foo;"', () => { + assertLocations({ + beforeCursor: 'select cos(1) as foo from customers order by foo; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 49}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 21}, + }, + { + type: 'function', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + function: 'cos', + }, + { + type: 'functionArgument', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, + function: 'cos', + argumentPosition: 0, + identifierChain: [{name: 'cos'}], + expression: {types: ['NUMBER'], text: '1'}, + }, + { + type: 'alias', + source: 'column', + alias: 'foo', + location: {first_line: 1, last_line: 1, first_column: 18, last_column: 21}, + parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 27, last_column: 36}, + identifierChain: [{name: 'customers'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 36, last_column: 36}, + }, + { + type: 'alias', + location: {first_line: 1, last_line: 1, first_column: 46, last_column: 49}, + alias: 'foo', + source: 'column', + parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 49, last_column: 49}, + }, + ], + }); +}); + +it('should report locations for "WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; |"', () => { + assertLocations({ + beforeCursor: 'WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 50}, + }, + { + type: 'alias', + source: 'cte', + alias: 'boo', + location: {first_line: 1, last_line: 1, first_column: 6, last_column: 9}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, + subquery: true, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, + tables: [{identifierChain: [{name: 'tbl'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 28, last_column: 31}, + identifierChain: [{name: 'tbl'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + subquery: true, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + subquery: true, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, + tables: [{identifierChain: [{name: 'boo'}]}], + }, + { + type: 'alias', + target: 'cte', + alias: 'boo', + location: {first_line: 1, last_line: 1, first_column: 47, last_column: 50}, + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, + }, + ], + }); +}); + +it('should report locations for "SELECT * FROM testTable1 JOIN db1.table2; |"', () => { + assertLocations({ + beforeCursor: 'SELECT * FROM testTable1 JOIN db1.table2; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 41}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + tables: [ + {identifierChain: [{name: 'testTable1'}]}, + {identifierChain: [{name: 'db1'}, {name: 'table2'}]}, + ], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 25}, + identifierChain: [{name: 'testTable1'}], + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 34}, + identifierChain: [{name: 'db1'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 35, last_column: 41}, + identifierChain: [{name: 'db1'}, {name: 'table2'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, + }, + ], + }); +}); + +it('should report locations for "SELECT a.col FROM db.tbl a; |"', () => { + assertLocations({ + beforeCursor: 'SELECT a.col FROM db.tbl a; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 27}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 10, last_column: 13}, + identifierChain: [{name: 'col'}], + tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], + qualified: true, + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 21}, + identifierChain: [{name: 'db'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 22, last_column: 25}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'alias', + source: 'table', + alias: 'a', + location: {first_line: 1, last_line: 1, first_column: 26, last_column: 27}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, + }, + ], + }); +}); + +it('should report locations for "SELECT tbl.col FROM db.tbl a; |"', () => { + assertLocations({ + beforeCursor: 'SELECT tbl.col FROM db.tbl a; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 29}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 15}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, + identifierChain: [{name: 'tbl'}], + tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], + qualified: false, + }, + { + type: 'complex', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 15}, + identifierChain: [{name: 'tbl'}, {name: 'col'}], + tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], + qualified: true, + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 23}, + identifierChain: [{name: 'db'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 24, last_column: 27}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'alias', + source: 'table', + alias: 'a', + location: {first_line: 1, last_line: 1, first_column: 28, last_column: 29}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, + }, + ], + }); +}); + +it('should report locations for "select x from x;"', () => { + assertLocations({ + beforeCursor: 'select x from x;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + ], + }); +}); + +it('should report locations for "select x from x;select y from y;"', () => { + assertLocations({ + beforeCursor: 'select x from x;select y from y;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 17, last_column: 32}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, + identifierChain: [{name: 'y'}], + tables: [{identifierChain: [{name: 'y'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 32}, + identifierChain: [{name: 'y'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, + }, + ], + }); +}); + +it('should report locations for "-- comment\nselect x from x;\n\n\nselect y from y;"', () => { + assertLocations({ + beforeCursor: '-- comment\nselect x from x;\n\n\nselect y from y;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 2, first_column: 1, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, + }, + { + type: 'statement', + location: {first_line: 2, last_line: 5, first_column: 17, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, + identifierChain: [{name: 'y'}], + tables: [{identifierChain: [{name: 'y'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 15, last_column: 16}, + identifierChain: [{name: 'y'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, + }, + ], + }); +}); + +it('should report locations for "select x from x, y;"', () => { + assertLocations({ + beforeCursor: 'select x from x, y;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 19}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}, {identifierChain: [{name: 'y'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 18, last_column: 19}, + identifierChain: [{name: 'y'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, + }, + ], + }); +}); + +it('should report locations for "SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;|"', () => { + assertLocations({ + beforeCursor: 'SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 63}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 17}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + identifierChain: [{name: 'testTable3'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 11, last_column: 13}, + identifierChain: [{name: 'id'}], + tables: [{identifierChain: [{name: 'testTable3'}], alias: 't3'}], + qualified: true, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 17}, + identifierChain: [{name: 'id'}], + tables: [ + {identifierChain: [{name: 'testTable1'}]}, + {identifierChain: [{name: 'db'}, {name: 'testTable2'}]}, + {identifierChain: [{name: 'testTable3'}], alias: 't3'}, + ], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 23, last_column: 33}, + identifierChain: [{name: 'testTable1'}], + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 35, last_column: 37}, + identifierChain: [{name: 'db'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 38, last_column: 48}, + identifierChain: [{name: 'db'}, {name: 'testTable2'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 50, last_column: 60}, + identifierChain: [{name: 'testTable3'}], + }, + { + type: 'alias', + source: 'table', + alias: 't3', + location: {first_line: 1, last_line: 1, first_column: 61, last_column: 63}, + identifierChain: [{name: 'testTable3'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, + }, + ], + }); +}); + +it('should report locations for "SELECT * FROM foo WHERE bar IN (1+1, 2+2);|"', () => { + assertLocations({ + beforeCursor: 'SELECT * FROM foo WHERE bar IN (1+1, 2+2);', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 42}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + tables: [{identifierChain: [{name: 'foo'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, + identifierChain: [{name: 'foo'}], + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 42}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, + identifierChain: [{name: 'bar'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 42, last_column: 42}, + }, + ], + }); +}); + +it('should report locations for "SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);|"', () => { + assertLocations({ + beforeCursor: 'SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 48}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + tables: [{identifierChain: [{name: 'foo'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, + identifierChain: [{name: 'foo'}], + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 48}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, + identifierChain: [{name: 'bar'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 33, last_column: 35}, + identifierChain: [{name: 'id'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 43}, + identifierChain: [{name: 'id'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 48, last_column: 48}, + }, + ], + }); +}); + +it( + 'should report locations for "SELECT s07.description, s07.salary, s08.salary,\\r\\n' + + ' s08.salary - s07.salary\\r\\n' + + 'FROM\\r\\n' + + ' sample_07 s07 JOIN sample_08 s08\\r\\n' + + 'ON ( s07.code = s08.code)\\r\\n' + + 'WHERE\\r\\n' + + ' s07.salary < s08.salary\\r\\n' + + 'ORDER BY s08.salary-s07.salary DESC\\r\\n' + + 'LIMIT 1000;|"', + () => { + assertLocations({ + beforeCursor: + 'SELECT s07.description, s07.salary, s08.salary,\r\n' + + ' s08.salary - s07.salary\r\n' + + 'FROM\r\n' + + ' sample_07 s07 JOIN sample_08 s08\r\n' + + 'ON ( s07.code = s08.code)\r\n' + + 'WHERE\r\n' + + ' s07.salary < s08.salary\r\n' + + 'ORDER BY s08.salary-s07.salary DESC\r\n' + + 'LIMIT 1000;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 9, first_column: 1, last_column: 11}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 2, first_column: 8, last_column: 26}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 23}, + identifierChain: [{name: 'description'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 29, last_column: 35}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 37, last_column: 40}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 47}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 3, last_column: 6}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 7, last_column: 13}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 16, last_column: 19}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 20, last_column: 26}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 3, last_column: 12}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'alias', + source: 'table', + alias: 's07', + location: {first_line: 4, last_line: 4, first_column: 13, last_column: 16}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 22, last_column: 31}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'alias', + source: 'table', + alias: 's08', + location: {first_line: 4, last_line: 4, first_column: 32, last_column: 35}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 6, last_column: 9}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 10, last_column: 14}, + identifierChain: [{name: 'code'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 17, last_column: 20}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 21, last_column: 25}, + identifierChain: [{name: 'code'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 6, last_line: 7, first_column: 1, last_column: 26}, + }, + { + type: 'table', + location: {first_line: 7, last_line: 7, first_column: 3, last_column: 6}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 7, last_line: 7, first_column: 7, last_column: 13}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 7, last_line: 7, first_column: 16, last_column: 19}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 7, last_line: 7, first_column: 20, last_column: 26}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 8, last_line: 8, first_column: 10, last_column: 13}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 8, last_line: 8, first_column: 14, last_column: 20}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 8, last_line: 8, first_column: 21, last_column: 24}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 8, last_line: 8, first_column: 25, last_column: 31}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'limitClause', + missing: false, + location: {first_line: 9, last_line: 9, first_column: 1, last_column: 11}, + }, + ], + }); + }, +); + +it('should handle "select bl from blablabla join (select * from blablabla) s1;', () => { + assertLocations({ + beforeCursor: 'select bl from blablabla join (select * from blablabla) s1;', + afterCursor: '', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 59}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + identifierChain: [{name: 'bl'}], + tables: [{identifierChain: [{name: 'blablabla'}]}, {subQuery: 's1'}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 25}, + identifierChain: [{name: 'blablabla'}], + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, + subquery: true, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, + tables: [{identifierChain: [{name: 'blablabla'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 46, last_column: 55}, + identifierChain: [{name: 'blablabla'}], + }, + { + type: 'whereClause', + subquery: true, + missing: true, + location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, + }, + { + type: 'limitClause', + subquery: true, + missing: true, + location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, + }, + { + type: 'alias', + source: 'subquery', + alias: 's1', + location: {first_line: 1, last_line: 1, first_column: 57, last_column: 59}, + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, + }, + ], + }); +}); + +it( + 'should report locations for "SELECT CASE cos(boo.a) > baa.boo \\n' + + '\\tWHEN baa.b THEN true \\n' + + '\\tWHEN boo.c THEN false \\n' + + '\\tWHEN baa.blue THEN boo.d \\n' + + '\\tELSE baa.e END \\n' + + '\\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);|"', + () => { + assertLocations({ + beforeCursor: + 'SELECT CASE cos(boo.a) > baa.boo \n\tWHEN baa.b THEN true \n\tWHEN boo.c THEN false \n\tWHEN baa.blue THEN boo.d \n\tELSE baa.e END \n\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 6, first_column: 1, last_column: 67}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 5, first_column: 8, last_column: 16}, + }, + { + type: 'function', + location: {first_line: 1, last_line: 1, first_column: 13, last_column: 15}, + function: 'cos', + }, + { + type: 'functionArgument', + location: {first_line: 1, last_line: 1, first_column: 17, last_column: 22}, + function: 'cos', + argumentPosition: 0, + identifierChain: [{name: 'cos'}], + expression: { + types: ['COLREF'], + columnReference: [{name: 'boo'}, {name: 'a'}], + }, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 17, last_column: 20}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, + identifierChain: [{name: 'a'}], + tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 26, last_column: 29}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, + identifierChain: [{name: 'boo'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 7, last_column: 10}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 11, last_column: 12}, + identifierChain: [{name: 'b'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 3, last_line: 3, first_column: 7, last_column: 10}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'column', + location: {first_line: 3, last_line: 3, first_column: 11, last_column: 12}, + identifierChain: [{name: 'c'}], + tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 7, last_column: 10}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 4, last_line: 4, first_column: 11, last_column: 15}, + identifierChain: [{name: 'blue'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 21, last_column: 24}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'column', + location: {first_line: 4, last_line: 4, first_column: 25, last_column: 26}, + identifierChain: [{name: 'd'}], + tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 7, last_column: 10}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 11, last_column: 12}, + identifierChain: [{name: 'e'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'database', + location: {first_line: 6, last_line: 6, first_column: 8, last_column: 11}, + identifierChain: [{name: 'db1'}], + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 12, last_column: 15}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'alias', + source: 'table', + alias: 'boo', + location: {first_line: 6, last_line: 6, first_column: 16, last_column: 19}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 21, last_column: 24}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'alias', + source: 'table', + alias: 'baa', + location: {first_line: 6, last_line: 6, first_column: 25, last_column: 28}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 6, last_line: 6, first_column: 29, last_column: 67}, + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 35, last_column: 38}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 6, last_line: 6, first_column: 39, last_column: 42}, + identifierChain: [{name: 'bla'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, + subquery: true, + }, + { + type: 'column', + location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, + identifierChain: [{name: 'ble'}], + tables: [{identifierChain: [{name: 'bla'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 63, last_column: 66}, + identifierChain: [{name: 'bla'}], + }, + { + type: 'whereClause', + subquery: true, + missing: true, + location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, + }, + { + type: 'limitClause', + subquery: true, + missing: true, + location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 6, last_line: 6, first_column: 67, last_column: 67}, + }, + ], + }); + }, +); + +it('should report locations for "SELECT tta.* FROM testTableA tta, testTableB; |"', () => { + assertLocations({ + beforeCursor: 'SELECT tta.* FROM testTableA tta, testTableB; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 45}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, + identifierChain: [{name: 'testTableA'}], + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, + tables: [{alias: 'tta', identifierChain: [{name: 'testTableA'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 29}, + identifierChain: [{name: 'testTableA'}], + }, + { + type: 'alias', + source: 'table', + alias: 'tta', + location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, + identifierChain: [{name: 'testTableA'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 35, last_column: 45}, + identifierChain: [{name: 'testTableB'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, + }, + ], + }); +}); + +it('should report locations for "SELECT COUNT(*) FROM testTable; |"', () => { + assertLocations({ + beforeCursor: 'SELECT COUNT(*) FROM testTable;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 31}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 16}, + }, + { + type: 'function', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 12}, + function: 'count', + }, + { + type: 'functionArgument', + location: {first_line: 1, last_line: 1, first_column: 14, last_column: 15}, + function: 'count', + argumentPosition: 0, + identifierChain: [{name: 'count'}], + expression: {text: '*'}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 22, last_column: 31}, + identifierChain: [{name: 'testTable'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + }, + ], + }); +}); + +// prettier-ignore-end diff --git a/src/autocomplete/parsers/postgresql/grammar/select/locations.test.ts b/src/autocomplete/parsers/postgresql/grammar/select/locations.test.ts new file mode 100644 index 00000000..7cdd1d1f --- /dev/null +++ b/src/autocomplete/parsers/postgresql/grammar/select/locations.test.ts @@ -0,0 +1,1316 @@ +import {beforeAll, expect, it} from '@jest/globals'; + +import {TestCase} from '../../../../test/testing'; +import {postgresqlAutocompleteParser} from '../../postgresqlAutocompleteParser'; + +// prettier-ignore-start + +beforeAll(() => { + postgresqlAutocompleteParser.yy.parseError = function (msg: string): void { + throw Error(msg); + }; +}); + +const assertAutoComplete = (testDefinition: TestCase): void => { + const debug = false; + expect( + postgresqlAutocompleteParser.parseSql( + testDefinition.beforeCursor, + testDefinition.afterCursor, + debug, + ), + ).toEqualDefinition(testDefinition); +}; + +const assertLocations = function (options: TestCase): void { + assertAutoComplete({ + beforeCursor: options.beforeCursor, + afterCursor: options.afterCursor || '', + locationsOnly: true, + noErrors: true, + expectedLocations: options.expectedLocations, + expectedDefinitions: options.expectedDefinitions, + }); +}; + +it('should report locations for "select cos(1) as foo from customers order by foo;"', () => { + assertLocations({ + beforeCursor: 'select cos(1) as foo from customers order by foo; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 49}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 21}, + }, + { + type: 'function', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + function: 'cos', + }, + { + type: 'functionArgument', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, + function: 'cos', + argumentPosition: 0, + identifierChain: [{name: 'cos'}], + expression: {types: ['NUMBER'], text: '1'}, + }, + { + type: 'alias', + source: 'column', + alias: 'foo', + location: {first_line: 1, last_line: 1, first_column: 18, last_column: 21}, + parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 27, last_column: 36}, + identifierChain: [{name: 'customers'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 36, last_column: 36}, + }, + { + type: 'alias', + location: {first_line: 1, last_line: 1, first_column: 46, last_column: 49}, + alias: 'foo', + source: 'column', + parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 49, last_column: 49}, + }, + ], + }); +}); + +it('should report locations for "WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; |"', () => { + assertLocations({ + beforeCursor: 'WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 50}, + }, + { + type: 'alias', + source: 'cte', + alias: 'boo', + location: {first_line: 1, last_line: 1, first_column: 6, last_column: 9}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, + subquery: true, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, + tables: [{identifierChain: [{name: 'tbl'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 28, last_column: 31}, + identifierChain: [{name: 'tbl'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + subquery: true, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + subquery: true, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, + tables: [{identifierChain: [{name: 'boo'}]}], + }, + { + type: 'alias', + target: 'cte', + alias: 'boo', + location: {first_line: 1, last_line: 1, first_column: 47, last_column: 50}, + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, + }, + ], + }); +}); + +it('should report locations for "SELECT * FROM testTable1 JOIN db1.table2; |"', () => { + assertLocations({ + beforeCursor: 'SELECT * FROM testTable1 JOIN db1.table2; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 41}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + tables: [ + {identifierChain: [{name: 'testTable1'}]}, + {identifierChain: [{name: 'db1'}, {name: 'table2'}]}, + ], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 25}, + identifierChain: [{name: 'testTable1'}], + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 34}, + identifierChain: [{name: 'db1'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 35, last_column: 41}, + identifierChain: [{name: 'db1'}, {name: 'table2'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, + }, + ], + }); +}); + +it('should report locations for "SELECT a.col FROM db.tbl a; |"', () => { + assertLocations({ + beforeCursor: 'SELECT a.col FROM db.tbl a; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 27}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 10, last_column: 13}, + identifierChain: [{name: 'col'}], + tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], + qualified: true, + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 21}, + identifierChain: [{name: 'db'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 22, last_column: 25}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'alias', + source: 'table', + alias: 'a', + location: {first_line: 1, last_line: 1, first_column: 26, last_column: 27}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, + }, + ], + }); +}); + +it('should report locations for "SELECT tbl.col FROM db.tbl a; |"', () => { + assertLocations({ + beforeCursor: 'SELECT tbl.col FROM db.tbl a; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 29}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 15}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, + identifierChain: [{name: 'tbl'}], + tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], + qualified: false, + }, + { + type: 'complex', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 15}, + identifierChain: [{name: 'tbl'}, {name: 'col'}], + tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], + qualified: true, + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 23}, + identifierChain: [{name: 'db'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 24, last_column: 27}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'alias', + source: 'table', + alias: 'a', + location: {first_line: 1, last_line: 1, first_column: 28, last_column: 29}, + identifierChain: [{name: 'db'}, {name: 'tbl'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, + }, + ], + }); +}); + +it('should report locations for "select x from x;"', () => { + assertLocations({ + beforeCursor: 'select x from x;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + ], + }); +}); + +it('should report locations for "select x from x;select y from y;"', () => { + assertLocations({ + beforeCursor: 'select x from x;select y from y;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, + }, + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 17, last_column: 32}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, + identifierChain: [{name: 'y'}], + tables: [{identifierChain: [{name: 'y'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 32}, + identifierChain: [{name: 'y'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, + }, + ], + }); +}); + +it('should report locations for "-- comment\nselect x from x;\n\n\nselect y from y;"', () => { + assertLocations({ + beforeCursor: '-- comment\nselect x from x;\n\n\nselect y from y;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 2, first_column: 1, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, + }, + { + type: 'statement', + location: {first_line: 2, last_line: 5, first_column: 17, last_column: 16}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, + identifierChain: [{name: 'y'}], + tables: [{identifierChain: [{name: 'y'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 15, last_column: 16}, + identifierChain: [{name: 'y'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, + }, + ], + }); +}); + +it('should report locations for "select x from x, y;"', () => { + assertLocations({ + beforeCursor: 'select x from x, y;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 19}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + identifierChain: [{name: 'x'}], + tables: [{identifierChain: [{name: 'x'}]}, {identifierChain: [{name: 'y'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, + identifierChain: [{name: 'x'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 18, last_column: 19}, + identifierChain: [{name: 'y'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, + }, + ], + }); +}); + +it('should report locations for "SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;|"', () => { + assertLocations({ + beforeCursor: 'SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 63}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 17}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + identifierChain: [{name: 'testTable3'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 11, last_column: 13}, + identifierChain: [{name: 'id'}], + tables: [{identifierChain: [{name: 'testTable3'}], alias: 't3'}], + qualified: true, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 17}, + identifierChain: [{name: 'id'}], + tables: [ + {identifierChain: [{name: 'testTable1'}]}, + {identifierChain: [{name: 'db'}, {name: 'testTable2'}]}, + {identifierChain: [{name: 'testTable3'}], alias: 't3'}, + ], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 23, last_column: 33}, + identifierChain: [{name: 'testTable1'}], + }, + { + type: 'database', + location: {first_line: 1, last_line: 1, first_column: 35, last_column: 37}, + identifierChain: [{name: 'db'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 38, last_column: 48}, + identifierChain: [{name: 'db'}, {name: 'testTable2'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 50, last_column: 60}, + identifierChain: [{name: 'testTable3'}], + }, + { + type: 'alias', + source: 'table', + alias: 't3', + location: {first_line: 1, last_line: 1, first_column: 61, last_column: 63}, + identifierChain: [{name: 'testTable3'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, + }, + ], + }); +}); + +it('should report locations for "SELECT * FROM foo WHERE bar IN (1+1, 2+2);|"', () => { + assertLocations({ + beforeCursor: 'SELECT * FROM foo WHERE bar IN (1+1, 2+2);', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 42}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + tables: [{identifierChain: [{name: 'foo'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, + identifierChain: [{name: 'foo'}], + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 42}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, + identifierChain: [{name: 'bar'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 42, last_column: 42}, + }, + ], + }); +}); + +it('should report locations for "SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);|"', () => { + assertLocations({ + beforeCursor: 'SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 48}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, + tables: [{identifierChain: [{name: 'foo'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, + identifierChain: [{name: 'foo'}], + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 48}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, + identifierChain: [{name: 'bar'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 33, last_column: 35}, + identifierChain: [{name: 'id'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 43}, + identifierChain: [{name: 'id'}], + tables: [{identifierChain: [{name: 'foo'}]}], + qualified: false, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 48, last_column: 48}, + }, + ], + }); +}); + +it( + 'should report locations for "SELECT s07.description, s07.salary, s08.salary,\\r\\n' + + ' s08.salary - s07.salary\\r\\n' + + 'FROM\\r\\n' + + ' sample_07 s07 JOIN sample_08 s08\\r\\n' + + 'ON ( s07.code = s08.code)\\r\\n' + + 'WHERE\\r\\n' + + ' s07.salary < s08.salary\\r\\n' + + 'ORDER BY s08.salary-s07.salary DESC\\r\\n' + + 'LIMIT 1000;|"', + () => { + assertLocations({ + beforeCursor: + 'SELECT s07.description, s07.salary, s08.salary,\r\n' + + ' s08.salary - s07.salary\r\n' + + 'FROM\r\n' + + ' sample_07 s07 JOIN sample_08 s08\r\n' + + 'ON ( s07.code = s08.code)\r\n' + + 'WHERE\r\n' + + ' s07.salary < s08.salary\r\n' + + 'ORDER BY s08.salary-s07.salary DESC\r\n' + + 'LIMIT 1000;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 9, first_column: 1, last_column: 11}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 2, first_column: 8, last_column: 26}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 23}, + identifierChain: [{name: 'description'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 29, last_column: 35}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 37, last_column: 40}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 41, last_column: 47}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 3, last_column: 6}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 7, last_column: 13}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 16, last_column: 19}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 20, last_column: 26}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 3, last_column: 12}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'alias', + source: 'table', + alias: 's07', + location: {first_line: 4, last_line: 4, first_column: 13, last_column: 16}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 22, last_column: 31}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'alias', + source: 'table', + alias: 's08', + location: {first_line: 4, last_line: 4, first_column: 32, last_column: 35}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 6, last_column: 9}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 10, last_column: 14}, + identifierChain: [{name: 'code'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 17, last_column: 20}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 21, last_column: 25}, + identifierChain: [{name: 'code'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 6, last_line: 7, first_column: 1, last_column: 26}, + }, + { + type: 'table', + location: {first_line: 7, last_line: 7, first_column: 3, last_column: 6}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 7, last_line: 7, first_column: 7, last_column: 13}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 7, last_line: 7, first_column: 16, last_column: 19}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 7, last_line: 7, first_column: 20, last_column: 26}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 8, last_line: 8, first_column: 10, last_column: 13}, + identifierChain: [{name: 'sample_08'}], + }, + { + type: 'column', + location: {first_line: 8, last_line: 8, first_column: 14, last_column: 20}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 8, last_line: 8, first_column: 21, last_column: 24}, + identifierChain: [{name: 'sample_07'}], + }, + { + type: 'column', + location: {first_line: 8, last_line: 8, first_column: 25, last_column: 31}, + identifierChain: [{name: 'salary'}], + tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], + qualified: true, + }, + { + type: 'limitClause', + missing: false, + location: {first_line: 9, last_line: 9, first_column: 1, last_column: 11}, + }, + ], + }); + }, +); + +it('should handle "select bl from blablabla join (select * from blablabla) s1;', () => { + assertLocations({ + beforeCursor: 'select bl from blablabla join (select * from blablabla) s1;', + afterCursor: '', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 59}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, + identifierChain: [{name: 'bl'}], + tables: [{identifierChain: [{name: 'blablabla'}]}, {subQuery: 's1'}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 16, last_column: 25}, + identifierChain: [{name: 'blablabla'}], + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, + subquery: true, + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, + tables: [{identifierChain: [{name: 'blablabla'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 46, last_column: 55}, + identifierChain: [{name: 'blablabla'}], + }, + { + type: 'whereClause', + subquery: true, + missing: true, + location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, + }, + { + type: 'limitClause', + subquery: true, + missing: true, + location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, + }, + { + type: 'alias', + source: 'subquery', + alias: 's1', + location: {first_line: 1, last_line: 1, first_column: 57, last_column: 59}, + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, + }, + ], + }); +}); + +it( + 'should report locations for "SELECT CASE cos(boo.a) > baa.boo \\n' + + '\\tWHEN baa.b THEN true \\n' + + '\\tWHEN boo.c THEN false \\n' + + '\\tWHEN baa.blue THEN boo.d \\n' + + '\\tELSE baa.e END \\n' + + '\\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);|"', + () => { + assertLocations({ + beforeCursor: + 'SELECT CASE cos(boo.a) > baa.boo \n\tWHEN baa.b THEN true \n\tWHEN boo.c THEN false \n\tWHEN baa.blue THEN boo.d \n\tELSE baa.e END \n\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 6, first_column: 1, last_column: 67}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 5, first_column: 8, last_column: 16}, + }, + { + type: 'function', + location: {first_line: 1, last_line: 1, first_column: 13, last_column: 15}, + function: 'cos', + }, + { + type: 'functionArgument', + location: {first_line: 1, last_line: 1, first_column: 17, last_column: 22}, + function: 'cos', + argumentPosition: 0, + identifierChain: [{name: 'cos'}], + expression: { + types: ['COLREF'], + columnReference: [{name: 'boo'}, {name: 'a'}], + }, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 17, last_column: 20}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, + identifierChain: [{name: 'a'}], + tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 26, last_column: 29}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, + identifierChain: [{name: 'boo'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 2, last_line: 2, first_column: 7, last_column: 10}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 2, last_line: 2, first_column: 11, last_column: 12}, + identifierChain: [{name: 'b'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 3, last_line: 3, first_column: 7, last_column: 10}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'column', + location: {first_line: 3, last_line: 3, first_column: 11, last_column: 12}, + identifierChain: [{name: 'c'}], + tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 7, last_column: 10}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 4, last_line: 4, first_column: 11, last_column: 15}, + identifierChain: [{name: 'blue'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 4, last_line: 4, first_column: 21, last_column: 24}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'column', + location: {first_line: 4, last_line: 4, first_column: 25, last_column: 26}, + identifierChain: [{name: 'd'}], + tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], + qualified: true, + }, + { + type: 'table', + location: {first_line: 5, last_line: 5, first_column: 7, last_column: 10}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 5, last_line: 5, first_column: 11, last_column: 12}, + identifierChain: [{name: 'e'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'database', + location: {first_line: 6, last_line: 6, first_column: 8, last_column: 11}, + identifierChain: [{name: 'db1'}], + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 12, last_column: 15}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'alias', + source: 'table', + alias: 'boo', + location: {first_line: 6, last_line: 6, first_column: 16, last_column: 19}, + identifierChain: [{name: 'db1'}, {name: 'foo'}], + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 21, last_column: 24}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'alias', + source: 'table', + alias: 'baa', + location: {first_line: 6, last_line: 6, first_column: 25, last_column: 28}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'whereClause', + missing: false, + location: {first_line: 6, last_line: 6, first_column: 29, last_column: 67}, + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 35, last_column: 38}, + identifierChain: [{name: 'bar'}], + }, + { + type: 'column', + location: {first_line: 6, last_line: 6, first_column: 39, last_column: 42}, + identifierChain: [{name: 'bla'}], + tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], + qualified: true, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, + subquery: true, + }, + { + type: 'column', + location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, + identifierChain: [{name: 'ble'}], + tables: [{identifierChain: [{name: 'bla'}]}], + qualified: false, + }, + { + type: 'table', + location: {first_line: 6, last_line: 6, first_column: 63, last_column: 66}, + identifierChain: [{name: 'bla'}], + }, + { + type: 'whereClause', + subquery: true, + missing: true, + location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, + }, + { + type: 'limitClause', + subquery: true, + missing: true, + location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 6, last_line: 6, first_column: 67, last_column: 67}, + }, + ], + }); + }, +); + +it('should report locations for "SELECT tta.* FROM testTableA tta, testTableB; |"', () => { + assertLocations({ + beforeCursor: 'SELECT tta.* FROM testTableA tta, testTableB; ', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 45}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, + identifierChain: [{name: 'testTableA'}], + }, + { + type: 'asterisk', + location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, + tables: [{alias: 'tta', identifierChain: [{name: 'testTableA'}]}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 19, last_column: 29}, + identifierChain: [{name: 'testTableA'}], + }, + { + type: 'alias', + source: 'table', + alias: 'tta', + location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, + identifierChain: [{name: 'testTableA'}], + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 35, last_column: 45}, + identifierChain: [{name: 'testTableB'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, + }, + ], + }); +}); + +it('should report locations for "SELECT COUNT(*) FROM testTable; |"', () => { + assertLocations({ + beforeCursor: 'SELECT COUNT(*) FROM testTable;', + expectedLocations: [ + { + type: 'statement', + location: {first_line: 1, last_line: 1, first_column: 1, last_column: 31}, + }, + { + type: 'selectList', + missing: false, + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 16}, + }, + { + type: 'function', + location: {first_line: 1, last_line: 1, first_column: 8, last_column: 12}, + function: 'count', + }, + { + type: 'functionArgument', + location: {first_line: 1, last_line: 1, first_column: 14, last_column: 15}, + function: 'count', + argumentPosition: 0, + identifierChain: [{name: 'count'}], + expression: {text: '*'}, + }, + { + type: 'table', + location: {first_line: 1, last_line: 1, first_column: 22, last_column: 31}, + identifierChain: [{name: 'testTable'}], + }, + { + type: 'whereClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + }, + { + type: 'limitClause', + missing: true, + location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, + }, + ], + }); +}); + +// prettier-ignore-end diff --git a/src/autocomplete/parsers/postgresql/postgresqlAutocompleteParser.locations.test.js b/src/autocomplete/parsers/postgresql/postgresqlAutocompleteParser.locations.test.js deleted file mode 100644 index 543d96c5..00000000 --- a/src/autocomplete/parsers/postgresql/postgresqlAutocompleteParser.locations.test.js +++ /dev/null @@ -1,1317 +0,0 @@ -import {beforeAll, describe, expect, it} from '@jest/globals'; - -import {postgresqlAutocompleteParser} from './postgresqlAutocompleteParser'; - -// prettier-ignore-start - -describe('postgreSqlAutocompleteParser.js locations', () => { - beforeAll(() => { - postgresqlAutocompleteParser.yy.parseError = function (msg) { - throw Error(msg); - }; - }); - - const assertAutoComplete = (testDefinition) => { - const debug = false; - expect( - postgresqlAutocompleteParser.parseSql( - testDefinition.beforeCursor, - testDefinition.afterCursor, - debug, - ), - ).toEqualDefinition(testDefinition); - }; - - const assertLocations = function (options) { - assertAutoComplete({ - beforeCursor: options.beforeCursor, - afterCursor: options.afterCursor || '', - locationsOnly: true, - noErrors: true, - expectedLocations: options.expectedLocations, - expectedDefinitions: options.expectedDefinitions, - }); - }; - - it('should report locations for "select cos(1) as foo from customers order by foo;"', () => { - assertLocations({ - beforeCursor: 'select cos(1) as foo from customers order by foo; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 49}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 21}, - }, - { - type: 'function', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - function: 'cos', - }, - { - type: 'functionArgument', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, - function: 'cos', - argumentPosition: 0, - identifierChain: [{name: 'cos'}], - expression: {types: ['NUMBER'], text: '1'}, - }, - { - type: 'alias', - source: 'column', - alias: 'foo', - location: {first_line: 1, last_line: 1, first_column: 18, last_column: 21}, - parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 27, last_column: 36}, - identifierChain: [{name: 'customers'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 36, last_column: 36}, - }, - { - type: 'alias', - location: {first_line: 1, last_line: 1, first_column: 46, last_column: 49}, - alias: 'foo', - source: 'column', - parentLocation: {first_line: 1, last_line: 1, first_column: 8, last_column: 14}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 49, last_column: 49}, - }, - ], - }); - }); - - it('should report locations for "WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; |"', () => { - assertLocations({ - beforeCursor: 'WITH boo AS (SELECT * FROM tbl) SELECT * FROM boo; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 50}, - }, - { - type: 'alias', - source: 'cte', - alias: 'boo', - location: {first_line: 1, last_line: 1, first_column: 6, last_column: 9}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, - subquery: true, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, - tables: [{identifierChain: [{name: 'tbl'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 28, last_column: 31}, - identifierChain: [{name: 'tbl'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - subquery: true, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - subquery: true, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 40, last_column: 41}, - tables: [{identifierChain: [{name: 'boo'}]}], - }, - { - type: 'alias', - target: 'cte', - alias: 'boo', - location: {first_line: 1, last_line: 1, first_column: 47, last_column: 50}, - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 50, last_column: 50}, - }, - ], - }); - }); - - it('should report locations for "SELECT * FROM testTable1 JOIN db1.table2; |"', () => { - assertLocations({ - beforeCursor: 'SELECT * FROM testTable1 JOIN db1.table2; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 41}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - tables: [ - {identifierChain: [{name: 'testTable1'}]}, - {identifierChain: [{name: 'db1'}, {name: 'table2'}]}, - ], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 25}, - identifierChain: [{name: 'testTable1'}], - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 34}, - identifierChain: [{name: 'db1'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 35, last_column: 41}, - identifierChain: [{name: 'db1'}, {name: 'table2'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 41}, - }, - ], - }); - }); - - it('should report locations for "SELECT a.col FROM db.tbl a; |"', () => { - assertLocations({ - beforeCursor: 'SELECT a.col FROM db.tbl a; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 27}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 10, last_column: 13}, - identifierChain: [{name: 'col'}], - tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], - qualified: true, - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 21}, - identifierChain: [{name: 'db'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 22, last_column: 25}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'alias', - source: 'table', - alias: 'a', - location: {first_line: 1, last_line: 1, first_column: 26, last_column: 27}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 27, last_column: 27}, - }, - ], - }); - }); - - it('should report locations for "SELECT tbl.col FROM db.tbl a; |"', () => { - assertLocations({ - beforeCursor: 'SELECT tbl.col FROM db.tbl a; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 29}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 15}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, - identifierChain: [{name: 'tbl'}], - tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], - qualified: false, - }, - { - type: 'complex', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 15}, - identifierChain: [{name: 'tbl'}, {name: 'col'}], - tables: [{identifierChain: [{name: 'db'}, {name: 'tbl'}], alias: 'a'}], - qualified: true, - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 23}, - identifierChain: [{name: 'db'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 24, last_column: 27}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'alias', - source: 'table', - alias: 'a', - location: {first_line: 1, last_line: 1, first_column: 28, last_column: 29}, - identifierChain: [{name: 'db'}, {name: 'tbl'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 29, last_column: 29}, - }, - ], - }); - }); - - it('should report locations for "select x from x;"', () => { - assertLocations({ - beforeCursor: 'select x from x;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - ], - }); - }); - - it('should report locations for "select x from x;select y from y;"', () => { - assertLocations({ - beforeCursor: 'select x from x;select y from y;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 16}, - }, - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 17, last_column: 32}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 24, last_column: 25}, - identifierChain: [{name: 'y'}], - tables: [{identifierChain: [{name: 'y'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 32}, - identifierChain: [{name: 'y'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 32, last_column: 32}, - }, - ], - }); - }); - - it('should report locations for "-- comment\nselect x from x;\n\n\nselect y from y;"', () => { - assertLocations({ - beforeCursor: '-- comment\nselect x from x;\n\n\nselect y from y;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 2, first_column: 1, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 2, last_line: 2, first_column: 16, last_column: 16}, - }, - { - type: 'statement', - location: {first_line: 2, last_line: 5, first_column: 17, last_column: 16}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 8, last_column: 9}, - identifierChain: [{name: 'y'}], - tables: [{identifierChain: [{name: 'y'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 15, last_column: 16}, - identifierChain: [{name: 'y'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 5, last_line: 5, first_column: 16, last_column: 16}, - }, - ], - }); - }); - - it('should report locations for "select x from x, y;"', () => { - assertLocations({ - beforeCursor: 'select x from x, y;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 19}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - identifierChain: [{name: 'x'}], - tables: [{identifierChain: [{name: 'x'}]}, {identifierChain: [{name: 'y'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 16}, - identifierChain: [{name: 'x'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 18, last_column: 19}, - identifierChain: [{name: 'y'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 19}, - }, - ], - }); - }); - - it('should report locations for "SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;|"', () => { - assertLocations({ - beforeCursor: 'SELECT t3.id, id FROM testTable1, db.testTable2, testTable3 t3;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 63}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 17}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - identifierChain: [{name: 'testTable3'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 11, last_column: 13}, - identifierChain: [{name: 'id'}], - tables: [{identifierChain: [{name: 'testTable3'}], alias: 't3'}], - qualified: true, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 17}, - identifierChain: [{name: 'id'}], - tables: [ - {identifierChain: [{name: 'testTable1'}]}, - {identifierChain: [{name: 'db'}, {name: 'testTable2'}]}, - {identifierChain: [{name: 'testTable3'}], alias: 't3'}, - ], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 23, last_column: 33}, - identifierChain: [{name: 'testTable1'}], - }, - { - type: 'database', - location: {first_line: 1, last_line: 1, first_column: 35, last_column: 37}, - identifierChain: [{name: 'db'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 38, last_column: 48}, - identifierChain: [{name: 'db'}, {name: 'testTable2'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 50, last_column: 60}, - identifierChain: [{name: 'testTable3'}], - }, - { - type: 'alias', - source: 'table', - alias: 't3', - location: {first_line: 1, last_line: 1, first_column: 61, last_column: 63}, - identifierChain: [{name: 'testTable3'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 63, last_column: 63}, - }, - ], - }); - }); - - it('should report locations for "SELECT * FROM foo WHERE bar IN (1+1, 2+2);|"', () => { - assertLocations({ - beforeCursor: 'SELECT * FROM foo WHERE bar IN (1+1, 2+2);', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 42}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - tables: [{identifierChain: [{name: 'foo'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, - identifierChain: [{name: 'foo'}], - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 42}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, - identifierChain: [{name: 'bar'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 42, last_column: 42}, - }, - ], - }); - }); - - it('should report locations for "SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);|"', () => { - assertLocations({ - beforeCursor: 'SELECT * FROM foo WHERE bar IN (id+1-1, id+1-2);', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 48}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 9}, - tables: [{identifierChain: [{name: 'foo'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 15, last_column: 18}, - identifierChain: [{name: 'foo'}], - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 48}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, - identifierChain: [{name: 'bar'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 33, last_column: 35}, - identifierChain: [{name: 'id'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 43}, - identifierChain: [{name: 'id'}], - tables: [{identifierChain: [{name: 'foo'}]}], - qualified: false, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 48, last_column: 48}, - }, - ], - }); - }); - - it( - 'should report locations for "SELECT s07.description, s07.salary, s08.salary,\\r\\n' + - ' s08.salary - s07.salary\\r\\n' + - 'FROM\\r\\n' + - ' sample_07 s07 JOIN sample_08 s08\\r\\n' + - 'ON ( s07.code = s08.code)\\r\\n' + - 'WHERE\\r\\n' + - ' s07.salary < s08.salary\\r\\n' + - 'ORDER BY s08.salary-s07.salary DESC\\r\\n' + - 'LIMIT 1000;|"', - () => { - assertLocations({ - beforeCursor: - 'SELECT s07.description, s07.salary, s08.salary,\r\n' + - ' s08.salary - s07.salary\r\n' + - 'FROM\r\n' + - ' sample_07 s07 JOIN sample_08 s08\r\n' + - 'ON ( s07.code = s08.code)\r\n' + - 'WHERE\r\n' + - ' s07.salary < s08.salary\r\n' + - 'ORDER BY s08.salary-s07.salary DESC\r\n' + - 'LIMIT 1000;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 9, first_column: 1, last_column: 11}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 2, first_column: 8, last_column: 26}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 23}, - identifierChain: [{name: 'description'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 25, last_column: 28}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 29, last_column: 35}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 37, last_column: 40}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 41, last_column: 47}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 3, last_column: 6}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 7, last_column: 13}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 16, last_column: 19}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 20, last_column: 26}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 3, last_column: 12}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'alias', - source: 'table', - alias: 's07', - location: {first_line: 4, last_line: 4, first_column: 13, last_column: 16}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 22, last_column: 31}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'alias', - source: 'table', - alias: 's08', - location: {first_line: 4, last_line: 4, first_column: 32, last_column: 35}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 6, last_column: 9}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 10, last_column: 14}, - identifierChain: [{name: 'code'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 17, last_column: 20}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 21, last_column: 25}, - identifierChain: [{name: 'code'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 6, last_line: 7, first_column: 1, last_column: 26}, - }, - { - type: 'table', - location: {first_line: 7, last_line: 7, first_column: 3, last_column: 6}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 7, last_line: 7, first_column: 7, last_column: 13}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 7, last_line: 7, first_column: 16, last_column: 19}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 7, last_line: 7, first_column: 20, last_column: 26}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 8, last_line: 8, first_column: 10, last_column: 13}, - identifierChain: [{name: 'sample_08'}], - }, - { - type: 'column', - location: {first_line: 8, last_line: 8, first_column: 14, last_column: 20}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_08'}], alias: 's08'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 8, last_line: 8, first_column: 21, last_column: 24}, - identifierChain: [{name: 'sample_07'}], - }, - { - type: 'column', - location: {first_line: 8, last_line: 8, first_column: 25, last_column: 31}, - identifierChain: [{name: 'salary'}], - tables: [{identifierChain: [{name: 'sample_07'}], alias: 's07'}], - qualified: true, - }, - { - type: 'limitClause', - missing: false, - location: {first_line: 9, last_line: 9, first_column: 1, last_column: 11}, - }, - ], - }); - }, - ); - - it('should handle "select bl from blablabla join (select * from blablabla) s1;', () => { - assertLocations({ - beforeCursor: 'select bl from blablabla join (select * from blablabla) s1;', - afterCursor: '', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 59}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 10}, - identifierChain: [{name: 'bl'}], - tables: [{identifierChain: [{name: 'blablabla'}]}, {subQuery: 's1'}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 16, last_column: 25}, - identifierChain: [{name: 'blablabla'}], - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, - subquery: true, - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 39, last_column: 40}, - tables: [{identifierChain: [{name: 'blablabla'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 46, last_column: 55}, - identifierChain: [{name: 'blablabla'}], - }, - { - type: 'whereClause', - subquery: true, - missing: true, - location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, - }, - { - type: 'limitClause', - subquery: true, - missing: true, - location: {first_line: 1, last_line: 1, first_column: 55, last_column: 55}, - }, - { - type: 'alias', - source: 'subquery', - alias: 's1', - location: {first_line: 1, last_line: 1, first_column: 57, last_column: 59}, - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 59, last_column: 59}, - }, - ], - }); - }); - - it( - 'should report locations for "SELECT CASE cos(boo.a) > baa.boo \\n' + - '\\tWHEN baa.b THEN true \\n' + - '\\tWHEN boo.c THEN false \\n' + - '\\tWHEN baa.blue THEN boo.d \\n' + - '\\tELSE baa.e END \\n' + - '\\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);|"', - () => { - assertLocations({ - beforeCursor: - 'SELECT CASE cos(boo.a) > baa.boo \n\tWHEN baa.b THEN true \n\tWHEN boo.c THEN false \n\tWHEN baa.blue THEN boo.d \n\tELSE baa.e END \n\t FROM db1.foo boo, bar baa WHERE baa.bla IN (SELECT ble FROM bla);', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 6, first_column: 1, last_column: 67}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 5, first_column: 8, last_column: 16}, - }, - { - type: 'function', - location: {first_line: 1, last_line: 1, first_column: 13, last_column: 15}, - function: 'cos', - }, - { - type: 'functionArgument', - location: {first_line: 1, last_line: 1, first_column: 17, last_column: 22}, - function: 'cos', - argumentPosition: 0, - identifierChain: [{name: 'cos'}], - expression: { - types: ['COLREF'], - columnReference: [{name: 'boo'}, {name: 'a'}], - }, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 17, last_column: 20}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 21, last_column: 22}, - identifierChain: [{name: 'a'}], - tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 26, last_column: 29}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, - identifierChain: [{name: 'boo'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 2, last_line: 2, first_column: 7, last_column: 10}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 2, last_line: 2, first_column: 11, last_column: 12}, - identifierChain: [{name: 'b'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 3, last_line: 3, first_column: 7, last_column: 10}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'column', - location: {first_line: 3, last_line: 3, first_column: 11, last_column: 12}, - identifierChain: [{name: 'c'}], - tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 7, last_column: 10}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 4, last_line: 4, first_column: 11, last_column: 15}, - identifierChain: [{name: 'blue'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 4, last_line: 4, first_column: 21, last_column: 24}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'column', - location: {first_line: 4, last_line: 4, first_column: 25, last_column: 26}, - identifierChain: [{name: 'd'}], - tables: [{identifierChain: [{name: 'db1'}, {name: 'foo'}], alias: 'boo'}], - qualified: true, - }, - { - type: 'table', - location: {first_line: 5, last_line: 5, first_column: 7, last_column: 10}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 5, last_line: 5, first_column: 11, last_column: 12}, - identifierChain: [{name: 'e'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'database', - location: {first_line: 6, last_line: 6, first_column: 8, last_column: 11}, - identifierChain: [{name: 'db1'}], - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 12, last_column: 15}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'alias', - source: 'table', - alias: 'boo', - location: {first_line: 6, last_line: 6, first_column: 16, last_column: 19}, - identifierChain: [{name: 'db1'}, {name: 'foo'}], - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 21, last_column: 24}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'alias', - source: 'table', - alias: 'baa', - location: {first_line: 6, last_line: 6, first_column: 25, last_column: 28}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'whereClause', - missing: false, - location: {first_line: 6, last_line: 6, first_column: 29, last_column: 67}, - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 35, last_column: 38}, - identifierChain: [{name: 'bar'}], - }, - { - type: 'column', - location: {first_line: 6, last_line: 6, first_column: 39, last_column: 42}, - identifierChain: [{name: 'bla'}], - tables: [{identifierChain: [{name: 'bar'}], alias: 'baa'}], - qualified: true, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, - subquery: true, - }, - { - type: 'column', - location: {first_line: 6, last_line: 6, first_column: 54, last_column: 57}, - identifierChain: [{name: 'ble'}], - tables: [{identifierChain: [{name: 'bla'}]}], - qualified: false, - }, - { - type: 'table', - location: {first_line: 6, last_line: 6, first_column: 63, last_column: 66}, - identifierChain: [{name: 'bla'}], - }, - { - type: 'whereClause', - subquery: true, - missing: true, - location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, - }, - { - type: 'limitClause', - subquery: true, - missing: true, - location: {first_line: 6, last_line: 6, first_column: 66, last_column: 66}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 6, last_line: 6, first_column: 67, last_column: 67}, - }, - ], - }); - }, - ); - - it('should report locations for "SELECT tta.* FROM testTableA tta, testTableB; |"', () => { - assertLocations({ - beforeCursor: 'SELECT tta.* FROM testTableA tta, testTableB; ', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 45}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 13}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 11}, - identifierChain: [{name: 'testTableA'}], - }, - { - type: 'asterisk', - location: {first_line: 1, last_line: 1, first_column: 12, last_column: 13}, - tables: [{alias: 'tta', identifierChain: [{name: 'testTableA'}]}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 19, last_column: 29}, - identifierChain: [{name: 'testTableA'}], - }, - { - type: 'alias', - source: 'table', - alias: 'tta', - location: {first_line: 1, last_line: 1, first_column: 30, last_column: 33}, - identifierChain: [{name: 'testTableA'}], - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 35, last_column: 45}, - identifierChain: [{name: 'testTableB'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 45, last_column: 45}, - }, - ], - }); - }); - - it('should report locations for "SELECT COUNT(*) FROM testTable; |"', () => { - assertLocations({ - beforeCursor: 'SELECT COUNT(*) FROM testTable;', - expectedLocations: [ - { - type: 'statement', - location: {first_line: 1, last_line: 1, first_column: 1, last_column: 31}, - }, - { - type: 'selectList', - missing: false, - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 16}, - }, - { - type: 'function', - location: {first_line: 1, last_line: 1, first_column: 8, last_column: 12}, - function: 'count', - }, - { - type: 'functionArgument', - location: {first_line: 1, last_line: 1, first_column: 14, last_column: 15}, - function: 'count', - argumentPosition: 0, - identifierChain: [{name: 'count'}], - expression: {text: '*'}, - }, - { - type: 'table', - location: {first_line: 1, last_line: 1, first_column: 22, last_column: 31}, - identifierChain: [{name: 'testTable'}], - }, - { - type: 'whereClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - }, - { - type: 'limitClause', - missing: true, - location: {first_line: 1, last_line: 1, first_column: 31, last_column: 31}, - }, - ], - }); - }); -}); - -// prettier-ignore-end diff --git a/src/autocomplete/test/testing.ts b/src/autocomplete/test/testing.ts index 8df9ec28..28679429 100644 --- a/src/autocomplete/test/testing.ts +++ b/src/autocomplete/test/testing.ts @@ -49,18 +49,18 @@ interface ExpectedError { } export interface TestCase { - namePrefix: string; // ex. "should suggest keywords" + namePrefix?: string; // ex. "should suggest keywords" beforeCursor: string; - afterCursor: string; + afterCursor?: string; containsKeywords?: string[]; doesNotContainKeywords?: string[]; containsColRefKeywords?: boolean | string[]; noErrors?: boolean; locationsOnly?: boolean; noLocations?: boolean; - expectedDefinitions: unknown; + expectedDefinitions?: unknown; expectedLocations?: ParseResult['locations']; - expectedResult: { + expectedResult?: { lowerCase?: boolean; locations?: ParseResult['locations']; suggestTables?: { @@ -137,7 +137,7 @@ export function toEqualDefinition( actualResponse.locations ) { const expectedLoc = - testDefinition.expectedLocations || testDefinition.expectedResult.locations; + testDefinition.expectedLocations || testDefinition.expectedResult?.locations; const expectsType = expectedLoc?.some((location) => location.type === 'statementType'); if (!expectsType) { actualResponse.locations = actualResponse.locations.filter( @@ -455,7 +455,7 @@ function createAssertForAutocomplete( ): (testCase: TestCase) => void { return (testCase: TestCase) => { expect( - parser.parseSql(testCase.beforeCursor, testCase.afterCursor, debug), + parser.parseSql(testCase.beforeCursor, testCase.afterCursor || '', debug), ).toEqualDefinition(testCase); }; } @@ -486,7 +486,7 @@ export function runTestCases( testCases.forEach((testCase) => { it(`${testCase.namePrefix} given "${prettyLineBreaks( testCase.beforeCursor, - )}|${prettyLineBreaks(testCase.afterCursor)}"`, () => { + )}|${prettyLineBreaks(testCase.afterCursor || '')}"`, () => { assertTestCase(testCase); }); });