Browse Source

[spark] Dynamic parameter list

Romain Rigaux 12 years ago
parent
commit
23a83b1081

+ 1 - 1
apps/beeswax/src/beeswax/templates/layout.mako

@@ -44,7 +44,7 @@ def is_selected(section, matcher):
             <li class="${is_selected(section, 'query')}"><a href="${ url('spark:editor') }">${_('Query Editor')}</a></li>
             ##<li class="${is_selected(section, 'my queries')}"><a href="${ url(app_name + ':my_queries') }">${_('My Queries')}</a></li>
             <li class="${is_selected(section, 'saved queries')}"><a href="${ url('spark:list_designs') }">${_('Queries')}</a></li>
-            <li class="${is_selected(section, 'history')}"><a href="${ url('spark:list_query_history') }">${_('History')}</a></li>
+            ##<li class="${is_selected(section, 'history')}"><a href="${ url('spark:list_query_history') }">${_('History')}</a></li>
             <li class="currentApp">
               <a href="/spark">
                 ${ _('Browser') }

+ 7 - 13
apps/spark/src/spark/api.py

@@ -26,8 +26,7 @@ from desktop.context_processors import get_app_name
 from desktop.lib.exceptions import StructuredException
 
 from beeswax import models as beeswax_models
-from beeswax.forms import SaveForm
-from beeswax.views import authorized_get_history, safe_get_design, save_design
+from beeswax.views import safe_get_design, save_design
 
 from spark.job_server_api import get_api
 from spark.forms import SparkForm, QueryForm
@@ -38,13 +37,6 @@ from spark.design import SparkDesign
 LOG = logging.getLogger(__name__)
 
 
-class ResultEncoder(json.JSONEncoder):
-  def default(self, obj):
-    if isinstance(obj, datetime.datetime):
-      return obj.strftime('%Y-%m-%d %H:%M:%S %Z')
-    return super(ResultEncoder, self).default(obj)
-
-
 def error_handler(view_fn):
   def decorator(*args, **kwargs):
     try:
@@ -155,13 +147,15 @@ def execute(request, design_id=None):
 #      query_history.last_state = beeswax_models.QueryHistory.STATE.expired.index
 #      query_history.save()
 
+      params = '\n'.join(['%(name)s=%(value)s' % param for param in json.loads(form.cleaned_data['params'])])
+
       try:
         api = get_api(request.user)
 
         results = api.submit_job(
             form.cleaned_data['appName'],
             form.cleaned_data['classPath'],
-            data=form.cleaned_data['params'],
+            data=params,
             context=None if form.cleaned_data['autoContext'] else form.cleaned_data['context'],
             sync=False
         )
@@ -178,7 +172,7 @@ def execute(request, design_id=None):
   except RuntimeError, e:
     response['message']= str(e)
 
-  return HttpResponse(json.dumps(response, cls=ResultEncoder), mimetype="application/json")
+  return HttpResponse(json.dumps(response), mimetype="application/json")
 
 
 @error_handler
@@ -194,7 +188,7 @@ def save_query(request, design_id=None):
   form = QueryForm()
   api = get_api(request.user)
   app_names = api.jars()
-
+  print request.POST
   try:
     form.bind(request.POST)
     form.query.fields['appName'].choices = ((key, key) for key in app_names)
@@ -236,7 +230,7 @@ def design_to_dict(design):
     'classPath': spark_design.classPath,
     'autoContext': spark_design.autoContext,
     'context': spark_design.context,
-    'params': spark_design.params,
+    'params': json.loads(spark_design.params),
   }
 
 def get_query_form(request):

+ 7 - 1
apps/spark/src/spark/design.py

@@ -84,7 +84,13 @@ class SparkDesign(object):
       dic = json.loads(data)
       dic = dict(map(lambda k: (str(k), dic.get(k)), dic.keys()))
     else:
-      dic = {'VERSION': SERIALIZATION_VERSION, 'query': {'type': 3, 'appName': '', 'classPath': 'spark.jobserver.WordCountExample', 'autoContext': True, 'context': '', 'params': ''}}
+      dic = {
+          'VERSION': SERIALIZATION_VERSION,
+          'query': {
+              'type': 3, 'appName': '', 'classPath': 'spark.jobserver.WordCountExample', 'autoContext': True, 'context': '',
+              'params': json.dumps([{'name': 'aa', 'value': 'rr'}])
+          }
+      }
 
     if dic['VERSION'] != SERIALIZATION_VERSION:
       LOG.error('Design version mismatch. Found %s; expect %s' % (dic['VERSION'], SERIALIZATION_VERSION))

