فهرست منبع

HUE-4024 [editor] The new autocompleter should suggest identifiers and aliases

Johan Ahlen 9 سال پیش
والد
کامیت
1fbde55

+ 25 - 9
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.jison

@@ -783,7 +783,12 @@ parser.expandLateralViews = function (tablePrimaries, identifierChain) {
           identifierChain.shift();
           firstIdentifier = identifierChain[0];
         } else if (firstIdentifier.name === lateralView.tableAlias && identifierChain.length === 1 && typeof parser.yy.result.suggestColumns !== 'undefined') {
-          parser.yy.result.suggestIdentifiers = lateralView.columnAliases;
+          if (typeof parser.yy.result.suggestIdentifiers === 'undefined') {
+            parser.yy.result.suggestIdentifiers = [];
+          }
+          lateralView.columnAliases.forEach(function (columnAlias) {
+            parser.yy.result.suggestIdentifiers.push({ name: columnAlias, type: 'alias' });
+          });
           delete parser.yy.result.suggestColumns;
           return identifierChain;
         }
@@ -818,18 +823,23 @@ var linkSuggestion = function (suggestion, isColumnSuggestion) {
   // Expand exploded views in the identifier chain
   if (parser.yy.dialect === 'hive') {
     if (identifierChain.length === 0) {
-      var identifiers = [];
+      if (typeof parser.yy.result.suggestIdentifiers === 'undefined') {
+        parser.yy.result.suggestIdentifiers = [];
+      }
       tablePrimaries.forEach(function (tablePrimary) {
         if (typeof tablePrimary.lateralViews !== 'undefined') {
           tablePrimary.lateralViews.forEach(function (lateralView) {
-            Array.prototype.push.apply(identifiers, lateralView.columnAliases);
+            if (typeof lateralView.tableAlias !== 'undefined') {
+              parser.yy.result.suggestIdentifiers.push({ name: lateralView.tableAlias + '.', type: 'alias' });
+              parser.yy.keepColumns = true;
+            }
+            lateralView.columnAliases.forEach(function (columnAlias) {
+              parser.yy.result.suggestIdentifiers.push({ name: columnAlias, type: 'alias' });
+              parser.yy.keepColumns = true;
+            });
           });
         }
       });
-      if (identifiers.length > 0) {
-        parser.yy.keepColumns = true;
-        parser.yy.result.suggestIdentifiers = identifiers;
-      }
     } else {
       identifierChain = parser.expandLateralViews(tablePrimaries, identifierChain);
       suggestion.identifierChain = identifierChain;
@@ -874,9 +884,15 @@ var linkSuggestion = function (suggestion, isColumnSuggestion) {
 }
 
 var suggestTablePrimariesAsIdentifiers = function () {
-  parser.yy.result.suggestIdentifiers = [];
+  if (typeof parser.yy.result.suggestIdentifiers === 'undefined') {
+    parser.yy.result.suggestIdentifiers = [];
+  }
   parser.yy.latestTablePrimaries.forEach(function (tablePrimary) {
-    parser.yy.result.suggestIdentifiers.push((tablePrimary.alias || tablePrimary.identifierChain[0].name) + '.');
+    if (typeof tablePrimary.alias !== 'undefined') {
+      parser.yy.result.suggestIdentifiers.push({ name: tablePrimary.alias + '.', type: 'alias' });
+    } else {
+      parser.yy.result.suggestIdentifiers.push({ name: tablePrimary.identifierChain[0].name + '.', type: 'table' });
+    }
   });
 }
 

+ 25 - 9
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.js

@@ -591,7 +591,12 @@ parser.expandLateralViews = function (tablePrimaries, identifierChain) {
           identifierChain.shift();
           firstIdentifier = identifierChain[0];
         } else if (firstIdentifier.name === lateralView.tableAlias && identifierChain.length === 1 && typeof parser.yy.result.suggestColumns !== 'undefined') {
-          parser.yy.result.suggestIdentifiers = lateralView.columnAliases;
+          if (typeof parser.yy.result.suggestIdentifiers === 'undefined') {
+            parser.yy.result.suggestIdentifiers = [];
+          }
+          lateralView.columnAliases.forEach(function (columnAlias) {
+            parser.yy.result.suggestIdentifiers.push({ name: columnAlias, type: 'alias' });
+          });
           delete parser.yy.result.suggestColumns;
           return identifierChain;
         }
@@ -626,18 +631,23 @@ var linkSuggestion = function (suggestion, isColumnSuggestion) {
   // Expand exploded views in the identifier chain
   if (parser.yy.dialect === 'hive') {
     if (identifierChain.length === 0) {
-      var identifiers = [];
+      if (typeof parser.yy.result.suggestIdentifiers === 'undefined') {
+        parser.yy.result.suggestIdentifiers = [];
+      }
       tablePrimaries.forEach(function (tablePrimary) {
         if (typeof tablePrimary.lateralViews !== 'undefined') {
           tablePrimary.lateralViews.forEach(function (lateralView) {
-            Array.prototype.push.apply(identifiers, lateralView.columnAliases);
+            if (typeof lateralView.tableAlias !== 'undefined') {
+              parser.yy.result.suggestIdentifiers.push({ name: lateralView.tableAlias + '.', type: 'alias' });
+              parser.yy.keepColumns = true;
+            }
+            lateralView.columnAliases.forEach(function (columnAlias) {
+              parser.yy.result.suggestIdentifiers.push({ name: columnAlias, type: 'alias' });
+              parser.yy.keepColumns = true;
+            });
           });
         }
       });
-      if (identifiers.length > 0) {
-        parser.yy.keepColumns = true;
-        parser.yy.result.suggestIdentifiers = identifiers;
-      }
     } else {
       identifierChain = parser.expandLateralViews(tablePrimaries, identifierChain);
       suggestion.identifierChain = identifierChain;
@@ -682,9 +692,15 @@ var linkSuggestion = function (suggestion, isColumnSuggestion) {
 }
 
 var suggestTablePrimariesAsIdentifiers = function () {
-  parser.yy.result.suggestIdentifiers = [];
+  if (typeof parser.yy.result.suggestIdentifiers === 'undefined') {
+    parser.yy.result.suggestIdentifiers = [];
+  }
   parser.yy.latestTablePrimaries.forEach(function (tablePrimary) {
-    parser.yy.result.suggestIdentifiers.push((tablePrimary.alias || tablePrimary.identifierChain[0].name) + '.');
+    if (typeof tablePrimary.alias !== 'undefined') {
+      parser.yy.result.suggestIdentifiers.push({ name: tablePrimary.alias + '.', type: 'alias' });
+    } else {
+      parser.yy.result.suggestIdentifiers.push({ name: tablePrimary.identifierChain[0].name + '.', type: 'table' });
+    }
   });
 }
 

+ 34 - 15
desktop/core/src/desktop/static/desktop/js/sqlAutocompleter2.js

@@ -33,23 +33,30 @@
   function SqlAutocompleter2(options) {
     var self = this;
     self.snippet = options.snippet;
-  };
+  }
 
   SqlAutocompleter2.prototype.autocomplete = function(beforeCursor, afterCursor, callback, editor) {
     var self = this;
     var parseResult = sqlParser.parseSql(beforeCursor, afterCursor, self.snippet.type());
-    var completions = [];
 
-    var onFailure = function () {
-      editor.hideSpinner();
-      self.finalizeCompletions(completions);
-    };
+    if (parseResult.error) {
+      console.log(parseResult.error)
+    }
+
+    var completions = [];
 
     if (parseResult.suggestKeywords) {
       parseResult.suggestKeywords.forEach(function (keyword) {
         completions.push({ value: keyword, meta: 'keyword' });
       });
     }
+
+    if (parseResult.suggestIdentifiers) {
+      parseResult.suggestIdentifiers.forEach(function (identifier) {
+        completions.push({ value: identifier.name, meta: identifier.type });
+      });
+    }
+
     if (parseResult.suggestStar) {
       completions.push({ value: '*', meta: 'keyword' });
     }
@@ -57,12 +64,16 @@
     if (parseResult.suggestTables || parseResult.suggestColumns || parseResult.suggestValues) {
       var database = parseResult.useDatabase || self.snippet.database();
 
+      var deferrals = [];
+
       if (parseResult.suggestTables) {
         var prefix = parseResult.suggestTables.prependQuestionMark ? '? ' : '';
         if (parseResult.suggestTables.prependFrom) {
           prefix += parseResult.lowerCase ? 'from ' : 'FROM ';
         }
-        
+
+        var tableDeferred = $.Deferred();
+        deferrals.push(tableDeferred);
         self.snippet.getApiHelper().fetchTables({
           sourceType: self.snippet.type(),
           databaseName: database,
@@ -70,14 +81,18 @@
             data.tables_meta.forEach(function (tablesMeta) {
               completions.push({ value: prefix + tablesMeta.name, meta: tablesMeta.type.toLowerCase() })
             });
-            self.finalizeCompletions(completions, callback);
+            tableDeferred.resolve();
           },
           silenceErrors: true,
-          errorCallback: onFailure,
+          errorCallback: tableDeferred.resolve,
           editor: editor
         });
       }
+
       if (parseResult.suggestColumns) {
+        var columnsDeferred = $.Deferred();
+        deferrals.push(columnsDeferred);
+
         var fields = [];
         if (parseResult.suggestColumns.identifierChain) {
           parseResult.suggestColumns.identifierChain.forEach(function (identifier) {
@@ -96,7 +111,6 @@
           fields: fields,
           editor: editor,
           successCallback: function (data) {
-            console.log(data);
             if (data.columns) {
               data.columns.forEach(function (column) {
                 completions.push({ value: column, meta: 'column' })
@@ -107,18 +121,22 @@
                 completions.push({ value: field.name  , meta: 'struct' })
               });
             }
-            self.finalizeCompletions(completions, callback);
+            columnsDeferred.resolve();
           },
           silenceErrors: true,
-          errorCallback: onFailure
+          errorCallback: columnsDeferred.resolve
         });
       }
+
+      $.when.apply($, deferrals).done(function () {
+        self.finalizeCompletions(completions, callback, editor);
+      });
     } else {
-      self.finalizeCompletions(completions, callback);
+      self.finalizeCompletions(completions, callback, editor);
     }
   };
 
-  SqlAutocompleter2.prototype.finalizeCompletions = function (completions, callback) {
+  SqlAutocompleter2.prototype.finalizeCompletions = function (completions, callback, editor) {
     var self = this;
     self.sortCompletions(completions);
 
@@ -128,10 +146,11 @@
       currentScore--;
     });
 
+    editor.hideSpinner();
     callback(completions);
   };
 
-  var typeOrder = { 'star': 1, 'table': 2, 'keyword': 3,  };
+  var typeOrder = { 'star': 1, 'alias': 2, 'table': 3, 'identifier': 4, 'keyword': 5 };
 
   SqlAutocompleter2.prototype.sortCompletions = function (completions) {
     completions.sort(function (a, b) {

+ 43 - 11
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpec.js

@@ -323,7 +323,7 @@ define([
           expectedResult: {
             lowerCase: false,
             suggestStar: true,
-            suggestIdentifiers: ['tta.', 'testTableB.']
+            suggestIdentifiers: [{ name: 'tta.', type: 'alias' }, { name: 'testTableB.', type: 'table' }]
           }
         });
       });
@@ -346,7 +346,7 @@ define([
           afterCursor: '',
           expectedResult : {
             lowerCase: false,
-            suggestIdentifiers: ['tta.', 'testTableB.']
+            suggestIdentifiers: [{ name: 'tta.', type: 'alias' }, { name: 'testTableB.', type: 'table' }]
           }
         });
       });
@@ -360,7 +360,7 @@ define([
           expectedResult: {
             lowerCase: false,
             suggestStar: true,
-            suggestIdentifiers: ['tta.', 'ttb.', 'ttaSum.']
+            suggestIdentifiers: [{ name: 'tta.', type: 'alias' }, { name: 'ttaSum', type: 'alias' }, { name: 'ttb.', type: 'alias' }]
           }
         });
       });
@@ -722,6 +722,38 @@ define([
           });
         });
 
