Pārlūkot izejas kodu

HUE-8856 [autocomplete] Use the new parsers in the syntax web worker

Johan Ahlen 6 gadi atpakaļ
vecāks
revīzija
fba02ddf06

+ 0 - 2
desktop/core/src/desktop/js/hue.js

@@ -68,7 +68,6 @@ import EditorViewModel from 'apps/notebook/editorViewModel'; // In history, inde
 import EditorViewModel2 from 'apps/notebook2/editorViewModel'; // In history, indexer, importer, editor etc.
 import HdfsAutocompleter from 'utils/hdfsAutocompleter';
 import SqlAutocompleter from 'sql/sqlAutocompleter';
-import sqlAutocompleteParser from 'parse/sqlAutocompleteParser'; // Notebook and used throughout via hue-simple-ace-editor ko component
 import sqlStatementsParser from 'parse/sqlStatementsParser'; // In search.ko and notebook.ko
 import HueFileEntry from 'doc/hueFileEntry';
 import HueDocument from 'doc/hueDocument';
@@ -110,7 +109,6 @@ window.page = page;
 window.PigFunctions = PigFunctions;
 window.qq = qq;
 window.sprintf = sprintf;
-window.sqlAutocompleteParser = sqlAutocompleteParser;
 window.SqlAutocompleter = SqlAutocompleter;
 window.SqlFunctions = SqlFunctions;
 window.SqlSetOptions = SqlSetOptions;

+ 1 - 6
desktop/core/src/desktop/js/ko/bindings/ko.aceEditor.js

