|
@@ -15,109 +15,17 @@
|
|
|
// limitations under the License.
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
import { matchesType } from 'sql/reference/typeUtils';
|
|
import { matchesType } from 'sql/reference/typeUtils';
|
|
|
-import { applyTypeToSuggestions, getSubQuery, suggestKeywords } from 'parse/sql/sqlParseUtils';
|
|
|
|
|
-
|
|
|
|
|
-/**
|
|
|
|
|
- * Calculates the Optimal String Alignment distance between two strings. Returns 0 when the strings are equal and the
|
|
|
|
|
- * distance when not, distances is less than or equal to the length of the longest string.
|
|
|
|
|
- *
|
|
|
|
|
- * @param strA
|
|
|
|
|
- * @param strB
|
|
|
|
|
- * @param [ignoreCase]
|
|
|
|
|
- * @returns {number} The similarity
|
|
|
|
|
- */
|
|
|
|
|
-const stringDistance = (strA, strB, ignoreCase) => {
|
|
|
|
|
- if (ignoreCase) {
|
|
|
|
|
- strA = strA.toLowerCase();
|
|
|
|
|
- strB = strB.toLowerCase();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // TODO: Consider other algorithms for performance
|
|
|
|
|
- const strALength = strA.length;
|
|
|
|
|
- const strBLength = strB.length;
|
|
|
|
|
- if (strALength === 0) {
|
|
|
|
|
- return strBLength;
|
|
|
|
|
- }
|
|
|
|
|
- if (strBLength === 0) {
|
|
|
|
|
- return strALength;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const distances = new Array(strALength);
|
|
|
|
|
-
|
|
|
|
|
- let cost, deletion, insertion, substitution, transposition;
|
|
|
|
|
- for (let i = 0; i <= strALength; i++) {
|
|
|
|
|
- distances[i] = new Array(strBLength);
|
|
|
|
|
- distances[i][0] = i;
|
|
|
|
|
- for (let j = 1; j <= strBLength; j++) {
|
|
|
|
|
- if (!i) {
|
|
|
|
|
- distances[0][j] = j;
|
|
|
|
|
- } else {
|
|
|
|
|
- cost = strA[i - 1] === strB[j - 1] ? 0 : 1;
|
|
|
|
|
- deletion = distances[i - 1][j] + 1;
|
|
|
|
|
- insertion = distances[i][j - 1] + 1;
|
|
|
|
|
- substitution = distances[i - 1][j - 1] + cost;
|
|
|
|
|
- if (deletion <= insertion && deletion <= substitution) {
|
|
|
|
|
- distances[i][j] = deletion;
|
|
|
|
|
- } else if (insertion <= deletion && insertion <= substitution) {
|
|
|
|
|
- distances[i][j] = insertion;
|
|
|
|
|
- } else {
|
|
|
|
|
- distances[i][j] = substitution;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (i > 1 && j > 1 && strA[i] === strB[j - 1] && strA[i - 1] === strB[j]) {
|
|
|
|
|
- transposition = distances[i - 2][j - 2] + cost;
|
|
|
|
|
- if (transposition < distances[i][j]) {
|
|
|
|
|
- distances[i][j] = transposition;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return distances[strALength][strBLength];
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const identifierEquals = (a, b) =>
|
|
|
|
|
- a &&
|
|
|
|
|
- b &&
|
|
|
|
|
- a
|
|
|
|
|
- .replace(/^\s*`/, '')
|
|
|
|
|
- .replace(/`\s*$/, '')
|
|
|
|
|
- .toLowerCase() ===
|
|
|
|
|
- b
|
|
|
|
|
- .replace(/^\s*`/, '')
|
|
|
|
|
- .replace(/`\s*$/, '')
|
|
|
|
|
- .toLowerCase();
|
|
|
|
|
-
|
|
|
|
|
-// endsWith polyfill from hue_utils.js, needed as workers live in their own js environment
|
|
|
|
|
-if (!String.prototype.endsWith) {
|
|
|
|
|
- String.prototype.endsWith = function(searchString, position) {
|
|
|
|
|
- const subjectString = this.toString();
|
|
|
|
|
- if (
|
|
|
|
|
- typeof position !== 'number' ||
|
|
|
|
|
- !isFinite(position) ||
|
|
|
|
|
- Math.floor(position) !== position ||
|
|
|
|
|
- position > subjectString.length
|
|
|
|
|
- ) {
|
|
|
|
|
- position = subjectString.length;
|
|
|
|
|
- }
|
|
|
|
|
- position -= searchString.length;
|
|
|
|
|
- const lastIndex = subjectString.lastIndexOf(searchString, position);
|
|
|
|
|
- return lastIndex !== -1 && lastIndex === position;
|
|
|
|
|
- };
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const equalIgnoreCase = (a, b) => a && b && a.toLowerCase() === b.toLowerCase();
|
|
|
|
|
-
|
|
|
|
|
-const SIMPLE_TABLE_REF_SUGGESTIONS = [
|
|
|
|
|
- 'suggestJoinConditions',
|
|
|
|
|
- 'suggestAggregateFunctions',
|
|
|
|
|
- 'suggestFilters',
|
|
|
|
|
- 'suggestGroupBys',
|
|
|
|
|
- 'suggestOrderBys'
|
|
|
|
|
-];
|
|
|
|
|
|
|
+import {
|
|
|
|
|
+ initSharedAutocomplete,
|
|
|
|
|
+ initSyntaxParser,
|
|
|
|
|
+ identifierEquals,
|
|
|
|
|
+ equalIgnoreCase,
|
|
|
|
|
+ SIMPLE_TABLE_REF_SUGGESTIONS
|
|
|
|
|
+} from 'parse/sql/sqlParseUtils';
|
|
|
|
|
|
|
|
const initSqlParser = function(parser) {
|
|
const initSqlParser = function(parser) {
|
|
|
|
|
+ initSharedAutocomplete(parser);
|
|
|
|
|
+
|
|
|
parser.prepareNewStatement = function() {
|
|
parser.prepareNewStatement = function() {
|
|
|
linkTablePrimaries();
|
|
linkTablePrimaries();
|
|
|
parser.commitLocations();
|
|
parser.commitLocations();
|
|
@@ -374,8 +282,6 @@ const initSqlParser = function(parser) {
|
|
|
parser.suggestKeywords(keywords);
|
|
parser.suggestKeywords(keywords);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- parser.applyTypeToSuggestions = applyTypeToSuggestions.bind(null, parser);
|
|
|
|
|
-
|
|
|
|
|
parser.findCaseType = function(whenThenList) {
|
|
parser.findCaseType = function(whenThenList) {
|
|
|
const types = {};
|
|
const types = {};
|
|
|
whenThenList.caseTypes.forEach(valueExpression => {
|
|
whenThenList.caseTypes.forEach(valueExpression => {
|
|
@@ -1212,8 +1118,6 @@ const initSqlParser = function(parser) {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- parser.getSubQuery = getSubQuery;
|
|
|
|
|
-
|
|
|
|
|
parser.addTablePrimary = function(ref) {
|
|
parser.addTablePrimary = function(ref) {
|
|
|
if (typeof parser.yy.latestTablePrimaries === 'undefined') {
|
|
if (typeof parser.yy.latestTablePrimaries === 'undefined') {
|
|
|
parser.yy.latestTablePrimaries = [];
|
|
parser.yy.latestTablePrimaries = [];
|
|
@@ -1342,8 +1246,6 @@ const initSqlParser = function(parser) {
|
|
|
return result;
|
|
return result;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- parser.suggestKeywords = suggestKeywords.bind(null, parser);
|
|
|
|
|
-
|
|
|
|
|
parser.suggestColRefKeywords = function(colRefKeywords) {
|
|
parser.suggestColRefKeywords = function(colRefKeywords) {
|
|
|
parser.yy.result.suggestColRefKeywords = colRefKeywords;
|
|
parser.yy.result.suggestColRefKeywords = colRefKeywords;
|
|
|
};
|
|
};
|
|
@@ -1427,80 +1329,6 @@ const initSqlParser = function(parser) {
|
|
|
parser.yy.result.suggestTables = details || {};
|
|
parser.yy.result.suggestTables = details || {};
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- const adjustLocationForCursor = function(location) {
|
|
|
|
|
- // columns are 0-based and lines not, so add 1 to cols
|
|
|
|
|
- const newLocation = {
|
|
|
|
|
- first_line: location.first_line,
|
|
|
|
|
- last_line: location.last_line,
|
|
|
|
|
- first_column: location.first_column + 1,
|
|
|
|
|
- last_column: location.last_column + 1
|
|
|
|
|
- };
|
|
|
|
|
- if (parser.yy.cursorFound) {
|
|
|
|
|
- if (
|
|
|
|
|
- parser.yy.cursorFound.first_line === newLocation.first_line &&
|
|
|
|
|
- parser.yy.cursorFound.last_column <= newLocation.first_column
|
|
|
|
|
- ) {
|
|
|
|
|
- let additionalSpace = parser.yy.partialLengths.left + parser.yy.partialLengths.right;
|
|
|
|
|
- additionalSpace -= parser.yy.partialCursor ? 1 : 3; // For some reason the normal cursor eats 3 positions.
|
|
|
|
|
- newLocation.first_column = newLocation.first_column + additionalSpace;
|
|
|
|
|
- newLocation.last_column = newLocation.last_column + additionalSpace;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return newLocation;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addFunctionLocation = function(location, functionName) {
|
|
|
|
|
- // Remove trailing '(' from location
|
|
|
|
|
- const adjustedLocation = {
|
|
|
|
|
- first_line: location.first_line,
|
|
|
|
|
- last_line: location.last_line,
|
|
|
|
|
- first_column: location.first_column,
|
|
|
|
|
- last_column: location.last_column - 1
|
|
|
|
|
- };
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'function',
|
|
|
|
|
- location: adjustLocationForCursor(adjustedLocation),
|
|
|
|
|
- function: functionName.toLowerCase()
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addStatementLocation = function(location) {
|
|
|
|
|
- // Don't report lonely cursor as a statement
|
|
|
|
|
- if (
|
|
|
|
|
- location.first_line === location.last_line &&
|
|
|
|
|
- Math.abs(location.last_column - location.first_column) === 1
|
|
|
|
|
- ) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- let adjustedLocation;
|
|
|
|
|
- if (
|
|
|
|
|
- parser.yy.cursorFound &&
|
|
|
|
|
- parser.yy.cursorFound.last_line === location.last_line &&
|
|
|
|
|
- parser.yy.cursorFound.first_column >= location.first_column &&
|
|
|
|
|
- parser.yy.cursorFound.last_column <= location.last_column
|
|
|
|
|
- ) {
|
|
|
|
|
- const additionalSpace = parser.yy.partialLengths.left + parser.yy.partialLengths.right;
|
|
|
|
|
- adjustedLocation = {
|
|
|
|
|
- first_line: location.first_line,
|
|
|
|
|
- last_line: location.last_line,
|
|
|
|
|
- first_column: location.first_column + 1,
|
|
|
|
|
- last_column: location.last_column + additionalSpace - (parser.yy.partialCursor ? 0 : 2)
|
|
|
|
|
- };
|
|
|
|
|
- } else {
|
|
|
|
|
- adjustedLocation = {
|
|
|
|
|
- first_line: location.first_line,
|
|
|
|
|
- last_line: location.last_line,
|
|
|
|
|
- first_column: location.first_column + 1,
|
|
|
|
|
- last_column: location.last_column + 1
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'statement',
|
|
|
|
|
- location: adjustedLocation
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
parser.firstDefined = function() {
|
|
parser.firstDefined = function() {
|
|
|
for (let i = 0; i + 1 < arguments.length; i += 2) {
|
|
for (let i = 0; i + 1 < arguments.length; i += 2) {
|
|
|
if (arguments[i]) {
|
|
if (arguments[i]) {
|
|
@@ -1509,295 +1337,6 @@ const initSqlParser = function(parser) {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- parser.addClauseLocation = function(type, precedingLocation, locationIfPresent, isCursor) {
|
|
|
|
|
- let location;
|
|
|
|
|
- if (isCursor) {
|
|
|
|
|
- if (parser.yy.partialLengths.left === 0 && parser.yy.partialLengths.right === 0) {
|
|
|
|
|
- location = {
|
|
|
|
|
- type: type,
|
|
|
|
|
- missing: true,
|
|
|
|
|
- location: adjustLocationForCursor({
|
|
|
|
|
- first_line: precedingLocation.last_line,
|
|
|
|
|
- first_column: precedingLocation.last_column,
|
|
|
|
|
- last_line: precedingLocation.last_line,
|
|
|
|
|
- last_column: precedingLocation.last_column
|
|
|
|
|
- })
|
|
|
|
|
- };
|
|
|
|
|
- } else {
|
|
|
|
|
- location = {
|
|
|
|
|
- type: type,
|
|
|
|
|
- missing: false,
|
|
|
|
|
- location: {
|
|
|
|
|
- first_line: locationIfPresent.last_line,
|
|
|
|
|
- first_column: locationIfPresent.last_column - 1,
|
|
|
|
|
- last_line: locationIfPresent.last_line,
|
|
|
|
|
- last_column:
|
|
|
|
|
- locationIfPresent.last_column -
|
|
|
|
|
- 1 +
|
|
|
|
|
- parser.yy.partialLengths.right +
|
|
|
|
|
- parser.yy.partialLengths.left
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- location = {
|
|
|
|
|
- type: type,
|
|
|
|
|
- missing: !locationIfPresent,
|
|
|
|
|
- location: adjustLocationForCursor(
|
|
|
|
|
- locationIfPresent || {
|
|
|
|
|
- first_line: precedingLocation.last_line,
|
|
|
|
|
- first_column: precedingLocation.last_column,
|
|
|
|
|
- last_line: precedingLocation.last_line,
|
|
|
|
|
- last_column: precedingLocation.last_column
|
|
|
|
|
- }
|
|
|
|
|
- )
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
- if (parser.isInSubquery()) {
|
|
|
|
|
- location.subquery = true;
|
|
|
|
|
- }
|
|
|
|
|
- parser.yy.locations.push(location);
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addStatementTypeLocation = function(identifier, location, additionalText) {
|
|
|
|
|
- // Don't add if already there except for SELECT
|
|
|
|
|
- if (identifier !== 'SELECT' && parser.yy.allLocations) {
|
|
|
|
|
- for (let i = parser.yy.allLocations.length - 1; i >= 0; i--) {
|
|
|
|
|
- if (parser.yy.allLocations[i] && parser.yy.allLocations[i].type === 'statement') {
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- if (parser.yy.allLocations[i] && parser.yy.allLocations[i].type === 'statementType') {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- const loc = {
|
|
|
|
|
- type: 'statementType',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- identifier: identifier
|
|
|
|
|
- };
|
|
|
|
|
- if (typeof additionalText !== 'undefined') {
|
|
|
|
|
- switch (identifier) {
|
|
|
|
|
- case 'ALTER':
|
|
|
|
|
- if (/ALTER\s+VIEW/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'ALTER VIEW';
|
|
|
|
|
- } else {
|
|
|
|
|
- loc.identifier = 'ALTER TABLE';
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
- case 'COMPUTE':
|
|
|
|
|
- loc.identifier = 'COMPUTE STATS';
|
|
|
|
|
- break;
|
|
|
|
|
- case 'CREATE':
|
|
|
|
|
- if (/CREATE\s+VIEW/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'CREATE VIEW';
|
|
|
|
|
- } else if (/CREATE\s+TABLE/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'CREATE TABLE';
|
|
|
|
|
- } else if (/CREATE\s+DATABASE/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'CREATE DATABASE';
|
|
|
|
|
- } else if (/CREATE\s+ROLE/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'CREATE ROLE';
|
|
|
|
|
- } else if (/CREATE\s+FUNCTION/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'CREATE FUNCTION';
|
|
|
|
|
- } else {
|
|
|
|
|
- loc.identifier = 'CREATE TABLE';
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
- case 'DROP':
|
|
|
|
|
- if (/DROP\s+VIEW/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'DROP VIEW';
|
|
|
|
|
- } else if (/DROP\s+TABLE/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'DROP TABLE';
|
|
|
|
|
- } else if (/DROP\s+DATABASE/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'DROP DATABASE';
|
|
|
|
|
- } else if (/DROP\s+ROLE/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'DROP ROLE';
|
|
|
|
|
- } else if (/DROP\s+STATS/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'DROP STATS';
|
|
|
|
|
- } else if (/DROP\s+FUNCTION/i.test(additionalText)) {
|
|
|
|
|
- loc.identifier = 'DROP FUNCTION';
|
|
|
|
|
- } else {
|
|
|
|
|
- loc.identifier = 'DROP TABLE';
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
- case 'INVALIDATE':
|
|
|
|
|
- loc.identifier = 'INVALIDATE METADATA';
|
|
|
|
|
- break;
|
|
|
|
|
- case 'LOAD':
|
|
|
|
|
- loc.identifier = 'LOAD DATA';
|
|
|
|
|
- break;
|
|
|
|
|
- case 'TRUNCATE':
|
|
|
|
|
- loc.identifier = 'TRUNCATE TABLE';
|
|
|
|
|
- break;
|
|
|
|
|
- default:
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- parser.yy.locations.push(loc);
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addFileLocation = function(location, path) {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'file',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- path: path
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addDatabaseLocation = function(location, identifierChain) {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'database',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- identifierChain: identifierChain
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addTableLocation = function(location, identifierChain) {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'table',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- identifierChain: identifierChain
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addColumnAliasLocation = function(location, alias, parentLocation) {
|
|
|
|
|
- const aliasLocation = {
|
|
|
|
|
- type: 'alias',
|
|
|
|
|
- source: 'column',
|
|
|
|
|
- alias: alias,
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- parentLocation: adjustLocationForCursor(parentLocation)
|
|
|
|
|
- };
|
|
|
|
|
- if (
|
|
|
|
|
- parser.yy.locations.length &&
|
|
|
|
|
- parser.yy.locations[parser.yy.locations.length - 1].type === 'column'
|
|
|
|
|
- ) {
|
|
|
|
|
- const closestColumn = parser.yy.locations[parser.yy.locations.length - 1];
|
|
|
|
|
- if (
|
|
|
|
|
- closestColumn.location.first_line === aliasLocation.parentLocation.first_line &&
|
|
|
|
|
- closestColumn.location.last_line === aliasLocation.parentLocation.last_line &&
|
|
|
|
|
- closestColumn.location.first_column === aliasLocation.parentLocation.first_column &&
|
|
|
|
|
- closestColumn.location.last_column === aliasLocation.parentLocation.last_column
|
|
|
|
|
- ) {
|
|
|
|
|
- parser.yy.locations[parser.yy.locations.length - 1].alias = alias;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- parser.yy.locations.push(aliasLocation);
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addTableAliasLocation = function(location, alias, identifierChain) {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'alias',
|
|
|
|
|
- source: 'table',
|
|
|
|
|
- alias: alias,
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- identifierChain: identifierChain
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addSubqueryAliasLocation = function(location, alias) {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'alias',
|
|
|
|
|
- source: 'subquery',
|
|
|
|
|
- alias: alias,
|
|
|
|
|
- location: adjustLocationForCursor(location)
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addAsteriskLocation = function(location, identifierChain) {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'asterisk',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- identifierChain: identifierChain
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addVariableLocation = function(location, value) {
|
|
|
|
|
- if (/\${[^}]*}/.test(value)) {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'variable',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- value: value
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addColumnLocation = function(location, identifierChain) {
|
|
|
|
|
- const isVariable =
|
|
|
|
|
- identifierChain.length && /\${[^}]*}/.test(identifierChain[identifierChain.length - 1].name);
|
|
|
|
|
- if (isVariable) {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'variable',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- value: identifierChain[identifierChain.length - 1].name
|
|
|
|
|
- });
|
|
|
|
|
- } else {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'column',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- identifierChain: identifierChain,
|
|
|
|
|
- qualified: identifierChain.length > 1
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addCteAliasLocation = function(location, alias) {
|
|
|
|
|
- parser.yy.locations.push({
|
|
|
|
|
- type: 'alias',
|
|
|
|
|
- source: 'cte',
|
|
|
|
|
- alias: alias,
|
|
|
|
|
- location: adjustLocationForCursor(location)
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addUnknownLocation = function(location, identifierChain) {
|
|
|
|
|
- const isVariable =
|
|
|
|
|
- identifierChain.length && /\${[^}]*}/.test(identifierChain[identifierChain.length - 1].name);
|
|
|
|
|
- let loc;
|
|
|
|
|
- if (isVariable) {
|
|
|
|
|
- loc = {
|
|
|
|
|
- type: 'variable',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- value: identifierChain[identifierChain.length - 1].name
|
|
|
|
|
- };
|
|
|
|
|
- } else {
|
|
|
|
|
- loc = {
|
|
|
|
|
- type: 'unknown',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- identifierChain: identifierChain,
|
|
|
|
|
- qualified: identifierChain.length > 1
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
- parser.yy.locations.push(loc);
|
|
|
|
|
- return loc;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addNewDatabaseLocation = function(location, identifierChain) {
|
|
|
|
|
- parser.yy.definitions.push({
|
|
|
|
|
- type: 'database',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- identifierChain: identifierChain
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.addNewTableLocation = function(location, identifierChain, colSpec) {
|
|
|
|
|
- const columns = [];
|
|
|
|
|
- if (colSpec) {
|
|
|
|
|
- colSpec.forEach(col => {
|
|
|
|
|
- columns.push({
|
|
|
|
|
- identifierChain: [col.identifier], // TODO: Complex
|
|
|
|
|
- type: col.type,
|
|
|
|
|
- location: adjustLocationForCursor(col.location)
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- parser.yy.definitions.push({
|
|
|
|
|
- type: 'table',
|
|
|
|
|
- location: adjustLocationForCursor(location),
|
|
|
|
|
- identifierChain: identifierChain,
|
|
|
|
|
- columns: columns
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
parser.addColRefToVariableIfExists = function(left, right) {
|
|
parser.addColRefToVariableIfExists = function(left, right) {
|
|
|
if (
|
|
if (
|
|
|
left &&
|
|
left &&
|
|
@@ -2061,377 +1600,7 @@ const initSqlParser = function(parser) {
|
|
|
};
|
|
};
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const SYNTAX_PARSER_NOOP_FUNCTIONS = [
|
|
|
|
|
- 'addAsteriskLocation',
|
|
|
|
|
- 'addClauseLocation',
|
|
|
|
|
- 'addColRefIfExists',
|
|
|
|
|
- 'addColRefToVariableIfExists',
|
|
|
|
|
- 'addColumnAliasLocation',
|
|
|
|
|
- 'addColumnLocation',
|
|
|
|
|
- 'addCommonTableExpressions',
|
|
|
|
|
- 'addCteAliasLocation',
|
|
|
|
|
- 'addDatabaseLocation',
|
|
|
|
|
- 'addFileLocation',
|
|
|
|
|
- 'addFunctionLocation',
|
|
|
|
|
- 'addNewDatabaseLocation',
|
|
|
|
|
- 'addNewTableLocation',
|
|
|
|
|
- 'addStatementLocation',
|
|
|
|
|
- 'addStatementTypeLocation',
|
|
|
|
|
- 'addSubqueryAliasLocation',
|
|
|
|
|
- 'addTableAliasLocation',
|
|
|
|
|
- 'addTableLocation',
|
|
|
|
|
- 'addTablePrimary',
|
|
|
|
|
- 'addUnknownLocation',
|
|
|
|
|
- 'addVariableLocation',
|
|
|
|
|
- 'applyArgumentTypesToSuggestions',
|
|
|
|
|
- 'applyTypeToSuggestions',
|
|
|
|
|
- 'checkForKeywords',
|
|
|
|
|
- 'checkForSelectListKeywords',
|
|
|
|
|
- 'commitLocations',
|
|
|
|
|
- 'firstDefined',
|
|
|
|
|
- 'getSelectListKeywords',
|
|
|
|
|
- 'getSubQuery',
|
|
|
|
|
- 'getValueExpressionKeywords',
|
|
|
|
|
- 'identifyPartials',
|
|
|
|
|
- 'popQueryState',
|
|
|
|
|
- 'prepareNewStatement',
|
|
|
|
|
- 'pushQueryState',
|
|
|
|
|
- 'selectListNoTableSuggest',
|
|
|
|
|
- 'suggestAggregateFunctions',
|
|
|
|
|
- 'suggestAnalyticFunctions',
|
|
|
|
|
- 'suggestColRefKeywords',
|
|
|
|
|
- 'suggestColumns',
|
|
|
|
|
- 'suggestDatabases',
|
|
|
|
|
- 'suggestDdlAndDmlKeywords',
|
|
|
|
|
- 'suggestFileFormats',
|
|
|
|
|
- 'suggestFilters',
|
|
|
|
|
- 'suggestFunctions',
|
|
|
|
|
- 'suggestGroupBys',
|
|
|
|
|
- 'suggestHdfs',
|
|
|
|
|
- 'suggestIdentifiers',
|
|
|
|
|
- 'suggestJoinConditions',
|
|
|
|
|
- 'suggestJoins',
|
|
|
|
|
- 'suggestKeyValues',
|
|
|
|
|
- 'suggestKeywords',
|
|
|
|
|
- 'suggestOrderBys',
|
|
|
|
|
- 'suggestSelectListAliases',
|
|
|
|
|
- 'suggestTables',
|
|
|
|
|
- 'suggestTablesOrColumns',
|
|
|
|
|
- 'suggestValueExpressionKeywords',
|
|
|
|
|
- 'suggestValues',
|
|
|
|
|
- 'valueExpressionSuggest'
|
|
|
|
|
-];
|
|
|
|
|
-
|
|
|
|
|
-const SYNTAX_PARSER_NOOP = function() {};
|
|
|
|
|
-
|
|
|
|
|
-const initSyntaxParser = function(parser) {
|
|
|
|
|
- // Noop functions for compatibility with the autocomplete parser as the grammar is shared
|
|
|
|
|
- SYNTAX_PARSER_NOOP_FUNCTIONS.forEach(noopFn => {
|
|
|
|
|
- parser[noopFn] = SYNTAX_PARSER_NOOP;
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- parser.yy.locations = [{}];
|
|
|
|
|
-
|
|
|
|
|
- parser.determineCase = function(text) {
|
|
|
|
|
- if (!parser.yy.caseDetermined) {
|
|
|
|
|
- parser.yy.lowerCase = text.toLowerCase() === text;
|
|
|
|
|
- parser.yy.caseDetermined = true;
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.getKeywordsForOptionalsLR = function() {
|
|
|
|
|
- return [];
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.mergeSuggestKeywords = function() {
|
|
|
|
|
- return {};
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.getTypeKeywords = function() {
|
|
|
|
|
- return [];
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.getColumnDataTypeKeywords = function() {
|
|
|
|
|
- return [];
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.findCaseType = function() {
|
|
|
|
|
- return { types: ['T'] };
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.expandIdentifierChain = function() {
|
|
|
|
|
- return [];
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.expandLateralViews = function() {
|
|
|
|
|
- return [];
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.createWeightedKeywords = function() {
|
|
|
|
|
- return [];
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.handleQuotedValueWithCursor = function(lexer, yytext, yylloc, quoteChar) {
|
|
|
|
|
- if (yytext.indexOf('\u2020') !== -1 || yytext.indexOf('\u2021') !== -1) {
|
|
|
|
|
- parser.yy.partialCursor = yytext.indexOf('\u2021') !== -1;
|
|
|
|
|
- const cursorIndex = parser.yy.partialCursor
|
|
|
|
|
- ? yytext.indexOf('\u2021')
|
|
|
|
|
- : yytext.indexOf('\u2020');
|
|
|
|
|
- parser.yy.cursorFound = {
|
|
|
|
|
- first_line: yylloc.first_line,
|
|
|
|
|
- last_line: yylloc.last_line,
|
|
|
|
|
- first_column: yylloc.first_column + cursorIndex,
|
|
|
|
|
- last_column: yylloc.first_column + cursorIndex + 1
|
|
|
|
|
- };
|
|
|
|
|
- const remainder = yytext.substring(cursorIndex + 1);
|
|
|
|
|
- const remainingQuotes = (lexer.upcomingInput().match(new RegExp(quoteChar, 'g')) || [])
|
|
|
|
|
- .length;
|
|
|
|
|
- if (remainingQuotes > 0 && (remainingQuotes & 1) !== 0) {
|
|
|
|
|
- parser.yy.missingEndQuote = false;
|
|
|
|
|
- lexer.input();
|
|
|
|
|
- } else {
|
|
|
|
|
- parser.yy.missingEndQuote = true;
|
|
|
|
|
- lexer.unput(remainder);
|
|
|
|
|
- }
|
|
|
|
|
- lexer.popState();
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- return false;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- let lexerModified = false;
|
|
|
|
|
-
|
|
|
|
|
- parser.yy.parseError = function(str, hash) {
|
|
|
|
|
- parser.yy.error = hash;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const IGNORED_EXPECTED = {
|
|
|
|
|
- ';': true,
|
|
|
|
|
- '.': true,
|
|
|
|
|
- EOF: true,
|
|
|
|
|
- UNSIGNED_INTEGER: true,
|
|
|
|
|
- UNSIGNED_INTEGER_E: true,
|
|
|
|
|
- REGULAR_IDENTIFIER: true,
|
|
|
|
|
- CURSOR: true,
|
|
|
|
|
- PARTIAL_CURSOR: true,
|
|
|
|
|
- HDFS_START_QUOTE: true,
|
|
|
|
|
- HDFS_PATH: true,
|
|
|
|
|
- HDFS_END_QUOTE: true,
|
|
|
|
|
- COMPARISON_OPERATOR: true, // TODO: Expand in results when found
|
|
|
|
|
- ARITHMETIC_OPERATOR: true, // TODO: Expand in results when found
|
|
|
|
|
- VARIABLE_REFERENCE: true,
|
|
|
|
|
- BACKTICK: true,
|
|
|
|
|
- VALUE: true,
|
|
|
|
|
- PARTIAL_VALUE: true,
|
|
|
|
|
- SINGLE_QUOTE: true,
|
|
|
|
|
- DOUBLE_QUOTE: true
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const CLEAN_EXPECTED = {
|
|
|
|
|
- BETWEEN_AND: 'AND',
|
|
|
|
|
- OVERWRITE_DIRECTORY: 'OVERWRITE',
|
|
|
|
|
- STORED_AS_DIRECTORIES: 'STORED',
|
|
|
|
|
- LIKE_PARQUET: 'LIKE',
|
|
|
|
|
- PARTITION_VALUE: 'PARTITION'
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.parseSyntax = function(beforeCursor, afterCursor, debug) {
|
|
|
|
|
- parser.yy.caseDetermined = false;
|
|
|
|
|
- parser.yy.error = undefined;
|
|
|
|
|
-
|
|
|
|
|
- parser.yy.latestTablePrimaries = [];
|
|
|
|
|
- parser.yy.subQueries = [];
|
|
|
|
|
- parser.yy.selectListAliases = [];
|
|
|
|
|
- parser.yy.latestTablePrimaries = [];
|
|
|
|
|
-
|
|
|
|
|
- parser.yy.activeDialect = 'hive';
|
|
|
|
|
-
|
|
|
|
|
- // Fix for parser bug when switching lexer states
|
|
|
|
|
- if (!lexerModified) {
|
|
|
|
|
- const originalSetInput = parser.lexer.setInput;
|
|
|
|
|
- parser.lexer.setInput = function(input, yy) {
|
|
|
|
|
- return originalSetInput.bind(parser.lexer)(input, yy);
|
|
|
|
|
- };
|
|
|
|
|
- lexerModified = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // TODO: Find a way around throwing an exception when the parser finds a syntax error
|
|
|
|
|
- try {
|
|
|
|
|
- parser.yy.error = false;
|
|
|
|
|
- parser.parse(beforeCursor + afterCursor);
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- if (debug) {
|
|
|
|
|
- console.warn(err);
|
|
|
|
|
- console.warn(err.stack);
|
|
|
|
|
- console.warn(parser.yy.error);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (
|
|
|
|
|
- parser.yy.error &&
|
|
|
|
|
- (parser.yy.error.loc.last_column < beforeCursor.length ||
|
|
|
|
|
- !beforeCursor.endsWith(parser.yy.error.text))
|
|
|
|
|
- ) {
|
|
|
|
|
- const weightedExpected = [];
|
|
|
|
|
-
|
|
|
|
|
- const addedExpected = {};
|
|
|
|
|
-
|
|
|
|
|
- const isLowerCase =
|
|
|
|
|
- (parser.yy.caseDetermined && parser.yy.lowerCase) ||
|
|
|
|
|
- parser.yy.error.text.toLowerCase() === parser.yy.error.text;
|
|
|
|
|
-
|
|
|
|
|
- if (
|
|
|
|
|
- parser.yy.error.expected.length === 2 &&
|
|
|
|
|
- parser.yy.error.expected.indexOf("';'") !== -1 &&
|
|
|
|
|
- parser.yy.error.expected.indexOf("'EOF'") !== -1
|
|
|
|
|
- ) {
|
|
|
|
|
- parser.yy.error.expected = [];
|
|
|
|
|
- parser.yy.error.expectedStatementEnd = true;
|
|
|
|
|
- return parser.yy.error;
|
|
|
|
|
- }
|
|
|
|
|
- for (let i = 0; i < parser.yy.error.expected.length; i++) {
|
|
|
|
|
- let expected = parser.yy.error.expected[i];
|
|
|
|
|
- // Strip away the surrounding ' chars
|
|
|
|
|
- expected = expected.substring(1, expected.length - 1);
|
|
|
|
|
- // TODO: Only suggest alphanumeric?
|
|
|
|
|
- if (expected === 'REGULAR_IDENTIFIER') {
|
|
|
|
|
- parser.yy.error.expectedIdentifier = true;
|
|
|
|
|
- if (/^<[a-z]+>/.test(parser.yy.error.token)) {
|
|
|
|
|
- const text = '`' + parser.yy.error.text + '`';
|
|
|
|
|
- weightedExpected.push({
|
|
|
|
|
- text: text,
|
|
|
|
|
- distance: stringDistance(parser.yy.error.text, text, true)
|
|
|
|
|
- });
|
|
|
|
|
- parser.yy.error.possibleReserved = true;
|
|
|
|
|
- }
|
|
|
|
|
- } else if (!IGNORED_EXPECTED[expected] && /[a-z_]+/i.test(expected)) {
|
|
|
|
|
- if (/^<[a-z]+>/.test(expected)) {
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- expected = CLEAN_EXPECTED[expected] || expected;
|
|
|
|
|
- if (expected === parser.yy.error.text.toUpperCase()) {
|
|
|
|
|
- // Can happen when the lexer entry for a rule contains multiple words like 'stored' in 'stored as parquet'
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- const text = isLowerCase ? expected.toLowerCase() : expected;
|
|
|
|
|
- if (text && !addedExpected[text]) {
|
|
|
|
|
- addedExpected[text] = true;
|
|
|
|
|
- weightedExpected.push({
|
|
|
|
|
- text: text,
|
|
|
|
|
- distance: stringDistance(parser.yy.error.text, text, true)
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if (weightedExpected.length === 0) {
|
|
|
|
|
- parser.yy.error.expected = [];
|
|
|
|
|
- parser.yy.error.incompleteStatement = true;
|
|
|
|
|
- return parser.yy.error;
|
|
|
|
|
- }
|
|
|
|
|
- weightedExpected.sort((a, b) => {
|
|
|
|
|
- if (a.distance === b.distance) {
|
|
|
|
|
- return a.text.localeCompare(b.text);
|
|
|
|
|
- }
|
|
|
|
|
- return a.distance - b.distance;
|
|
|
|
|
- });
|
|
|
|
|
- parser.yy.error.expected = weightedExpected;
|
|
|
|
|
- parser.yy.error.incompleteStatement = true;
|
|
|
|
|
- return parser.yy.error;
|
|
|
|
|
- } else if (parser.yy.error) {
|
|
|
|
|
- parser.yy.error.expected = [];
|
|
|
|
|
- parser.yy.error.incompleteStatement = true;
|
|
|
|
|
- return parser.yy.error;
|
|
|
|
|
- }
|
|
|
|
|
- return false;
|
|
|
|
|
- };
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const initGlobalSearchParser = function(parser) {
|
|
|
|
|
- parser.identifyPartials = function(beforeCursor, afterCursor) {
|
|
|
|
|
- const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
|
|
|
|
|
- const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
|
|
|
|
|
- return {
|
|
|
|
|
- left: beforeMatch ? beforeMatch[0].length : 0,
|
|
|
|
|
- right: afterMatch ? afterMatch[0].length : 0
|
|
|
|
|
- };
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.mergeFacets = function(a, b) {
|
|
|
|
|
- if (!a.facets) {
|
|
|
|
|
- a.facets = {};
|
|
|
|
|
- }
|
|
|
|
|
- if (!b.facets) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- Object.keys(b.facets).forEach(key => {
|
|
|
|
|
- if (a.facets[key]) {
|
|
|
|
|
- Object.keys(b.facets[key]).forEach(val => {
|
|
|
|
|
- a.facets[key][val.toLowerCase()] = true;
|
|
|
|
|
- });
|
|
|
|
|
- } else {
|
|
|
|
|
- a.facets[key] = b.facets[key];
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.mergeText = function(a, b) {
|
|
|
|
|
- if (!a.text) {
|
|
|
|
|
- a.text = [];
|
|
|
|
|
- }
|
|
|
|
|
- if (!b.text) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- a.text = a.text.concat(b.text);
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.handleQuotedValueWithCursor = function(lexer, yytext, yylloc, quoteChar) {
|
|
|
|
|
- if (yytext.indexOf('\u2020') !== -1 || yytext.indexOf('\u2021') !== -1) {
|
|
|
|
|
- const cursorIndex = yytext.indexOf('\u2020');
|
|
|
|
|
- parser.yy.cursorFound = {
|
|
|
|
|
- first_line: yylloc.first_line,
|
|
|
|
|
- last_line: yylloc.last_line,
|
|
|
|
|
- first_column: yylloc.first_column + cursorIndex,
|
|
|
|
|
- last_column: yylloc.first_column + cursorIndex + 1
|
|
|
|
|
- };
|
|
|
|
|
- const remainder = yytext.substring(cursorIndex + 1);
|
|
|
|
|
- const remainingQuotes = (lexer.upcomingInput().match(new RegExp(quoteChar, 'g')) || [])
|
|
|
|
|
- .length;
|
|
|
|
|
- if (remainingQuotes > 0 && (remainingQuotes & 1) !== 0) {
|
|
|
|
|
- parser.yy.missingEndQuote = false;
|
|
|
|
|
- lexer.input();
|
|
|
|
|
- } else {
|
|
|
|
|
- parser.yy.missingEndQuote = true;
|
|
|
|
|
- lexer.unput(remainder);
|
|
|
|
|
- }
|
|
|
|
|
- lexer.popState();
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- return false;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- parser.parseGlobalSearch = function(beforeCursor, afterCursor, debug) {
|
|
|
|
|
- delete parser.yy.cursorFound;
|
|
|
|
|
-
|
|
|
|
|
- let result;
|
|
|
|
|
- try {
|
|
|
|
|
- result = parser.parse(beforeCursor + '\u2020' + afterCursor);
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- if (debug) {
|
|
|
|
|
- console.warn(err);
|
|
|
|
|
- console.warn(err.stack);
|
|
|
|
|
- console.warn(parser.yy.error);
|
|
|
|
|
- }
|
|
|
|
|
- return {
|
|
|
|
|
- facets: {},
|
|
|
|
|
- text: []
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
- return result;
|
|
|
|
|
- };
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
export default {
|
|
export default {
|
|
|
initSqlParser: initSqlParser,
|
|
initSqlParser: initSqlParser,
|
|
|
- initSyntaxParser: initSyntaxParser,
|
|
|
|
|
- initGlobalSearchParser: initGlobalSearchParser
|
|
|
|
|
|
|
+ initSyntaxParser: initSyntaxParser
|
|
|
};
|
|
};
|