+ 1 - 1
apps/spark/src/spark/templates/common.mako

@@ -39,7 +39,7 @@ def is_selected(section, matcher):
             <li class="${is_selected(section, 'editor')}"><a href="${ url('spark:editor') }">${_('Query Editor')}</a></li>
             ##<li class="${is_selected(section, 'my queries')}"><a href="${ url(app_name + ':my_queries') }">${_('My Queries')}</a></li>
             <li class="${is_selected(section, 'queries')}"><a href="${ url('spark:list_designs') }">${_('Queries')}</a></li>
-            <li class="${is_selected(section, 'history')}"><a href="${ url('spark:list_query_history') }">${_('History')}</a></li>
+            ##<li class="${is_selected(section, 'history')}"><a href="${ url('spark:list_query_history') }">${_('History')}</a></li>
             <li class="currentApp">
               <a href="/spark">
                 ${ _('Browser') }

+ 24 - 80
apps/spark/src/spark/templates/editor.mako

@@ -125,7 +125,29 @@ ${ common.navbar('editor') }
                 </div>
               </div>
 
-              <textarea class="hide" tabindex="2" name="query" id="queryField"></textarea>
+				<div class="control-group">
+				  <div class="controls">
+				      <table class="table-condensed designTable">
+				        <thead>
+				          <tr>
+				            <th>${ _('Name') }</th>
+				            <th>${ _('Value') }</th>
+				            <th/>
+				          </tr>
+				        </thead>
+				        <tbody data-bind="foreach: query.params">
+				          <tr>
+				            <td><input type="text" class="span6 required propKey" data-bind="value: name" /></td>
+				            <td><input type="text" class="span6 required pathChooserKo" data-bind="fileChooser: $data, value: value" /></td>
+				            <td>
+				              <a class="btn" href="#" data-bind="click: $root.removeParam">${ _('Delete') }</a>
+				            </td>
+				          </tr>
+				        </tbody>
+				      </table>
+				      <button class="btn" data-bind="click: $root.addParam">${ _('Add') }</button>
+				  </div>
+				</div>
 
               <div class="actions">
                 <button data-bind="click: tryExecuteQuery" type="button" id="executeQuery" class="btn btn-primary" tabindex="2">${_('Execute')}</button>
@@ -347,15 +369,6 @@ ${ common.navbar('editor') }
     background: #DDDDDD;
   }
 
