소스 검색

HUE-4017 [editor] Make ace editor suggestions from the new autocompleter

Johan Ahlen 9 년 전
부모
커밋
3ce9a15
2개의 변경된 파일173개의 추가작업 그리고 15개의 파일을 삭제
  1. 23 15
      desktop/core/src/desktop/static/desktop/js/autocompleter.js
  2. 150 0
      desktop/core/src/desktop/static/desktop/js/sqlAutocompleter2.js

+ 23 - 15
desktop/core/src/desktop/static/desktop/js/autocompleter.js

@@ -18,19 +18,20 @@
   if(typeof define === "function" && define.amd) {
     define([
       'desktop/js/sqlAutocompleter',
+      'desktop/js/sqlAutocompleter2',
       'desktop/js/hdfsAutocompleter'
     ], factory);
   } else {
-    root.Autocompleter = factory(SqlAutocompleter, HdfsAutocompleter);
+    root.Autocompleter = factory(SqlAutocompleter, SqlAutocompleter2, HdfsAutocompleter);
   }
-}(this, function (SqlAutocompleter, HdfsAutocompleter) {
+}(this, function (SqlAutocompleter, SqlAutocompleter2, HdfsAutocompleter) {
 
   /**
    * @param options {object}
    * @param options.snippet
    * @param options.user
    * @param options.optEnabled
-   *
+   * @param options.useNewSqlAutocompleter {boolean}
    * @constructor
    */
   function Autocompleter(options) {
@@ -40,19 +41,25 @@
     self.topTables = {};
 
     var initializeAutocompleter = function () {
-      var hdfsAutocompleter = new HdfsAutocompleter({
-        user: options.user,
-        snippet: options.snippet
-      });
-      if (self.snippet.isSqlDialect()) {
-        self.autocompleter = new SqlAutocompleter({
-          hdfsAutocompleter: hdfsAutocompleter,
-          snippet: options.snippet,
-          oldEditor: options.oldEditor,
-          optEnabled: options.optEnabled
-        })
+      if (self.snippet.isSqlDialect() && options.useNewAutocompleter) {
+        self.autocompleter = new SqlAutocompleter2({
+          snippet: self.snippet
+        });
       } else {
-        self.autocompleter = hdfsAutocompleter;
+        var hdfsAutocompleter = new HdfsAutocompleter({
+          user: options.user,
+          snippet: options.snippet
+        });
+        if (self.snippet.isSqlDialect()) {
+          self.autocompleter = new SqlAutocompleter({
+            hdfsAutocompleter: hdfsAutocompleter,
+            snippet: options.snippet,
+            oldEditor: options.oldEditor,
+            optEnabled: options.optEnabled
+          })
+        } else {
+          self.autocompleter = hdfsAutocompleter;
+        }
       }
     };
     self.snippet.type.subscribe(function () {
@@ -61,6 +68,7 @@
     initializeAutocompleter();
   }
 
+  // TODO: See why we need this one.
   Autocompleter.prototype.initializeAutocompleter = function () {
     var self = this;
   };

+ 150 - 0
desktop/core/src/desktop/static/desktop/js/sqlAutocompleter2.js

@@ -0,0 +1,150 @@
+// 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.
+
+(function (root, factory) {
+  if(typeof define === "function" && define.amd) {
+    define([
+      'desktop/js/autocomplete/sql'
+    ], factory);
+  } else {
+    root.SqlAutocompleter2 = factory(sql);
+  }
+}(this, function (sqlParser) {
+
+
+  /**
+   * @param {Object} options
+   * @param {Snippet} options.snippet
+   * @constructor
+   */
+  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.suggestKeywords) {
+      parseResult.suggestKeywords.forEach(function (keyword) {
+        completions.push({ value: keyword, meta: 'keyword' });
+      });
+    }
+    if (parseResult.suggestStar) {
+      completions.push({ value: '*', meta: 'keyword' });
+    }
+
+    if (parseResult.suggestTables || parseResult.suggestColumns || parseResult.suggestValues) {
+      var database = parseResult.useDatabase || self.snippet.database();
+
+      if (parseResult.suggestTables) {
+        var prefix = parseResult.suggestTables.prependQuestionMark ? '? ' : '';
+        if (parseResult.suggestTables.prependFrom) {
+          prefix += parseResult.lowerCase ? 'from ' : 'FROM ';
+        }
+        
+        self.snippet.getApiHelper().fetchTables({
+          sourceType: self.snippet.type(),
+          databaseName: database,
+          successCallback: function (data) {
+            data.tables_meta.forEach(function (tablesMeta) {
+              completions.push({ value: prefix + tablesMeta.name, meta: tablesMeta.type.toLowerCase() })
+            });
+            self.finalizeCompletions(completions, callback);
+          },
+          silenceErrors: true,
+          errorCallback: onFailure,
+          editor: editor
+        });
+      }
+      if (parseResult.suggestColumns) {
+        var fields = [];
+        if (parseResult.suggestColumns.identifierChain) {
+          parseResult.suggestColumns.identifierChain.forEach(function (identifier) {
+            var field = identifier.name;
+            if (identifier.key) {
+              field += '[' + identifier.key + ']';
+            }
+            fields.push(field);
+          });
+        }
+
+        self.snippet.getApiHelper().fetchFields({
+          sourceType: self.snippet.type(),
+          databaseName: parseResult.suggestColumns.database || database,
+          tableName: parseResult.suggestColumns.table,
+          fields: fields,
+          editor: editor,
+          successCallback: function (data) {
+            console.log(data);
+            if (data.columns) {
+              data.columns.forEach(function (column) {
+                completions.push({ value: column, meta: 'column' })
+              });
+            }
+            if (data.type === 'struct') {
+              data.fields.forEach(function (field) {
+                completions.push({ value: field.name  , meta: 'struct' })
+              });
+            }
+            self.finalizeCompletions(completions, callback);
+          },
+          silenceErrors: true,
+          errorCallback: onFailure
+        });
+      }
+    } else {
+      self.finalizeCompletions(completions, callback);
+    }
+  };
+
+  SqlAutocompleter2.prototype.finalizeCompletions = function (completions, callback) {
+    var self = this;
+    self.sortCompletions(completions);
+
+    var currentScore = 1000;
+    completions.forEach(function (completion) {
+      completion.score = currentScore;
+      currentScore--;
+    });
+
+    callback(completions);
+  };
+
+  var typeOrder = { 'star': 1, 'table': 2, 'keyword': 3,  };
+
+  SqlAutocompleter2.prototype.sortCompletions = function (completions) {
+    completions.sort(function (a, b) {
+      if (typeOrder[a.value == '*' ? 'star' : a.meta] !== typeOrder[b.value == '*' ? 'star' : b.meta]) {
+        return typeOrder[a.value == '*' ? 'star' : a.meta] - typeOrder[b.value == '*' ? 'star' : b.meta];
+      }
+      return a.value.localeCompare(b.value);
+    });
+  };
+  
+  SqlAutocompleter2.prototype.getDocTooltip = function (item) {
+
+  };
+
+  return SqlAutocompleter2;
+}));