Explorar o código

HUE-3326 [editor] Introduce the cursor and add suggestions for possible statements

Johan Ahlen %!s(int64=9) %!d(string=hai) anos
pai
achega
9072772fc8

+ 37 - 8
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.jison

@@ -18,31 +18,60 @@
 %%
 %%
 
 
 \s+                   { /* skip whitespace */ }
 \s+                   { /* skip whitespace */ }
-"SELECT"              { return 'SELECT'; }
-"FROM"                { return 'FROM'; }
+'|CURSOR|'            { return '|CURSOR|'; }
+'SELECT'              { return 'SELECT'; }
+'USE'                 { return 'USE'; }
+'FROM'                { return 'FROM'; }
 [a-zA-Z0-9_]*\b       { return 'STRING_IDENTIFIER'; }
 [a-zA-Z0-9_]*\b       { return 'STRING_IDENTIFIER'; }
-","                   { return ','; }
-"*"                   { return '*'; }
-";"                   { return ';'; }
+','                   { return ','; }
+'*'                   { return '*'; }
+';'                   { return ';'; }
 <<EOF>>               { return 'EOF'; }
 <<EOF>>               { return 'EOF'; }
 
 
 /lex
 /lex
 
 
 %start SqlStatement
 %start SqlStatement
+
+%{
+  var suggestions = {
+    statements: [{ value: 'SELECT' }, { value: 'USE' }]
+  }
+%}
+
 %%
 %%
 
 
 SqlStatement
 SqlStatement
- : "SELECT" SelectExpression "FROM" TableReference ";" EOF
+ : SelectStatement EOF
+ | UseStatement EOF
+ | STRING_IDENTIFIER '|CURSOR|' EOF
+   {
+     var upperCase = $1.toUpperCase();
+     return suggestions.statements.filter(function (statement) {
+       return statement.value.indexOf(upperCase) === 0;
+     });
+   }
+ | '|CURSOR|' EOF
+   {
+     return suggestions.statements;
+   }
+ ;
+
+UseStatement
+  : 'USE' STRING_IDENTIFIER ';'
+  ;
+
+SelectStatement
+ : 'SELECT' SelectExpression 'FROM' TableReference ';'
  ;
  ;
 
 
 SelectExpression
 SelectExpression
- : "*"
+ : '*'
  | SelectExpressionList
  | SelectExpressionList
  ;
  ;
 
 
 SelectExpressionList
 SelectExpressionList
  : DerivedColumn
  : DerivedColumn
- | SelectExpressionList "," DerivedColumn
+ | SelectExpressionList ',' DerivedColumn
  ;
  ;
 
 
 DerivedColumn
 DerivedColumn

+ 35 - 14
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.js

@@ -15,21 +15,34 @@
 // limitations under the License.
 // limitations under the License.
 
 
 define(function(require){
 define(function(require){
-var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,7],$V1=[6,13];
+var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,16],$V1=[13,18];
 var parser = {trace: function trace() { },
 var parser = {trace: function trace() { },
 yy: {},
 yy: {},
-symbols_: {"error":2,"SqlStatement":3,"SELECT":4,"SelectExpression":5,"FROM":6,"TableReference":7,";":8,"EOF":9,"*":10,"SelectExpressionList":11,"DerivedColumn":12,",":13,"STRING_IDENTIFIER":14,"$accept":0,"$end":1},
-terminals_: {2:"error",4:"SELECT",6:"FROM",8:";",9:"EOF",10:"*",13:",",14:"STRING_IDENTIFIER"},
-productions_: [0,[3,6],[5,1],[5,1],[11,1],[11,3],[12,1],[7,1]],
+symbols_: {"error":2,"SqlStatement":3,"SelectStatement":4,"EOF":5,"UseStatement":6,"STRING_IDENTIFIER":7,"|CURSOR|":8,"USE":9,";":10,"SELECT":11,"SelectExpression":12,"FROM":13,"TableReference":14,"*":15,"SelectExpressionList":16,"DerivedColumn":17,",":18,"$accept":0,"$end":1},
+terminals_: {2:"error",5:"EOF",7:"STRING_IDENTIFIER",8:"|CURSOR|",9:"USE",10:";",11:"SELECT",13:"FROM",15:"*",18:","},
+productions_: [0,[3,2],[3,2],[3,3],[3,2],[6,3],[4,5],[12,1],[12,1],[16,1],[16,3],[17,1],[14,1]],
 performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
 performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
 /* this == yyval */
 /* this == yyval */
 
 
 var $0 = $$.length - 1;
 var $0 = $$.length - 1;
 switch (yystate) {
 switch (yystate) {
+case 3:
+
+     var upperCase = $$[$0-2].toUpperCase();
+     return suggestions.statements.filter(function (statement) {
+       return statement.value.indexOf(upperCase) === 0;
+     });
+   
+break;
+case 4:
+
+     return suggestions.statements;
+   
+break;
 }
 }
 },
 },
-table: [{3:1,4:[1,2]},{1:[3]},{5:3,10:[1,4],11:5,12:6,14:$V0},{6:[1,8]},{6:[2,2]},{6:[2,3],13:[1,9]},o($V1,[2,4]),o($V1,[2,6]),{7:10,14:[1,11]},{12:12,14:$V0},{8:[1,13]},{8:[2,7]},o($V1,[2,5]),{9:[1,14]},{1:[2,1]}],
-defaultActions: {4:[2,2],11:[2,7],14:[2,1]},
+table: [{3:1,4:2,6:3,7:[1,4],8:[1,5],9:[1,7],11:[1,6]},{1:[3]},{5:[1,8]},{5:[1,9]},{8:[1,10]},{5:[1,11]},{7:$V0,12:12,15:[1,13],16:14,17:15},{7:[1,17]},{1:[2,1]},{1:[2,2]},{5:[1,18]},{1:[2,4]},{13:[1,19]},{13:[2,7]},{13:[2,8],18:[1,20]},o($V1,[2,9]),o($V1,[2,11]),{10:[1,21]},{1:[2,3]},{7:[1,23],14:22},{7:$V0,17:24},{5:[2,5]},{10:[1,25]},{10:[2,12]},o($V1,[2,10]),{5:[2,6]}],
+defaultActions: {8:[2,1],9:[2,2],11:[2,4],13:[2,7],18:[2,3],21:[2,5],23:[2,12],25:[2,6]},
 parseError: function parseError(str, hash) {
 parseError: function parseError(str, hash) {
     if (hash.recoverable) {
     if (hash.recoverable) {
         this.trace(str);
         this.trace(str);
@@ -181,6 +194,10 @@ parse: function parse(input) {
     return true;
     return true;
 }};
 }};
 
 
+  var suggestions = {
+   statements: [{ value: 'SELECT' }, { value: 'USE' }]
+  }
+
 
 
 /*
 /*
  Hive Select syntax from https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Select
  Hive Select syntax from https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Select
@@ -525,24 +542,28 @@ var YYSTATE=YY_START;
 switch($avoiding_name_collisions) {
 switch($avoiding_name_collisions) {
 case 0: /* skip whitespace */ 
 case 0: /* skip whitespace */ 
 break;
 break;
-case 1: return 4; 
+case 1: return 8; 
 break;
 break;
-case 2: return 6; 
+case 2: return 11; 
 break;
 break;
-case 3: return 14; 
+case 3: return 9; 
 break;
 break;
 case 4: return 13; 
 case 4: return 13; 
 break;
 break;
-case 5: return 10; 
+case 5: return 7; 
+break;
+case 6: return 18; 
+break;
+case 7: return 15; 
 break;
 break;
-case 6: return 8; 
+case 8: return 10; 
 break;
 break;
-case 7: return 9; 
+case 9: return 5; 
 break;
 break;
 }
 }
 },
 },