-  .CodeMirror {
-    border: 1px solid #eee;
-    margin-bottom: 20px;
-  }
-
-  .CodeMirror.cm-s-default {
-    height:100px;
-  }
-
   .editorError {
     color: #B94A48;
     background-color: #F2DEDE;
@@ -410,25 +423,15 @@ ${ common.navbar('editor') }
 <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
 <script src="/spark/static/js/spark.vm.js"></script>
-<script src="/static/ext/js/codemirror-3.11.js"></script>
-<link rel="stylesheet" href="/static/ext/css/codemirror.css">
-<script src="/static/ext/js/codemirror-sql.js"></script>
-<script src="/static/js/codemirror-sql-hint.js"></script>
-<script src="/static/js/codemirror-show-hint.js"></script>
 
 <link href="/static/ext/css/bootstrap-editable.css" rel="stylesheet">
 <script src="/static/ext/js/bootstrap-editable.min.js"></script>
 <script src="/static/ext/js/bootstrap-editable.min.js"></script>
 
 <script src="/static/ext/js/jquery/plugins/jquery-fieldselection.js" type="text/javascript"></script>
-<script src="/spark/static/js/autocomplete.utils.js" type="text/javascript" charset="utf-8"></script>
 
 <script type="text/javascript" charset="utf-8">
-  var codeMirror, viewModel;
-
-  var spark_AUTOCOMPLETE_BASE_URL = '/spark/api';
-  var spark_AUTOCOMPLETE_FAILS_SILENTLY_ON = [500, 404]; // error codes from spark/views.py - autocomplete
-  var spark_AUTOCOMPLETE_GLOBAL_CALLBACK = $.noop;
+  var viewModel;
 
   $(document).ready(function(){
     $("*[rel=tooltip]").tooltip({
@@ -463,31 +466,17 @@ ${ common.navbar('editor') }
     };
   }
 
-  function getHighlightedQuery() {
-    var selection = codeMirror.getSelection();
-    if (selection != "") {
-      return selection;
-    }
-    return null;
-  }
-
   function tryExecuteQuery() {
-    var query = getHighlightedQuery() || codeMirror.getValue();
-    viewModel.query.params(query);
     viewModel.executeQuery();
   }
 
   function trySaveQuery() {
-    var query = getHighlightedQuery() || codeMirror.getValue();
-    viewModel.query.params(query);
     if (viewModel.query.id() && viewModel.query.id() != -1) {
       viewModel.saveQuery();
     }
   }
 
   function trySaveAsQuery() {
-    var params = getHighlightedQuery() || codeMirror.getValue();
-    viewModel.query.params(params);
     $('#saveAsQueryModal').modal('show');
   }
 
@@ -512,51 +501,6 @@ ${ common.navbar('editor') }
     }
   }
 
-  var queryEditor = $("#queryField")[0];
-  var AUTOCOMPLETE_SET = CodeMirror.sqlHint;
-
-  codeMirror = CodeMirror(function (elt) {
-      queryEditor.parentNode.replaceChild(elt, queryEditor);
-    }, {
-      value: queryEditor.value,
-      readOnly: false,
-      lineNumbers: true,
-      mode: "text/x-sql",
-      extraKeys: {
-        "Ctrl-Space": function () {
-          CodeMirror.fromDot = false;
-          codeMirror.execCommand("autocomplete");
-        },
-        Tab: function (cm) {
-          $("#executeQuery").focus();
-        }
-      },
-      onKeyEvent: function (e, s) {
-        if (s.type == "keyup") {
-          if (s.keyCode == 190) {
-            var _line = codeMirror.getLine(codeMirror.getCursor().line);
-            var _partial = _line.substring(0, codeMirror.getCursor().ch);
-            var _table = _partial.substring(_partial.lastIndexOf(" ") + 1, _partial.length - 1);
-            if (codeMirror.getValue().toUpperCase().indexOf("FROM") > -1) {
-              rdbms_getTableColumns(viewModel.server().name(), viewModel.database(), _table, codeMirror.getValue(),
-                function (columns) {
-                  var _cols = columns.split(" ");
-                  for (var col in _cols) {
-                    _cols[col] = "." + _cols[col];
-                  }
-                  CodeMirror.catalogFields = _cols.join(" ");
-                  CodeMirror.fromDot = true;
-                  window.setTimeout(function () {
-                    codeMirror.execCommand("autocomplete");
-                  }, 100);  // timeout for IE8
-                });
-            }
-          }
-        }
-      }
-    });
-
-
   // Editables
   $("#query-name").editable({
     validate: function (value) {

+ 1 - 0
apps/spark/src/spark/views.py

@@ -43,6 +43,7 @@ def editor(request, design_id=None):
     job_id, design_id = design_id, None
   else:
     job_id = None
+
   action = request.path
   app_name = get_app_name(request)
   query_type = beeswax_models.SavedQuery.TYPES_MAPPING[app_name]

+ 11 - 2
apps/spark/static/js/spark.vm.js

@@ -35,7 +35,7 @@ function sparkViewModel() {
     'classPath': '',
     'context': '',
     'autoContext': true,
-    'params': '',
+    'params': [],
   });
 
   self.rows = ko.observableArray();
@@ -113,6 +113,14 @@ function sparkViewModel() {
     }
   };
 
+  self.addParam = function() {
+    self.query.params.push({name: "", value: ""});
+  };
+
+  self.removeParam = function() {
+    self.query.params.remove(this);
+  };
+
   function createDropdownItem(item) {
     return {
       'name': ko.observable(item),
@@ -172,7 +180,7 @@ function sparkViewModel() {
       data['query-classPath'] = self.classPath();
       data['query-autoContext'] = self.autoContext();
       data['query-context'] = self.context().name;
-      data['query-params'] = '';
+      data['query-params'] = JSON.stringify(self.query.params());
       var url = '/spark/api/save_query/';
       if (self.query.id() && self.query.id() != -1) {
         url += self.query.id() + '/';
@@ -203,6 +211,7 @@ function sparkViewModel() {
     data.classPath = self.classPath();
     data.autoContext = self.autoContext();
     data.context = self.context().name;
+    data.params = JSON.stringify(self.query.params());
     var request = {
       url: '/spark/api/execute',
       dataType: 'json',