Преглед изворни кода

HUE-7 [importer] Add support for creating manually a database

Romain Rigaux пре 9 година
родитељ
комит
5d8b5e5d21

+ 36 - 6
desktop/libs/indexer/src/indexer/api3.py

@@ -158,14 +158,48 @@ def importer_submit(request):
     collection_name = destination["name"]
     source['columns'] = destination['columns']
     job_handle = _index(request, source, collection_name)
+  elif destination['ouputFormat'] == 'database':
+    job_handle = create_database(request, source, destination)
   else:
     job_handle = _create_table(request, source, destination)
 
   return JsonResponse(job_handle)
 
 
+def create_database(request, source, destination):
+  database = destination['name']
+  comment = destination['description']
+
+  use_default_location = destination['useDefaultLocation']
+  external_path = destination['nonDefaultLocation']
+
+  sql = django_mako.render_to_string("gen/create_database_statement.mako", {
+      'database': {
+          'name': database,
+          'comment': comment,
+          'use_default_location': use_default_location,
+          'external_location': external_path,
+          'properties': [],
+      }
+    }
+  )
+
+  editor_type = 'hive'
+  on_success_url = reverse('metastore:show_tables', kwargs={'database': database})
+
+  try:
+    notebook = make_notebook(name='Execute and watch', editor_type=editor_type, statement=sql, status='ready', on_success_url=on_success_url)
+    return notebook.execute(request, batch=False)
+  except Exception, e:
+    raise PopupException(_('The table could not be created.'), detail=e.message)
+
+
 def _create_table(request, source, destination):
-  return _create_table_from_a_file(request, source, destination)
+  try:
+    notebook = _create_table_from_a_file(request, source, destination)
+    return notebook.execute(request, batch=False)
+  except Exception, e:
+    raise PopupException(_('The table could not be created.'), detail=e.message)
 
 
 def _create_table_from_a_file(request, source, destination):
@@ -291,14 +325,10 @@ def _create_table_from_a_file(request, source, destination):
         'table_name': table_name
     }
 
-  try:
     editor_type = 'impala' if table_format == 'kudu' else 'hive'
     on_success_url = reverse('metastore:describe_table', kwargs={'database': database, 'table': table_name})
-    notebook = make_notebook(name='Execute and watch', editor_type=editor_type, statement=sql, status='ready', database=database, on_success_url=on_success_url)
 
-    return notebook.execute(request, batch=False)
-  except Exception, e:
-    raise PopupException(_('The table could not be created.'), detail=e.message)
+    return make_notebook(name='Execute and watch', editor_type=editor_type, statement=sql, status='ready', database=database, on_success_url=on_success_url)
 
 
 def _index(request, file_format, collection_name, query=None):

+ 34 - 0
desktop/libs/indexer/src/indexer/templates/gen/create_database_statement.mako

@@ -0,0 +1,34 @@
+## 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.
+
+## TODO(philip): Check escaping more carefully?
+## TODO(philip): The whitespace management here is mediocre.
+##
+## |n is used throughout here, since this is not going to HTML.
+##
+## Reference: http://wiki.apache.org/hadoop/Hive/LanguageManual/DDL#Create_Table
+CREATE DATABASE ${database["name"]} \
+% if database["comment"]:
+COMMENT "${database["comment"] | n}"
+% endif
+% if not database.get("use_default_location", True):
+LOCATION "${database["external_location"] | n}"
+% endif
+% if database.get("properties", False):
+WITH DBPROPERTIES (\
+${ ','.join('%s=%s' % (prop["name"], prop["value"]) for prop in database["properties"]) }\
+)
+% endif

+ 38 - 9
desktop/libs/indexer/src/indexer/templates/importer.mako

@@ -268,7 +268,7 @@ ${ assist.assistPanel() }
             </div>
           </div>
 
-          <!-- ko if: createWizard.source.show -->
+          <!-- ko if: createWizard.source.show() && createWizard.source.inputFormat() != 'manual' -->
           <h3 class="card-heading simple">${_('Format')}</h3>
           <div class="card-body">
             <label data-bind="visible: ! createWizard.prefill.source_type">${_('File Type')} <select data-bind="options: $root.createWizard.fileTypes, optionsText: 'description', value: $root.createWizard.fileType"></select></label>
@@ -325,11 +325,11 @@ ${ assist.assistPanel() }
         </label>
 
         <label for="collectionName" class="control-label"><div>${ _('Name') }</div>
-          <!-- ko if: ouputFormat() != 'table' -->
+          <!-- ko if: ouputFormat() != 'table' || ouputFormat() != 'database' -->
             <input type="text" class="form-control input-xlarge" id="collectionName" data-bind="value: name, valueUpdate: 'afterkeydown'" placeholder="${ _('Name') }">
           <!-- /ko -->
 
-          <!-- ko if: ouputFormat() == 'table' -->
+          <!-- ko if: ouputFormat() == 'table' || ouputFormat() == 'database' -->
             <label for="path" class="control-label">
               <input type="text" data-bind="value: name, hivechooser: name, skipColumns: true, valueUpdate: 'afterkeydown'" placeholder="${ _('Name') }">
             </label>
@@ -471,7 +471,8 @@ ${ assist.assistPanel() }
           </label>
         <!-- /ko -->
 
-         <h3 class="card-heading simple">${_('Fields')}</h3>
+        <!-- ko if: ouputFormat() == 'table' || ouputFormat() == 'index' -->
+        <h3 class="card-heading simple">${_('Fields')}</h3>
         <form class="form-inline" data-bind="foreach: columns">
           <!-- ko if: $parent.ouputFormat() == 'table' -->
             <div data-bind="template: { name: 'table-field-template', data: $data }" class="margin-top-10 field"></div>
@@ -481,6 +482,20 @@ ${ assist.assistPanel() }
             <div data-bind="template: { name: 'index-field-template', data: $data }" class="margin-top-10 field"></div>
           <!-- /ko -->
         </form>
+        <!-- /ko -->
+
+        <!-- ko if: ouputFormat() == 'database' -->
+          <input type="text" class="form-control input-xlarge" data-bind="value: description, valueUpdate: 'afterkeydown'" placeholder="${ _('Description') }">
+
+          <label class="checkbox">
+            <input type="checkbox" data-bind="checked: useDefaultLocation"> ${_('Default location')}
+          </label>
+          <span data-bind="visible: ! useDefaultLocation()">
+            <label for="path" class="control-label"><div>${ _('External location') }</div>
+              <input type="text" class="form-control path input-xxlarge" data-bind="value: nonDefaultLocation, filechooser: nonDefaultLocation, filechooserOptions: { linkMarkup: true, skipInitialPathIfEmpty: true }, valueUpdate: 'afterkeydown'">
+            </label>
+          </span>
+        <!-- /ko -->
       </div>
       <!-- /ko -->
     </div>
@@ -929,6 +944,8 @@ ${ assist.assistPanel() }
           return self.table().length > 0;
         } else if (self.inputFormat() == 'query') {
           return self.query();
+        } else if (self.inputFormat() == 'manual') {
+          return true;
         }
       });
 
@@ -957,18 +974,30 @@ ${ assist.assistPanel() }
       });
     };
 
-    var Destination = function (vm) {
+    var Destination = function (vm, wizard) {
       var self = this;
 
       self.name = ko.observable('');
       self.description = ko.observable('');
 
       self.ouputFormat = ko.observable('table');
-      self.ouputFormats = ko.observableArray([
+      self.ouputFormatsList = ko.observableArray([
           {'name': 'Table', 'value': 'table'},
           {'name': 'Solr index', 'value': 'index'},
-          {'name': 'File', 'value': 'file'}
+          {'name': 'File', 'value': 'file'},
+          {'name': 'Database', 'value': 'database'},
       ]);
+      self.ouputFormats = ko.computed(function() {
+        return $.grep(self.ouputFormatsList(), function(format) {
+          if (format.value == 'database' && wizard.source.inputFormat() != 'manual') {
+            return false;
+          }
+          else if (format.value == 'file' && wizard.source.inputFormat() != 'manual') {
+            return false;
+          }
+          return true;
+        })
+      });
 
       self.format = ko.observable();
       self.columns = ko.observableArray();
@@ -1026,7 +1055,7 @@ ${ assist.assistPanel() }
       self.showCreate = ko.observable(false);
 
       self.source = new Source(vm, self);
-      self.destination = new Destination(vm);
+      self.destination = new Destination(vm, self);
 
       self.customDelimiters = ko.observable([
         {'value': '\\001', 'name': '^A (\\001)', 'ascii': 1},
@@ -1049,7 +1078,7 @@ ${ assist.assistPanel() }
       });
 
       self.readyToIndex = ko.computed(function () {
-        var validFields = self.destination.columns().length;
+        var validFields = self.destination.columns().length || self.destination.ouputFormat() == 'database';
         return self.destination.name().length > 0 && validFields;
       });