-rules: [/^(?:\s+)/,/^(?:SELECT\b)/,/^(?:FROM\b)/,/^(?:[a-zA-Z0-9_]*\b)/,/^(?:,)/,/^(?:\*)/,/^(?:;)/,/^(?:$)/],
-conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7],"inclusive":true}}
+rules: [/^(?:\s+)/,/^(?:\|CURSOR\|)/,/^(?:SELECT\b)/,/^(?:USE\b)/,/^(?:FROM\b)/,/^(?:[a-zA-Z0-9_]*\b)/,/^(?:,)/,/^(?:\*)/,/^(?:;)/,/^(?:$)/],
+conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9],"inclusive":true}}
 });
 });
 return lexer;
 return lexer;
 })();
 })();

+ 56 - 0
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpec.js

@@ -0,0 +1,56 @@
+// 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.
+define([
+  'knockout',
+  'desktop/js/autocomplete/sql',
+  'desktop/spec/autocompleterTestUtils'
+], function(ko, sql, testUtils) {
+
+  describe("sql.js", function() {
+    var subject;
+
+    beforeAll(function() {
+      sql.yy.parseError = function (msg) {
+        throw Error(msg);
+      };
+      jasmine.addMatchers(testUtils.autocompleteMatcher);
+    });
+
+    beforeEach(function () {
+    });
+
+    var assertAutoComplete = function(testDefinition) {
+      var result = sql.parse(testDefinition.beforeCursor + '|CURSOR|' + testDefinition.afterCursor);
+      expect(result).toEqualAutocompleteValues(testDefinition.expectedSuggestions);
+    };
+
+    it("should suggest keywords for empty statement", function() {
+      assertAutoComplete({
+        beforeCursor: '',
+        afterCursor: '',
+        expectedSuggestions: [ 'SELECT', 'USE' ]
+      });
+    });
+
+    it("should suggest keywords for started statement", function() {
+      assertAutoComplete({
+        beforeCursor: 'se',
+        afterCursor: '',
+        expectedSuggestions: [ 'SELECT' ]
+      });
+    })
+  });
+});

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

@@ -15,5 +15,6 @@
 ## limitations under the License.
 ## limitations under the License.
 ##
 ##
 
 
+<<<<<<< HEAD
 <%include file="jasmineRunner.html"/>
 <%include file="jasmineRunner.html"/>
 
 

+ 2 - 1
desktop/core/src/desktop/templates/jasmineRunner.html

@@ -92,7 +92,8 @@
       require([
       require([
         'desktop/spec/sqlAutocompleterSpec',
         'desktop/spec/sqlAutocompleterSpec',
         'desktop/spec/hdfsAutocompleterSpec',
         'desktop/spec/hdfsAutocompleterSpec',
-        'desktop/spec/apiHelperSpec'
+        'desktop/spec/apiHelperSpec',
+        'desktop/spec/autocomplete/sqlSpec'
       ], function () {
       ], function () {
         if (/PhantomJS/.test(window.navigator.userAgent)) {
         if (/PhantomJS/.test(window.navigator.userAgent)) {
           console.log("Running Jasmine tests with JUnitXmlReporter and TerminalReporter");
           console.log("Running Jasmine tests with JUnitXmlReporter and TerminalReporter");