+        it('should suggest lateral view aliases', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT ',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testArray) explodedTable AS testItem',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable'
+              },
+              suggestIdentifiers: [{ name: 'explodedTable.', type: 'alias' }, { name: 'testItem', type: 'alias' }]
+            }
+          });
+        });
+
+        it('should suggest lateral view aliases with multiple column aliases', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT ',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) explodedTable AS (testKey, testValue)',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable'
+              },
+              suggestIdentifiers: [{ name: 'explodedTable.', type: 'alias' }, { name: 'testKey', type: 'alias' }, { name: 'testValue', type: 'alias' }]
+            }
+          });
+        });
+
         it('should suggest structs from exploded item references to arrays', function () {
           assertAutoComplete({
             beforeCursor: 'SELECT testItem.',
@@ -873,7 +905,7 @@ define([
             expectedResult: {
               lowerCase: false,
               suggestStar: true, // TODO: Check if really true
-              suggestIdentifiers: ['testMapKey', 'testMapValue']
+              suggestIdentifiers: [{ name: 'testMapKey', type: 'alias' }, { name: 'testMapValue', type: 'alias' }]
             }
           });
         });
@@ -891,7 +923,7 @@ define([
             expectedResult: {
               lowerCase: false,
               suggestStar: true, // TODO: Check if really true
-              suggestIdentifiers: ['testMapKey', 'testMapValue'],
+              suggestIdentifiers: [{ name: 'explodedMap.', type: 'alias' }, { name: 'testMapKey', type: 'alias' }, { name: 'testMapValue', type: 'alias' }],
               suggestColumns: {
                 table: 'testTable',
               }
@@ -1021,7 +1053,7 @@ define([
           expectedResult: {
             lowerCase: false,
             suggestStar: true, // TODO: Check if really so
-            suggestIdentifiers: ['t.', 'tm.']
+            suggestIdentifiers: [{ name: 't.', type: 'alias' }, { name: 'tm.', type: 'alias' }]
           }
         });
       });
@@ -1068,7 +1100,7 @@ define([
               table: 'testTable',
               identifierChain: [{ name: 'testMap' }, { name: 'key' }]
             },
-            suggestIdentifiers : ['t.', 'tm.']
+            suggestIdentifiers : [{ name: 't.', type: 'alias' }, { name: 'tm.', type: 'alias' }]
           }
         });
       });
@@ -1084,7 +1116,7 @@ define([
               table: 'testTable',
               identifierChain: [{ name: 'testMap' }, { name: 'field' }]
             },
-            suggestIdentifiers : ['t.', 'm.']
+            suggestIdentifiers : [{ name: 't.', type: 'alias' }, { name: 'm.', type: 'alias' }]
           }
         });
       })
@@ -1398,7 +1430,7 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestIdentifiers: ['testTable1.', 'testTable2.']
+            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }]
           }
         });
       });
@@ -1410,7 +1442,7 @@ define([
           ignoreErrors: true, // Here the right parenthesis is missing
           expectedResult: {
             lowerCase: false,
-            suggestIdentifiers: ['testTable1.', 'testTable2.']
+            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }]
           }
         });
       });
@@ -1421,7 +1453,7 @@ define([
           afterCursor: ' AND testTable1.testColumn1 = testTable2.testColumn3',
           expectedResult: {
             lowerCase: false,
-            suggestIdentifiers: ['testTable1.', 'testTable2.']
+            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }]
           }
         });
       });