@@ -838,12 +838,7 @@ ko.bindingHandlers.aceEditor = {
         window.clearTimeout(autocompleteThrottle);
         autocompleteThrottle = window.setTimeout(() => {
           const textBeforeCursor = editor.getTextBeforeCursor();
-          let questionMarkMatch;
-          if ($('.hue-ace-autocompleter').length > 0) {
-            questionMarkMatch = textBeforeCursor.match(/select\s+(\? from \S+[^.]\s$)/i);
-          } else {
-            questionMarkMatch = textBeforeCursor.match(/select\s+(\? from \S+[^.]$)/i);
-          }
+          const questionMarkMatch = textBeforeCursor.match(/select\s+(\? from \S+[^.]\s*$)/i);
           if (questionMarkMatch && $('.ace_autocomplete:visible').length === 0) {
             editor.moveCursorTo(
               editor.getCursorPosition().row,

+ 0 - 41
desktop/core/src/desktop/js/parse/spec/sqlTestUtils.js

@@ -14,8 +14,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import sqlAutocompleteParser from 'parse/sqlAutocompleteParser';
-
 // Needed to compare by val without taking attr order into account
 const resultEquals = function(a, b) {
   if (typeof a !== typeof b) {
@@ -290,45 +288,6 @@ const testUtils = {
         }
       };
     }
-  },
-
-  assertAutocomplete: function(testDefinition) {
-    const debug = false;
-    if (typeof testDefinition.dialect === 'undefined') {
-      expect(
-        sqlAutocompleteParser.parseSql(
-          testDefinition.beforeCursor,
-          testDefinition.afterCursor,
-          undefined,
-          debug
-        )
-      ).toEqualDefinition(testDefinition);
-      expect(
-        sqlAutocompleteParser.parseSql(
-          testDefinition.beforeCursor,
-          testDefinition.afterCursor,
-          'hive',
-          debug
-        )
-      ).toEqualDefinition(testDefinition);
-      expect(
-        sqlAutocompleteParser.parseSql(
-          testDefinition.beforeCursor,
-          testDefinition.afterCursor,
-          'impala',
-          debug
-        )
-      ).toEqualDefinition(testDefinition);
-    } else {
-      expect(
-        sqlAutocompleteParser.parseSql(
-          testDefinition.beforeCursor,
-          testDefinition.afterCursor,
-          testDefinition.dialect,
-          debug
-        )
-      ).toEqualDefinition(testDefinition);
-    }
   }
 };
 

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
desktop/core/src/desktop/js/parse/sql/generic/genericSyntaxParser.js


+ 188 - 0
desktop/core/src/desktop/js/parse/sql/generic/spec/genericSyntaxParserSpec.js

@@ -0,0 +1,188 @@
+// 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.
+
+import genericSyntaxParser from '../genericSyntaxParser';
+
+describe('genericSyntaxParser.js', () => {
+  const expectedToStrings = function(expected) {
+    return expected.map(ex => ex.text);
+  };
+
+  it('should not find errors for ""', () => {
+    const result = genericSyntaxParser.parseSyntax('', '');
+    expect(result).toBeFalsy();
+  });
+
+  it('should report incomplete statement for "SEL"', () => {
+    const result = genericSyntaxParser.parseSyntax('SEL', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should report incomplete statement for "SELECT"', () => {
+    const result = genericSyntaxParser.parseSyntax('SELECT', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should report incomplete statement for "SELECT "', () => {
+    const result = genericSyntaxParser.parseSyntax('SELECT ', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should not report incomplete statement for "SELECT * FROM tbl"', () => {
+    const result = genericSyntaxParser.parseSyntax('SELECT * FROM tbl', '');
+    expect(result.incompleteStatement).toBeFalsy();
+  });
+
+  it('should not report incomplete statement for "SELECT * FROM tbl LIMIT 1"', () => {
+    const result = genericSyntaxParser.parseSyntax('SELECT * FROM tbl LIMIT 1', '');
+    expect(result.incompleteStatement).toBeFalsy();
+  });
+
+  it('should report incomplete statement for "SELECT * FROM tbl LIMIT "', () => {
+    const result = genericSyntaxParser.parseSyntax('SELECT * FROM tbl LIMIT ', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should report incomplete statement for "SELECT * FROM tbl GROUP"', () => {
+    const result = genericSyntaxParser.parseSyntax('SELECT * FROM tbl GROUP', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should not find errors for "SELECT *"', () => {
+    const result = genericSyntaxParser.parseSyntax('SELECT *', '');
+    expect(result).toBeFalsy();
+  });
+
+  it('should not report incomplete statement for "SELECT * FR"', () => {
+    const result = genericSyntaxParser.parseSyntax('SELECT * FR', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should find errors for "SLELECT "', () => {
+    const result = genericSyntaxParser.parseSyntax('SLELECT ', '');
+    expect(result).toBeTruthy();
+    expect(result.text).toEqual('SLELECT');
+    expect(result.expected.length).toBeGreaterThan(0);
+    expect(result.loc.first_column).toEqual(0);
+    expect(result.loc.last_column).toEqual(7);
+  });
+
+  it('should find errors for "alter tabel "', () => {
+    const result = genericSyntaxParser.parseSyntax('alter tabel ', '');
+    expect(result).toBeTruthy();
+    expect(result.text).toEqual('tabel');
+    expect(result.expected.length).toBeGreaterThan(0);
+    expect(result.loc.first_column).toEqual(6);
+    expect(result.loc.last_column).toEqual(11);
+  });
+
+  it('should find errors for "select *  form "', () => {
+    const result = genericSyntaxParser.parseSyntax('select *  form ', '');
+    expect(result).toBeTruthy();
+    expect(result.loc.first_column).toEqual(10);
+    expect(result.loc.last_column).toEqual(14);
+    expect(expectedToStrings(result.expected)).toEqual(['from', 'union']);
+  });
+
+  it('should find errors for "select * from customers c cultster by awasd asd afd;"', () => {
+    const result = genericSyntaxParser.parseSyntax(
+      'select * from customers c cultster by awasd asd afd;',
+      ''
+    );
+    expect(result).toBeTruthy();
+  });
+
+  it('should find errors for "select asdf wer qwer qewr   qwer"', () => {
+    const result = genericSyntaxParser.parseSyntax('select asdf wer qwer qewr   qwer', '');
+    expect(result).toBeTruthy();
+  });
+
+  it('should suggest expected words for "SLELECT "', () => {
+    const result = genericSyntaxParser.parseSyntax('SLELECT ', '');
+    expect(result).toBeTruthy();
+    expect(expectedToStrings(result.expected)).toEqual([
+      'SELECT',
+      'SET',
+      'ALTER',
+      'INSERT',
+      'CREATE',
+      'USE',
+      'DROP',
+      'TRUNCATE',
+      'UPDATE',
+      'WITH'
+    ]);
+  });
+
+  it('should suggest expected words for "slelect "', () => {
+    const result = genericSyntaxParser.parseSyntax('slelect ', '');
+    expect(result).toBeTruthy();
+    expect(expectedToStrings(result.expected)).toEqual([
+      'select',
+      'set',
+      'alter',
+      'insert',
+      'create',
+      'use',
+      'drop',
+      'truncate',
+      'update',
+      'with'
+    ]);
+  });
+
+  it('should suggest expected that the statement should end for "use somedb extrastuff "', () => {
+    const result = genericSyntaxParser.parseSyntax('use somedb extrastuff  ', '');
+    expect(result).toBeTruthy();
+    expect(result.expectedStatementEnd).toBeTruthy();
+  });
+
+  const expectEqualIds = function(beforeA, afterA, beforeB, afterB) {
+    const resultA = genericSyntaxParser.parseSyntax(beforeA, afterA);
+    const resultB = genericSyntaxParser.parseSyntax(beforeB, afterB);
+    expect(resultA).toBeTruthy('"' + beforeA + '|' + afterA + '" was not reported as an error');
+    expect(resultB).toBeTruthy('"' + beforeB + '|' + afterB + '" was not reported as an error');
+    expect(resultA.ruleId).toEqual(resultB.ruleId);
+  };
+
+  const expectNonEqualIds = function(beforeA, afterA, beforeB, afterB) {
+    const resultA = genericSyntaxParser.parseSyntax(beforeA, afterA);
+    const resultB = genericSyntaxParser.parseSyntax(beforeB, afterB);
+    expect(resultA).toBeTruthy('"' + beforeA + '|' + afterA + '" was not reported as an error');
+    expect(resultB).toBeTruthy('"' + beforeB + '|' + afterB + '" was not reported as an error');
+    expect(resultA.ruleId).not.toEqual(resultB.ruleId);
+  };
+
+  it('should have unique rule IDs when the same rule is failing in different locations', () => {
+    expectEqualIds('SLELECT ', '', 'dlrop ', '');
+    expectEqualIds('SELECT * FORM ', '', 'SELECT * bla ', '');
+    expectEqualIds('DROP TABLE b.bla ERRROROR ', '', 'DROP TABLE c.cla OTHERERRRRORRR ', '');
+    expectEqualIds(
+      'SELECT * FROM a WHERE id = 1, a b SELECT ',
+      '',
+      'SELECT id, foo FROM a WHERE a b SELECT',
+      ''
+    );
+    expectEqualIds(
+      'SELECT * FROM a WHERE id = 1, a b SELECT ',
+      '',
+      'SELECT id, foo FROM a WHERE a b SELECT',
+      ''
+    );
+
+    expectNonEqualIds('slelect ', '', 'select * form ', '');
+  });
+});

+ 0 - 0
desktop/core/src/desktop/js/parse/spec/sqlParseSupportSpec.js → desktop/core/src/desktop/js/parse/sql/generic/spec/sqlParseSupportSpec.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
desktop/core/src/desktop/js/parse/sql/hive/hiveSyntaxParser.js


+ 89 - 117
desktop/core/src/desktop/js/parse/spec/sqlSyntaxParserSpec.js → desktop/core/src/desktop/js/parse/sql/hive/spec/hiveSyntaxParserSpec.js

@@ -14,65 +14,65 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import sqlSyntaxParser from '../sqlSyntaxParser';
+import hiveSyntaxParser from '../hiveSyntaxParser';
 
-describe('sqlSyntaxParser.js', () => {
+describe('hiveSyntaxParser.js', () => {
   const expectedToStrings = function(expected) {
     return expected.map(ex => ex.text);
   };
 
   it('should not find errors for ""', () => {
-    const result = sqlSyntaxParser.parseSyntax('', '');
+    const result = hiveSyntaxParser.parseSyntax('', '');
     expect(result).toBeFalsy();
   });
 
   it('should report incomplete statement for "SEL"', () => {
-    const result = sqlSyntaxParser.parseSyntax('SEL', '');
+    const result = hiveSyntaxParser.parseSyntax('SEL', '');
     expect(result.incompleteStatement).toBeTruthy();
   });
 
   it('should report incomplete statement for "SELECT"', () => {
-    const result = sqlSyntaxParser.parseSyntax('SELECT', '');
+    const result = hiveSyntaxParser.parseSyntax('SELECT', '');
     expect(result.incompleteStatement).toBeTruthy();
   });
 
   it('should report incomplete statement for "SELECT "', () => {
-    const result = sqlSyntaxParser.parseSyntax('SELECT ', '');
+    const result = hiveSyntaxParser.parseSyntax('SELECT ', '');
     expect(result.incompleteStatement).toBeTruthy();
   });
 
   it('should not report incomplete statement for "SELECT * FROM tbl"', () => {
-    const result = sqlSyntaxParser.parseSyntax('SELECT * FROM tbl', '');
+    const result = hiveSyntaxParser.parseSyntax('SELECT * FROM tbl', '');
     expect(result.incompleteStatement).toBeFalsy();
   });
 
   it('should not report incomplete statement for "SELECT * FROM tbl LIMIT 1"', () => {
-    const result = sqlSyntaxParser.parseSyntax('SELECT * FROM tbl LIMIT 1', '');
+    const result = hiveSyntaxParser.parseSyntax('SELECT * FROM tbl LIMIT 1', '');
     expect(result.incompleteStatement).toBeFalsy();
   });
 
   it('should report incomplete statement for "SELECT * FROM tbl LIMIT "', () => {
-    const result = sqlSyntaxParser.parseSyntax('SELECT * FROM tbl LIMIT ', '');
+    const result = hiveSyntaxParser.parseSyntax('SELECT * FROM tbl LIMIT ', '');
     expect(result.incompleteStatement).toBeTruthy();
   });
 
   it('should report incomplete statement for "SELECT * FROM tbl GROUP"', () => {
-    const result = sqlSyntaxParser.parseSyntax('SELECT * FROM tbl GROUP', '');
+    const result = hiveSyntaxParser.parseSyntax('SELECT * FROM tbl GROUP', '');
     expect(result.incompleteStatement).toBeTruthy();
   });
 
   it('should not find errors for "SELECT *"', () => {
-    const result = sqlSyntaxParser.parseSyntax('SELECT *', '');
+    const result = hiveSyntaxParser.parseSyntax('SELECT *', '');
     expect(result).toBeFalsy();
   });
 
   it('should not report incomplete statement for "SELECT * FR"', () => {
-    const result = sqlSyntaxParser.parseSyntax('SELECT * FR', '');
+    const result = hiveSyntaxParser.parseSyntax('SELECT * FR', '');
     expect(result.incompleteStatement).toBeTruthy();
   });
 
   it('should find errors for "SLELECT "', () => {
-    const result = sqlSyntaxParser.parseSyntax('SLELECT ', '');
+    const result = hiveSyntaxParser.parseSyntax('SLELECT ', '');
     expect(result).toBeTruthy();
     expect(result.text).toEqual('SLELECT');
     expect(result.expected.length).toBeGreaterThan(0);
@@ -81,7 +81,7 @@ describe('sqlSyntaxParser.js', () => {
   });
 
   it('should find errors for "alter tabel "', () => {
-    const result = sqlSyntaxParser.parseSyntax('alter tabel ', '');
+    const result = hiveSyntaxParser.parseSyntax('alter tabel ', '');
     expect(result).toBeTruthy();
     expect(result.text).toEqual('tabel');
     expect(result.expected.length).toBeGreaterThan(0);
@@ -90,23 +90,28 @@ describe('sqlSyntaxParser.js', () => {
   });
 
   it('should find errors for "select *  form "', () => {
-    const result = sqlSyntaxParser.parseSyntax('select *  form ', '');
+    const result = hiveSyntaxParser.parseSyntax('select *  form ', '');
     expect(result).toBeTruthy();
     expect(result.loc.first_column).toEqual(10);
     expect(result.loc.last_column).toEqual(14);
     expect(expectedToStrings(result.expected)).toEqual([
       'from',
+      'sort',
       'group',
       'order',
       'where',
+      'insert',
       'limit',
       'union',
-      'having'
+      'having',
+      'window',
+      'cluster',
+      'distribute'
     ]);
   });
 
   it('should find errors for "select * from customers c cultster by awasd asd afd;"', () => {
-    const result = sqlSyntaxParser.parseSyntax(
+    const result = hiveSyntaxParser.parseSyntax(
       'select * from customers c cultster by awasd asd afd;',
       ''
     );
@@ -114,99 +119,100 @@ describe('sqlSyntaxParser.js', () => {
   });
 
   it('should find errors for "select asdf wer qwer qewr   qwer"', () => {
-    const result = sqlSyntaxParser.parseSyntax('select asdf wer qwer qewr   qwer', '');
-    expect(result).toBeTruthy();
-  });
-
-  it('should find errors for "select * from foo where method = 1;"', () => {
-    const result = sqlSyntaxParser.parseSyntax('select * from foo where method = 1;', '', 'impala');
-    expect(result).toBeTruthy();
-    expect(
-      result.expected.some(expected => {
-        return expected.text === '`method`';
-      })
-    ).toBeTruthy();
-    expect(result.expectedIdentifier).toBeTruthy();
-    expect(result.possibleReserved).toBeTruthy();
-  });
-
-  it('should find errors for "select * from using where a = 1;"', () => {
-    const result = sqlSyntaxParser.parseSyntax('select * from using where a = 1;', '', 'hive');
+    const result = hiveSyntaxParser.parseSyntax('select asdf wer qwer qewr   qwer', '');
     expect(result).toBeTruthy();
-    expect(
-      result.expected.some(expected => {
-        return expected.text === '`using`';
-      })
-    ).toBeTruthy();
-    expect(result.expectedIdentifier).toBeTruthy();
-    expect(result.possibleReserved).toBeTruthy();
   });
 
   it('should suggest expected words for "SLELECT "', () => {
-    const result = sqlSyntaxParser.parseSyntax('SLELECT ', '');
+    const result = hiveSyntaxParser.parseSyntax('SLELECT ', '');
     expect(result).toBeTruthy();
     expect(expectedToStrings(result.expected)).toEqual([
       'SELECT',
+      'DELETE',
       'SET',
       'ALTER',
       'INSERT',
+      'RELOAD',
+      'ABORT',
+      'ANALYZE',
       'CREATE',
+      'EXPLAIN',
+      'EXPORT',
+      'GRANT',
+      'IMPORT',
+      'LOAD',
+      'MERGE',
+      'MSCK',
+      'REVOKE',
       'SHOW',
       'USE',
       'DROP',
       'FROM',
       'TRUNCATE',
       'UPDATE',
-      'WITH'
+      'WITH',
+      'DESCRIBE'
     ]);
   });
 
   it('should suggest expected words for "slelect "', () => {
-    const result = sqlSyntaxParser.parseSyntax('slelect ', '');
+    const result = hiveSyntaxParser.parseSyntax('slelect ', '');
     expect(result).toBeTruthy();
     expect(expectedToStrings(result.expected)).toEqual([
       'select',
+      'delete',
       'set',
       'alter',
       'insert',
+      'reload',
+      'abort',
+      'analyze',
       'create',
+      'explain',
+      'export',
+      'grant',
+      'import',
+      'load',
+      'merge',
+      'msck',
+      'revoke',
       'show',
       'use',
       'drop',
       'from',
       'truncate',
       'update',
-      'with'
+      'with',
+      'describe'
     ]);
   });
 
   it('should suggest expected that the statement should end for "use somedb extrastuff "', () => {
-    const result = sqlSyntaxParser.parseSyntax('use somedb extrastuff  ', '');
+    const result = hiveSyntaxParser.parseSyntax('use somedb extrastuff  ', '');
     expect(result).toBeTruthy();
     expect(result.expectedStatementEnd).toBeTruthy();
   });
 
   it('should find errors for "select * from sample_07 where and\\n\\nselect unknownCol from sample_07;"', () => {
-    const result = sqlSyntaxParser.parseSyntax(
+    const result = hiveSyntaxParser.parseSyntax(
       'select * from sample_07 where and\n\nselect unknownCol from sample_07;',
       '',
-      'hive',
       false
     );
     expect(result).toBeTruthy();
   });
 
   const expectEqualIds = function(beforeA, afterA, beforeB, afterB) {
-    const resultA = sqlSyntaxParser.parseSyntax(beforeA, afterA);
-    const resultB = sqlSyntaxParser.parseSyntax(beforeB, afterB);
+    const resultA = hiveSyntaxParser.parseSyntax(beforeA, afterA);
+    const resultB = hiveSyntaxParser.parseSyntax(beforeB, afterB);
     expect(resultA).toBeTruthy('"' + beforeA + '|' + afterA + '" was not reported as an error');
     expect(resultB).toBeTruthy('"' + beforeB + '|' + afterB + '" was not reported as an error');
     expect(resultA.ruleId).toEqual(resultB.ruleId);
   };
 
   const expectNonEqualIds = function(beforeA, afterA, beforeB, afterB) {
-    const resultA = sqlSyntaxParser.parseSyntax(beforeA, afterA);
-    const resultB = sqlSyntaxParser.parseSyntax(beforeB, afterB);
+    const resultA = hiveSyntaxParser.parseSyntax(beforeA, afterA);
+    const resultB = hiveSyntaxParser.parseSyntax(beforeB, afterB);
     expect(resultA).toBeTruthy('"' + beforeA + '|' + afterA + '" was not reported as an error');
     expect(resultB).toBeTruthy('"' + beforeB + '|' + afterB + '" was not reported as an error');
     expect(resultA.ruleId).not.toEqual(resultB.ruleId);
@@ -232,69 +238,35 @@ describe('sqlSyntaxParser.js', () => {
     expectNonEqualIds('slelect ', '', 'select * form ', '');
   });
 
-  describe('Hive specific', () => {
-    it('should suggest expected words for "SLELECT "', () => {
-      const result = sqlSyntaxParser.parseSyntax('SLELECT ', '', 'hive');
-      expect(result).toBeTruthy();
-      expect(expectedToStrings(result.expected)).toEqual([
-        'SELECT',
-        'DELETE',
-        'SET',
-        'ALTER',
-        'INSERT',
-        'RELOAD',
-        'ABORT',
-        'ANALYZE',
-        'CREATE',
-        'EXPLAIN',
-        'EXPORT',
-        'GRANT',
-        'IMPORT',
-        'LOAD',
-        'MERGE',
-        'MSCK',
-        'REVOKE',
-        'SHOW',
-        'USE',
-        'DROP',
-        'FROM',
-        'TRUNCATE',
-        'UPDATE',
-        'WITH',
-        'DESCRIBE'
-      ]);
-    });
-  });
-
-  describe('Impala specific', () => {
-    it('should suggest expected words for "SLELECT "', () => {
-      const result = sqlSyntaxParser.parseSyntax('SLELECT ', '', 'impala');
-      expect(result).toBeTruthy();
-      expect(expectedToStrings(result.expected)).toEqual([
-        'SELECT',
-        'DELETE',
-        'SET',
-        'ALTER',
-        'COMMENT',
-        'INSERT',
-        'UPSERT',
-        'CREATE',
-        'EXPLAIN',
-        'GRANT',
-        'LOAD',
-        'REFRESH',
-        'REVOKE',
-        'SHOW',
-        'USE',
-        'COMPUTE',
-        'DROP',
-        'FROM',
-        'TRUNCATE',
-        'UPDATE',
-        'WITH',
-        'DESCRIBE',
-        'INVALIDATE'
-      ]);
-    });
+  it('should suggest expected words for "SLELECT "', () => {
+    const result = hiveSyntaxParser.parseSyntax('SLELECT ', '');
+    expect(result).toBeTruthy();
+    expect(expectedToStrings(result.expected)).toEqual([
+      'SELECT',
+      'DELETE',
+      'SET',
+      'ALTER',
+      'INSERT',
+      'RELOAD',
+      'ABORT',
+      'ANALYZE',
+      'CREATE',
+      'EXPLAIN',
+      'EXPORT',
+      'GRANT',
+      'IMPORT',
+      'LOAD',
+      'MERGE',
+      'MSCK',
+      'REVOKE',
+      'SHOW',
+      'USE',
+      'DROP',
+      'FROM',
+      'TRUNCATE',
+      'UPDATE',
+      'WITH',
+      'DESCRIBE'
+    ]);
   });
 });

+ 114 - 0
desktop/core/src/desktop/js/parse/sql/hive/spec/sqlParseSupportSpec.js

@@ -0,0 +1,114 @@
+// 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.
+
+import SqlParseSupport from '../sqlParseSupport';
+
+describe('sqlParseSupport.js', () => {
+  const expectDistance = function(strA, strB, distance, ignoreCase) {
+    const lr = SqlParseSupport.stringDistance(strA, strB, ignoreCase);
+    const rl = SqlParseSupport.stringDistance(strB, strA, ignoreCase);
+    expect(lr).toEqual(rl);
+    expect(lr).toEqual(distance);
+  };
+
+  it('should calculate the distance between "" and "" correctly', () => {
+    expectDistance('', '', 0, true);
+  });
+
+  it('should calculate the distance between "abc" and "" correctly', () => {
+    expectDistance('abc', '', 3, true);
+  });
+
+  it('should calculate the distance between "a" and "b" correctly', () => {
+    expectDistance('a', 'b', 1, true);
+  });
+
+  it('should calculate the distance between "abc" and "abc" correctly', () => {
+    expectDistance('abc', 'abc', 0, true);
+  });
+
+  it('should calculate the distance between "abcd" and "abc" correctly', () => {
+    expectDistance('abcd', 'abc', 1, true);
+  });
+
+  it('should calculate the distance between "abd" and "abc" correctly', () => {
+    expectDistance('abd', 'abc', 1, true);
+  });
+
+  it('should calculate the distance between "ca" and "abc" correctly', () => {
+    expectDistance('ca', 'abc', 3, true);
+  });
+
+  it('should calculate the distance between "abC" and "abc" whe not ignoring case correctly', () => {
+    expectDistance('abC', 'abc', 1, false);
+  });
+
+  it('should calculate the distance between "abC" and "abc" when ignoring case correctly', () => {
+    expectDistance('abC', 'abc', 0, true);
+  });
+
+  it('should calculate the distance between "abe" and "abc" correctly', () => {
+    expectDistance('abe', 'abc', 1, true);
+  });
+
+  it('should calculate the distance between "ace" and "abc" correctly', () => {
+    expectDistance('ace', 'abc', 2, true);
+  });
+
+  it('should calculate the distance between "12345" and "23451" correctly', () => {
+    expectDistance('12345', '23451', 2, true);
+  });
+
+  it('should calculate the distance between "abcde" and "12345" correctly', () => {
+    expectDistance('abcde', '12345', 5, true);
+  });
+
+  it('should calculate the distance between "12345" and "abcdefgh" correctly', () => {
+    expectDistance('12345', 'abcdefgh', 8, true);
+  });
+
+  it('should calculate the distance between "abc1def" and "abcdef" correctly', () => {
+    expectDistance('abc1def', 'abcdef', 1, true);
+  });
+
+  it('should calculate the distance between "bacdef" and "abcdef" correctly', () => {
+    expectDistance('bacdef', 'abcdef', 2, true);
+  });
+
+  xit('should be quick', () => {
+    const strA = 'abcdefgh012345678ijklmnop012345678';
+    const strB = 'ijklmnop012345678abcdefgh012345678';
+    let start, end;
+    const durations = new Array(10000 - 1000);
+    for (let i = 0; i < 10000; i++) {
+      if (i > 1000) {
+        start = performance.now();
+      }
+      SqlParseSupport.stringDistance(strA, strB, true);
+      if (i > 1000) {
+        end = performance.now();
+        durations.push(end - start);
+      }
+    }
+    let sum = 0;
+    durations.forEach(duration => {
+      sum += duration;
+    });
+    console.log('it took ' + sum / durations.length + ' ms on average.');
+    // ~ 0.037 ms on average
+    expect(true).toBeTruthy();
+  });
+});

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
desktop/core/src/desktop/js/parse/sql/impala/impalaSyntaxParser.js


+ 212 - 0
desktop/core/src/desktop/js/parse/sql/impala/spec/impalaSyntaxParserSpec.js

@@ -0,0 +1,212 @@
+// 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.
+
+import impalaSyntaxParser from '../impalaSyntaxParser';
+
+describe('impalaSyntaxParser.js', () => {
+  const expectedToStrings = function(expected) {
+    return expected.map(ex => ex.text);
+  };
+
+  it('should not find errors for ""', () => {
+    const result = impalaSyntaxParser.parseSyntax('', '');
+    expect(result).toBeFalsy();
+  });
+
+  it('should report incomplete statement for "SEL"', () => {
+    const result = impalaSyntaxParser.parseSyntax('SEL', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should report incomplete statement for "SELECT"', () => {
+    const result = impalaSyntaxParser.parseSyntax('SELECT', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should report incomplete statement for "SELECT "', () => {
+    const result = impalaSyntaxParser.parseSyntax('SELECT ', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should not report incomplete statement for "SELECT * FROM tbl"', () => {
+    const result = impalaSyntaxParser.parseSyntax('SELECT * FROM tbl', '');
+    expect(result.incompleteStatement).toBeFalsy();
+  });
+
+  it('should not report incomplete statement for "SELECT * FROM tbl LIMIT 1"', () => {
+    const result = impalaSyntaxParser.parseSyntax('SELECT * FROM tbl LIMIT 1', '');
+    expect(result.incompleteStatement).toBeFalsy();
+  });
+
+  it('should report incomplete statement for "SELECT * FROM tbl LIMIT "', () => {
+    const result = impalaSyntaxParser.parseSyntax('SELECT * FROM tbl LIMIT ', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should report incomplete statement for "SELECT * FROM tbl GROUP"', () => {
+    const result = impalaSyntaxParser.parseSyntax('SELECT * FROM tbl GROUP', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should not find errors for "SELECT *"', () => {
+    const result = impalaSyntaxParser.parseSyntax('SELECT *', '');
+    expect(result).toBeFalsy();
+  });
+
+  it('should not report incomplete statement for "SELECT * FR"', () => {
+    const result = impalaSyntaxParser.parseSyntax('SELECT * FR', '');
+    expect(result.incompleteStatement).toBeTruthy();
+  });
+
+  it('should find errors for "SLELECT "', () => {
+    const result = impalaSyntaxParser.parseSyntax('SLELECT ', '');
+    expect(result).toBeTruthy();
+    expect(result.text).toEqual('SLELECT');
+    expect(result.expected.length).toBeGreaterThan(0);
+    expect(result.loc.first_column).toEqual(0);
+    expect(result.loc.last_column).toEqual(7);
+  });
+
+  it('should find errors for "alter tabel "', () => {
+    const result = impalaSyntaxParser.parseSyntax('alter tabel ', '');
+    expect(result).toBeTruthy();
+    expect(result.text).toEqual('tabel');
+    expect(result.expected.length).toBeGreaterThan(0);
+    expect(result.loc.first_column).toEqual(6);
+    expect(result.loc.last_column).toEqual(11);
+  });
+
+  it('should find errors for "select *  form "', () => {
+    const result = impalaSyntaxParser.parseSyntax('select *  form ', '');
+    expect(result).toBeTruthy();
+    expect(result.loc.first_column).toEqual(10);
+    expect(result.loc.last_column).toEqual(14);
+    expect(expectedToStrings(result.expected)).toEqual(['from', 'union']);
+  });
+
+  it('should find errors for "select * from customers c cultster by awasd asd afd;"', () => {
+    const result = impalaSyntaxParser.parseSyntax(
+      'select * from customers c cultster by awasd asd afd;',
+      ''
+    );
+    expect(result).toBeTruthy();
+  });
+
+  it('should find errors for "select asdf wer qwer qewr   qwer"', () => {
+    const result = impalaSyntaxParser.parseSyntax('select asdf wer qwer qewr   qwer', '');
+    expect(result).toBeTruthy();
+  });
+
+  it('should suggest expected words for "SLELECT "', () => {
+    const result = impalaSyntaxParser.parseSyntax('SLELECT ', '');
+    expect(result).toBeTruthy();
+    expect(expectedToStrings(result.expected)).toEqual([
+      'SELECT',
+      'DELETE',
+      'SET',
+      'ALTER',
+      'COMMENT',
+      'INSERT',
+      'UPSERT',
+      'CREATE',
+      'EXPLAIN',
+      'GRANT',
+      'LOAD',
+      'REFRESH',
+      'REVOKE',
+      'SHOW',
+      'USE',
+      'COMPUTE',
+      'DROP',
+      'TRUNCATE',
+      'UPDATE',
+      'WITH',
+      'DESCRIBE',
+      'INVALIDATE'
+    ]);
+  });
+
+  it('should suggest expected words for "slelect "', () => {
+    const result = impalaSyntaxParser.parseSyntax('slelect ', '');
+    expect(result).toBeTruthy();
+    expect(expectedToStrings(result.expected)).toEqual([
+      'select',
+      'delete',
+      'set',
+      'alter',
+      'comment',
+      'insert',
+      'upsert',
+      'create',
+      'explain',
+      'grant',
+      'load',
+      'refresh',
+      'revoke',
+      'show',
+      'use',
+      'compute',
+      'drop',
+      'truncate',
+      'update',
+      'with',
+      'describe',
+      'invalidate'
+    ]);
+  });
+
+  it('should suggest expected that the statement should end for "use somedb extrastuff "', () => {
+    const result = impalaSyntaxParser.parseSyntax('use somedb extrastuff  ', '');
+    expect(result).toBeTruthy();
+    expect(result.expectedStatementEnd).toBeTruthy();
+  });
+
+  const expectEqualIds = function(beforeA, afterA, beforeB, afterB) {
+    const resultA = impalaSyntaxParser.parseSyntax(beforeA, afterA);
+    const resultB = impalaSyntaxParser.parseSyntax(beforeB, afterB);
+    expect(resultA).toBeTruthy('"' + beforeA + '|' + afterA + '" was not reported as an error');
+    expect(resultB).toBeTruthy('"' + beforeB + '|' + afterB + '" was not reported as an error');
+    expect(resultA.ruleId).toEqual(resultB.ruleId);
+  };
+
+  const expectNonEqualIds = function(beforeA, afterA, beforeB, afterB) {
+    const resultA = impalaSyntaxParser.parseSyntax(beforeA, afterA);
+    const resultB = impalaSyntaxParser.parseSyntax(beforeB, afterB);
+    expect(resultA).toBeTruthy('"' + beforeA + '|' + afterA + '" was not reported as an error');
+    expect(resultB).toBeTruthy('"' + beforeB + '|' + afterB + '" was not reported as an error');
+    expect(resultA.ruleId).not.toEqual(resultB.ruleId);
+  };
+
+  it('should have unique rule IDs when the same rule is failing in different locations', () => {
+    expectEqualIds('SLELECT ', '', 'dlrop ', '');
+    expectEqualIds('SELECT * FORM ', '', 'SELECT * bla ', '');
+    expectEqualIds('DROP TABLE b.bla ERRROROR ', '', 'DROP TABLE c.cla OTHERERRRRORRR ', '');
+    expectEqualIds(
+      'SELECT * FROM a WHERE id = 1, a b SELECT ',
+      '',
+      'SELECT id, foo FROM a WHERE a b SELECT',
+      ''
+    );
+    expectEqualIds(
+      'SELECT * FROM a WHERE id = 1, a b SELECT ',
+      '',
+      'SELECT id, foo FROM a WHERE a b SELECT',
+      ''
+    );
+
+    expectNonEqualIds('slelect ', '', 'select * form ', '');
+  });
+});

+ 114 - 0
desktop/core/src/desktop/js/parse/sql/impala/spec/sqlParseSupportSpec.js

@@ -0,0 +1,114 @@
+// 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.
+
+import SqlParseSupport from '../sqlParseSupport';
+
+describe('sqlParseSupport.js', () => {
+  const expectDistance = function(strA, strB, distance, ignoreCase) {
+    const lr = SqlParseSupport.stringDistance(strA, strB, ignoreCase);
+    const rl = SqlParseSupport.stringDistance(strB, strA, ignoreCase);
+    expect(lr).toEqual(rl);
+    expect(lr).toEqual(distance);
+  };
+
+  it('should calculate the distance between "" and "" correctly', () => {
+    expectDistance('', '', 0, true);
+  });
+
+  it('should calculate the distance between "abc" and "" correctly', () => {
+    expectDistance('abc', '', 3, true);
+  });
+
+  it('should calculate the distance between "a" and "b" correctly', () => {
+    expectDistance('a', 'b', 1, true);
+  });
+
+  it('should calculate the distance between "abc" and "abc" correctly', () => {
+    expectDistance('abc', 'abc', 0, true);
+  });
+
+  it('should calculate the distance between "abcd" and "abc" correctly', () => {
+    expectDistance('abcd', 'abc', 1, true);
+  });
+
+  it('should calculate the distance between "abd" and "abc" correctly', () => {
+    expectDistance('abd', 'abc', 1, true);
+  });
+
+  it('should calculate the distance between "ca" and "abc" correctly', () => {
+    expectDistance('ca', 'abc', 3, true);
+  });
+
+  it('should calculate the distance between "abC" and "abc" whe not ignoring case correctly', () => {
+    expectDistance('abC', 'abc', 1, false);
+  });
+
+  it('should calculate the distance between "abC" and "abc" when ignoring case correctly', () => {
+    expectDistance('abC', 'abc', 0, true);
+  });
+
+  it('should calculate the distance between "abe" and "abc" correctly', () => {
+    expectDistance('abe', 'abc', 1, true);
+  });
+
+  it('should calculate the distance between "ace" and "abc" correctly', () => {
+    expectDistance('ace', 'abc', 2, true);
+  });
+
+  it('should calculate the distance between "12345" and "23451" correctly', () => {
+    expectDistance('12345', '23451', 2, true);
+  });
+
+  it('should calculate the distance between "abcde" and "12345" correctly', () => {
+    expectDistance('abcde', '12345', 5, true);
+  });
+
+  it('should calculate the distance between "12345" and "abcdefgh" correctly', () => {
+    expectDistance('12345', 'abcdefgh', 8, true);
+  });
+
+  it('should calculate the distance between "abc1def" and "abcdef" correctly', () => {
+    expectDistance('abc1def', 'abcdef', 1, true);
+  });
+
+  it('should calculate the distance between "bacdef" and "abcdef" correctly', () => {
+    expectDistance('bacdef', 'abcdef', 2, true);
+  });
+
+  xit('should be quick', () => {
+    const strA = 'abcdefgh012345678ijklmnop012345678';
+    const strB = 'ijklmnop012345678abcdefgh012345678';
+    let start, end;
+    const durations = new Array(10000 - 1000);
+    for (let i = 0; i < 10000; i++) {
+      if (i > 1000) {
+        start = performance.now();
+      }
+      SqlParseSupport.stringDistance(strA, strB, true);
+      if (i > 1000) {
+        end = performance.now();
+        durations.push(end - start);
+      }
+    }
+    let sum = 0;
+    durations.forEach(duration => {
+      sum += duration;
+    });
+    console.log('it took ' + sum / durations.length + ' ms on average.');
+    // ~ 0.037 ms on average
+    expect(true).toBeTruthy();
+  });
+});

+ 1 - 1
desktop/core/src/desktop/js/parse/sql/sqlParserRepository.js

@@ -45,7 +45,7 @@ class SqlParserRepository {
           .catch(reject);
       });
     }
-    return this.modulePromises[sourceType + 'Autocomplete'];
+    return this.modulePromises[sourceType + parserType];
   }
 
   async getAutocompleter(sourceType) {

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 91
desktop/core/src/desktop/js/parse/sqlAutocompleteParser.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 2775
desktop/core/src/desktop/js/parse/sqlParseSupport.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 91
desktop/core/src/desktop/js/parse/sqlSyntaxParser.js


+ 48 - 2
desktop/core/src/desktop/js/sql/sqlSyntaxWebWorker.js

@@ -14,6 +14,52 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import sqlSyntaxParser from 'parse/sqlSyntaxParser';
+import 'utils/workerPublicPath';
+import '@babel/polyfill';
+import sqlParserRepository from 'parse/sql/sqlParserRepository';
 
-WorkerGlobalScope.sqlSyntaxParser = sqlSyntaxParser;
+/**
+ * This function turns the relative nested location into an absolute location given the statement location.
+ *
+ * @param statementLocation
+ * @param nestedLocation
+ */
+const toAbsoluteLocation = (statementLocation, nestedLocation) => {
+  if (nestedLocation.first_line === 1) {
+    nestedLocation.first_column += statementLocation.first_column;
+  }
+  if (nestedLocation.last_line === 1) {
+    nestedLocation.last_column += statementLocation.first_column;
+  }
+  const lineAdjust = statementLocation.first_line - 1;
+  nestedLocation.first_line += lineAdjust;
+  nestedLocation.last_line += lineAdjust;
+};
+
+let throttle = -1;
+
+const onMessage = msg => {
+  if (msg.data.ping) {
+    postMessage({ ping: true });
+    return;
+  }
+  clearTimeout(throttle);
+  throttle = setTimeout(() => {
+    sqlParserRepository.getSyntaxParser(msg.data.type).then(parser => {
+      const syntaxError = parser.parseSyntax(msg.data.beforeCursor, msg.data.afterCursor);
+      console.log(syntaxError);
+
+      if (syntaxError) {
+        toAbsoluteLocation(msg.data.statementLocation, syntaxError.loc);
+      }
+      postMessage({
+        id: msg.data.id,
+        editorChangeTime: msg.data.editorChangeTime,
+        syntaxError: syntaxError,
+        statementLocation: msg.data.statementLocation
+      });
+    });
+  }, 400);
+};
+
+WorkerGlobalScope.onSyntaxMessage = onMessage;

+ 5 - 42
desktop/core/src/desktop/templates/ace_sql_syntax_worker.mako

@@ -18,50 +18,13 @@
   from webpack_loader import utils
 %>
 
+WorkerGlobalScope.KNOX_BASE_PATH_HUE = '/KNOX_BASE_PATH_HUE';
+WorkerGlobalScope.HUE_BASE_URL = WorkerGlobalScope.KNOX_BASE_PATH_HUE.indexOf('KNOX_BASE_PATH_HUE') < 0 ? WorkerGlobalScope.KNOX_BASE_PATH_HUE : '';
+
 % for js_file in utils.get_files('sqlSyntaxWebWorker', config='WORKERS'):
   importScripts('${ js_file.get('url') }');
 % endfor
 
 (function () {
-
-  // TODO: Move to utils and re-use elsewhere
-  /**
-  * This function turns the relative nested location into an absolute location given the statement location.
-  *
-  * @param statementLocation
-  * @param nestedLocation
-  */
-  var toAbsoluteLocation = function (statementLocation, nestedLocation) {
-    if (nestedLocation.first_line === 1) {
-      nestedLocation.first_column += statementLocation.first_column;
-    }
-    if (nestedLocation.last_line === 1) {
-      nestedLocation.last_column += statementLocation.first_column;
-    }
-    var lineAdjust = statementLocation.first_line - 1;
-    nestedLocation.first_line += lineAdjust;
-    nestedLocation.last_line += lineAdjust;
-  };
-
-  this.throttle = -1;
-
-  this.onmessage = function (msg) {
-    if (msg.data.ping) {
-      postMessage({ ping: true });
-      return;
-    }
-    clearTimeout(this.throttle);
-    this.throttle = setTimeout(function () {
-      var syntaxError = WorkerGlobalScope.sqlSyntaxParser.parseSyntax(msg.data.beforeCursor, msg.data.afterCursor, msg.data.type, false);
-      if (syntaxError) {
-        toAbsoluteLocation(msg.data.statementLocation, syntaxError.loc);
-      }
-      postMessage({
-        id: msg.data.id,
-        editorChangeTime: msg.data.editorChangeTime,
-        syntaxError: syntaxError,
-        statementLocation: msg.data.statementLocation
-      });
-    }, 400);
-  }
-})();
+  this.onmessage = WorkerGlobalScope.onSyntaxMessage
+})();

+ 6 - 1
tools/jison/generateParsers.js

@@ -306,7 +306,12 @@ const identifySqlParsers = () =>
 
             if (fileIndex['sql.jisonlex']) {
               findParser(fileIndex, folder, sharedFiles, true);
-              findParser(fileIndex, folder, sharedFiles, false);
+              findParser(
+                fileIndex,
+                folder,
+                sharedFiles.filter(path => path.indexOf('_error.jison') === -1),
+                false
+              );
             } else {
               console.log(
                 "Warn: Could not find 'sql.jisonlex' in " + JISON_FOLDER + 'sql/' + folder + '/'

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels