Эх сурвалжийг харах

[core] Extract assist helper with common assist functionality

The assist helper will be shared between the assist panel and the autocomplete. The idea is that the assist helper will be in charge of talking to the API and caching. It replaces the existing assist.js.
Johan Ahlen 10 жил өмнө
parent
commit
5dfee30

+ 7 - 3
apps/beeswax/src/beeswax/templates/execute.mako

@@ -802,6 +802,7 @@ ${ commonshare() | n,unicode }
 <script src="${ static('desktop/ext/js/knockout.min.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/ext/js/knockout-mapping.min.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/js/ko.hue-bindings.js') }" type="text/javascript" charset="utf-8"></script>
+<script src="${ static('desktop/js/assistHelper.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/js/autocomplete.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('beeswax/js/beeswax.vm.js') }"></script>
 <script src="${ static('desktop/js/share.vm.js') }"></script>
@@ -1126,10 +1127,13 @@ var HIVE_AUTOCOMPLETE_GLOBAL_CALLBACK = function (data) {
   }
 };
 
+var asssitHelper = new AssistHelper({
+    app: HIVE_AUTOCOMPLETE_APP,
+    user: HIVE_AUTOCOMPLETE_USER,
+})
+
 var autocompleter = new Autocompleter({
-  baseUrl: HIVE_AUTOCOMPLETE_BASE_URL,
-  app: HIVE_AUTOCOMPLETE_APP,
-  user: HIVE_AUTOCOMPLETE_USER,
+  assistHelper: asssitHelper,
   mode: HIVE_AUTOCOMPLETE_APP
 });
 

+ 6 - 2
apps/spark/src/spark/templates/editor_components.mako

@@ -90,6 +90,7 @@ from desktop.views import _ko
 <script src="${ static('desktop/js/ace/ace.js') }"></script>
 <script src="${ static('desktop/js/ace/ext-language_tools.js') }"></script>
 <script src="${ static('desktop/js/ace.extended.js') }"></script>
+<script src="${ static('desktop/js/assistHelper.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/js/autocomplete.js') }" type="text/javascript" charset="utf-8"></script>
 </%def>
 
@@ -1604,12 +1605,15 @@ from desktop.views import _ko
     $('#snippet_' + snippet.id()).find('.download-form').submit();
   }
 
-  var aceAutocompleter = new Autocompleter({
-    baseUrl: '${ autocomplete_base_url | n,unicode }',
+  var assistHelper = new AssistHelper({
     app: 'beeswax',
     user: '${user}'
   });
 
+  var aceAutocompleter = new Autocompleter({
+    assistHelper: assistHelper
+  });
+
   var assist = new Assist({
     baseURL: "${ autocomplete_base_url | n,unicode }",
     app: "beeswax",

+ 162 - 0
desktop/core/src/desktop/static/desktop/js/assistHelper.js

@@ -0,0 +1,162 @@
+// 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.
+
+var TIME_TO_LIVE_IN_MILLIS = 86400000; // 1 day
+
+/**
+ * @param options {object}
+ * @param options.app
+ * @param options.user
+ *
+ * @constructor
+ */
+function AssistHelper (options) {
+  var self = this;
+  self.options = options;
+}
+
+AssistHelper.prototype.hasExpired = function (timestamp) {
+  return (new Date()).getTime() - timestamp > TIME_TO_LIVE_IN_MILLIS;
+};
+
+AssistHelper.prototype.getTotalStorageUserPrefix = function () {
+  var self = this;
+  var app = "";
+  if (typeof self.options.app != "undefined") {
+    app = self.options.app;
+  }
+  if (typeof self.options.user != "undefined") {
+    return app + "_" + self.options.user;
+  }
+  return app;
+};
+
+AssistHelper.prototype.fetchTableHtmlPreview = function(databaseName, tableName, successCallback, errorCallback) {
+  var self = this;
+  $.ajax({
+    url: "/" + self.options.app + "/api/table/" + databaseName + "/" + tableName,
+    data: {"sample": true},
+    beforeSend: function (xhr) {
+      xhr.setRequestHeader("X-Requested-With", "Hue");
+    },
+    dataType: "html",
+    success: successCallback,
+    error: errorCallback
+  });
+};
+
+AssistHelper.prototype.refreshTableStats = function(databaseName, tableName, successCallback, errorCallback) {
+  var self = this;
+  var pollRefresh = function (url) {
+    $.post(url, function (data) {
+      if (data.isSuccess) {
+        successCallback(data);
+      } else if (data.isFailure) {
+        errorCallback(data.message);
+      } else {
+        window.setTimeout(function () {
+          pollRefresh(url);
+        }, 1000);
+      }
+    }).fail(errorCallback);
+  };
+
+  $.post("/" + self.options.app + "/api/analyze/" + databaseName + "/" + tableName + "/", function (data) {
+    if (data.status == 0 && data.watch_url) {
+      pollRefresh(data.watch_url);
+    } else {
+      errorCallback();
+    }
+  }).fail(errorCallback);
+};
+
+AssistHelper.prototype.fetchStats = function(databaseName, tableName, columnName, successCallback, errorCallback) {
+  var self = this;
+  $.ajax({
+    url: "/" + self.options.app + "/api/table/" + databaseName + "/" + tableName + "/stats/" + (columnName || ""),
+    data: {},
+    beforeSend: function (xhr) {
+      xhr.setRequestHeader("X-Requested-With", "Hue");
+    },
+    dataType: "json",
+    success: successCallback,
+    error: errorCallback
+  });
+};
+
+AssistHelper.prototype.fetchTerms = function(databaseName, tableName, columnName, prefixFilter, successCallback, errorCallback) {
+  var self = this;
+  $.ajax({
+    url: "/" + self.options.app + "/api/table/" + databaseName + "/" + tableName + "/terms/" + columnName + "/" + (prefixFilter || ""),
+    data: {},
+    beforeSend: function (xhr) {
+      xhr.setRequestHeader("X-Requested-With", "Hue");
+    },
+    dataType: "json",
+    success: successCallback,
+    error: errorCallback
+  });
+};
+
+AssistHelper.prototype.fetchDatabases = function(successCallback, errorCallback) {
+  var self = this;
+  self.fetchAssistData("/" + self.options.app + "/api/autocomplete/", successCallback, errorCallback);
+};
+
+AssistHelper.prototype.fetchTables = function(databaseName, successCallback, errorCallback) {
+  var self = this;
+  self.fetchAssistData("/" + self.options.app + "/api/autocomplete/" + databaseName, successCallback, errorCallback);
+};
+
+AssistHelper.prototype.fetchFields = function(databaseName, tableName, fields, successCallback, errorCallback) {
+  var self = this;
+
+  var fieldPart = fields.length > 0 ? "/" + fields.join("/") : "";
+  self.fetchAssistData("/" + self.options.app + "/api/autocomplete/" + databaseName + "/" + tableName + fieldPart, successCallback, errorCallback);
+};
+
+AssistHelper.prototype.clearCache = function() {
+  var self = this;
+  $.totalStorage("hue.assist." + self.getTotalStorageUserPrefix(), {});
+};
+
+AssistHelper.prototype.fetchPanelData = function (hierarcy, successCallback, errorCallback) {
+  var self = this;
+  self.fetchAssistData("/" + self.options.app + "/api/autocomplete/" + hierarcy.join("/"), successCallback, errorCallback);
+};
+
+AssistHelper.prototype.fetchAssistData = function (url, successCallback, errorCallback) {
+  var self = this;
+  var cachedData = $.totalStorage("hue.assist." + self.getTotalStorageUserPrefix()) || {};
+
+  if (typeof cachedData[url] == "undefined" || self.hasExpired(cachedData[url].timestamp)) {
+    $.ajax({
+      type: "GET",
+      url: url + "?" + Math.random(),
+      success: function (data) {
+        cachedData[url] = {
+          timestamp: (new Date()).getTime(),
+          data: data
+        };
+        $.totalStorage("hue.assist." + self.getTotalStorageUserPrefix(), cachedData);
+        successCallback(data);
+      },
+      error: errorCallback
+    });
+  } else {
+    successCallback(cachedData[url].data);
+  }
+};

+ 9 - 50
desktop/core/src/desktop/static/desktop/js/autocomplete.js

@@ -19,17 +19,16 @@ var TIME_TO_LIVE_IN_MILLIS = 86400000; // 1 day
 
 /**
  * @param options {object}
- * @param options.baseUrl
- * @param options.app
- * @param options.user
  * @param options.db
  * @param options.mode
+ * @param options.assistHelper
  *
  * @constructor
  */
 function Autocompleter(options) {
   var self = this;
   self.options = options;
+  self.assistHelper = options.assistHelper;
   self.currentDb = options.db;
   if (typeof options.mode === "undefined" || options.mode === null || options.mode === "beeswax") {
     self.currentMode = "hive";
@@ -46,10 +45,6 @@ function Autocompleter(options) {
   })
 }
 
-Autocompleter.prototype.hasExpired = function (timestamp) {
-  return (new Date()).getTime() - timestamp > TIME_TO_LIVE_IN_MILLIS;
-};
-
 Autocompleter.prototype.getTableReferenceIndex = function (statement) {
   var result = {};
   var fromMatch = statement.match(/\s*from\s*([^;]*).*$/i);
@@ -98,41 +93,6 @@ Autocompleter.prototype.extractFields = function (data, valuePrefix, includeStar
   return fields;
 };
 
-Autocompleter.prototype.getTotalStorageUserPrefix = function () {
-  var self = this;
-  var app = "";
-  if (typeof self.options.app != "undefined") {
-    app = self.options.app;
-  }
-  if (typeof self.options.user != "undefined") {
-    return app + "_" + self.options.user;
-  }
-  return app;
-};
-
-Autocompleter.prototype.fetchAssistData = function (url, successCallback, errorCallback) {
-  var self = this;
-  var cachedData = $.totalStorage("hue.assist." + self.getTotalStorageUserPrefix()) || {};
-
-  if (typeof cachedData[url] == "undefined" || self.hasExpired(cachedData[url].timestamp)) {
-    $.ajax({
-      type: "GET",
-      url: url + "?" + Math.random(),
-      success: function (data) {
-        cachedData[url] = {
-          timestamp: (new Date()).getTime(),
-          data: data
-        };
-        $.totalStorage("hue.assist." + self.getTotalStorageUserPrefix(), cachedData);
-        successCallback(data);
-      },
-      error: errorCallback
-    });
-  } else {
-    successCallback(cachedData[url].data);
-  }
-};
-
 Autocompleter.prototype.autocomplete = function(beforeCursor, afterCursor, callback) {
   var self = this;
 
@@ -171,8 +131,7 @@ Autocompleter.prototype.autocomplete = function(beforeCursor, afterCursor, callb
 
 
   if (tableNameAutoComplete || (selectBefore && !fromAfter)) {
-    var url = self.options.baseUrl + self.currentDb;
-    self.fetchAssistData(url, function(data) {
+    self.assistHelper.fetchTables(self.currentDb, function(data) {
       var fromKeyword = "";
       if (selectBefore) {
         if (beforeCursor.indexOf("SELECT") > -1) {
@@ -221,24 +180,24 @@ Autocompleter.prototype.autocomplete = function(beforeCursor, afterCursor, callb
       callback([]);
       return;
     }
-    var url = self.options.baseUrl + self.currentDb + "/" + tableName;
+    var fields = [];
     $.each(parts, function(index, part) {
       if (part != '' && (index > 0 || part !== tableName)) {
-        url += "/";
         if (self.currentMode === "hive") {
           var mapMatch = part.match(/([^\[]*)\[[^\]]+\]$/i);
           if (mapMatch !== null) {
-            url += mapMatch[1] + "/value"
+            fields.push(mapMatch[1]);
+            fields.push("value");
           } else {
-            url += part;
+            fields.push(part);
           }
         } else {
-          url += part;
+          fields.push(part);
         }
       }
     });
 
-    self.fetchAssistData(url, function(data) {
+    self.assistHelper.fetchFields(self.currentDb, tableName, fields, function(data) {
       callback(self.extractFields(data, "", !fieldTermBefore));
     }, function() {
       callback([]);

+ 33 - 30
desktop/core/src/desktop/static/desktop/spec/autocompleteSpec.js

@@ -64,9 +64,10 @@ describe("autocomplete.js", function() {
 
   beforeEach(function() {
     var options = {
-      baseUrl: "http://baseUrl/",
-      app: "testApp",
-      user: "testUser",
+      assistHelper: new AssistHelper({
+        app: "testApp",
+        user: "testUser"
+      }),
       db: "testDb"
     };
     subject = new Autocompleter(options);
@@ -90,7 +91,7 @@ describe("autocomplete.js", function() {
     it("should suggest table names with no columns", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb" : {
+          "/testApp/api/autocomplete/testDb" : {
             tables: ["testTable1", "testTable2"]
           }
         },
@@ -103,7 +104,7 @@ describe("autocomplete.js", function() {
     it("should follow keyword case for table name completion", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb" : {
+          "/testApp/api/autocomplete/testDb" : {
             tables: ["testTable1", "testTable2"]
           }
         },
@@ -116,7 +117,7 @@ describe("autocomplete.js", function() {
     it("should suggest table names with *", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb" : {
+          "/testApp/api/autocomplete/testDb" : {
             tables: ["testTable1", "testTable2"]
           }
         },
@@ -129,7 +130,7 @@ describe("autocomplete.js", function() {
     it("should suggest table names with started FROM", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb" : {
+          "/testApp/api/autocomplete/testDb" : {
             tables: ["testTable1", "testTable2"]
           }
         },
@@ -142,7 +143,7 @@ describe("autocomplete.js", function() {
     it("should suggest table names after FROM", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb" : {
+          "/testApp/api/autocomplete/testDb" : {
             tables: ["testTable1", "testTable2"]
           }
         },
@@ -156,9 +157,10 @@ describe("autocomplete.js", function() {
   describe("hive-specific stuff", function() {
     beforeEach(function() {
       var options = {
-        baseUrl: "http://baseUrl/",
-        app: "testApp",
-        user: "testUser",
+        assistHelper: new AssistHelper({
+          app: "testApp",
+          user: "testUser"
+        }),
         db: "testDb",
         mode: "hive"
       };
@@ -169,7 +171,7 @@ describe("autocomplete.js", function() {
     it("should suggest struct from map values", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTable/testMap/value" : {
+          "/testApp/api/autocomplete/testDb/testTable/testMap/value" : {
             fields: [
               {"type": "string", "name": "fieldA" },
               {"type": "string", "name": "fieldB" },
@@ -189,7 +191,7 @@ describe("autocomplete.js", function() {
     it("should suggest struct from structs from map values", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTable/testMap/value/fieldC" : {
+          "/testApp/api/autocomplete/testDb/testTable/testMap/value/fieldC" : {
             fields: [
               {"type": "string", "name": "fieldC_A" },
               {"type": "boolean", "name": "fieldC_B"}
@@ -207,9 +209,10 @@ describe("autocomplete.js", function() {
   describe("impala-specific stuff", function() {
     beforeEach(function () {
       var options = {
-        baseUrl: "http://baseUrl/",
-        app: "testApp",
-        user: "testUser",
+        assistHelper: new AssistHelper({
+          app: "testApp",
+          user: "testUser"
+        }),
         db: "testDb",
         mode: "impala"
       };
@@ -220,7 +223,7 @@ describe("autocomplete.js", function() {
     it("should not suggest struct from map values with hive style syntax", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTable/testMap[\"anyKey\"]" : {}
+          "/testApp/api/autocomplete/testDb/testTable/testMap[\"anyKey\"]" : {}
         },
         beforeCursor: "SELECT testMap[\"anyKey\"].",
         afterCursor: " FROM testTable",
@@ -234,7 +237,7 @@ describe("autocomplete.js", function() {
     it("should suggest columns for table", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTable" : {
+          "/testApp/api/autocomplete/testDb/testTable" : {
             columns: ["testTableColumn1", "testTableColumn2"]
           }
         },
@@ -248,7 +251,7 @@ describe("autocomplete.js", function() {
     it("should suggest columns for table after WHERE", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTable" : {
+          "/testApp/api/autocomplete/testDb/testTable" : {
             columns: ["testTableColumn1", "testTableColumn2"]
           }
         },
@@ -262,7 +265,7 @@ describe("autocomplete.js", function() {
     it("should suggest columns for table after ORDER BY ", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTable" : {
+          "/testApp/api/autocomplete/testDb/testTable" : {
             columns: ["testTableColumn1", "testTableColumn2"]
           }
         },
@@ -276,10 +279,10 @@ describe("autocomplete.js", function() {
     it("should suggest columns for table after ON ", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTable1" : {
+          "/testApp/api/autocomplete/testDb/testTable1" : {
             columns: ["testTableColumn1", "testTableColumn2"]
           },
-          "http://baseUrl/testDb/testTable2" : {
+          "/testDb/testTable2" : {
             columns: ["testTableColumn3", "testTableColumn4"]
           }
         },
@@ -292,7 +295,7 @@ describe("autocomplete.js", function() {
     it("should suggest columns for table with table ref", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTable" : {
+          "/testApp/api/autocomplete/testDb/testTable" : {
             columns: ["testTableColumn1", "testTableColumn2"]
           }
         },
@@ -305,7 +308,7 @@ describe("autocomplete.js", function() {
     it("should suggest columns with table alias", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTable" : {
+          "/testApp/api/autocomplete/testDb/testTable" : {
             columns: ["testTableColumn1", "testTableColumn2"]
           }
         },
@@ -317,10 +320,10 @@ describe("autocomplete.js", function() {
 
     it("should suggest columns with multiple table aliases", function() {
       var serverResponses = {
-        "http://baseUrl/testDb/testTableA": {
+        "/testApp/api/autocomplete/testDb/testTableA": {
           columns: ["testTableColumn1", "testTableColumn2"]
         },
-        "http://baseUrl/testDb/testTableB": {
+        "/testApp/api/autocomplete/testDb/testTableB": {
           columns: ["testTableColumn3", "testTableColumn4"]
         }
       };
@@ -341,10 +344,10 @@ describe("autocomplete.js", function() {
     it("should suggest aliases", function() {
       assertAutoComplete({
         serverResponses: {
-          "http://baseUrl/testDb/testTableA" : {
+          "/testApp/api/autocomplete/testDb/testTableA" : {
             columns: ["testTableColumn1", "testTableColumn2"]
           },
-          "http://baseUrl/testDb/testTableB" : {
+          "/testApp/api/autocomplete/testDb/testTableB" : {
             columns: ["testTableColumn3", "testTableColumn4"]
           }
         },
@@ -358,7 +361,7 @@ describe("autocomplete.js", function() {
       it("should suggest fields from columns that are structs", function() {
         assertAutoComplete({
           serverResponses: {
-            "http://baseUrl/testDb/testTable/columnA" : {
+            "/testApp/api/autocomplete/testDb/testTable/columnA" : {
               fields: [
                 {"type": "string", "name": "fieldA" },
                 {"type": "boolean", "name": "fieldB" },
@@ -380,7 +383,7 @@ describe("autocomplete.js", function() {
       it("should suggest fields from nested structs", function() {
         assertAutoComplete({
           serverResponses: {
-            "http://baseUrl/testDb/testTable/columnA/fieldC" : {
+            "/testApp/api/autocomplete/testDb/testTable/columnA/fieldC" : {
               fields: [
                 {"type": "string", "name": "fieldC_A" },
                 {"type": "boolean", "name": "fieldC_B"}

+ 1 - 0
desktop/core/src/desktop/templates/jasmine.mako

@@ -28,6 +28,7 @@
   <script src="${ static('desktop/js/hue.utils.js') }"></script>
 
   ## Specs below
+  <script src="${ static('desktop/js/assistHelper.js') }"></script>
   <script src="${ static('desktop/js/autocomplete.js') }"></script>
   <script src="${ static('desktop/spec/autocompleteSpec.js') }"></script>
 </%block>