You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2017/02/08 15:35:43 UTC
ambari git commit: AMBARI-19898. Hive View 2.0: Ability to edit table
through UI. (dipayanb)
Repository: ambari
Updated Branches:
refs/heads/branch-2.5 90d1ff1ad -> 151d2f167
AMBARI-19898. Hive View 2.0: Ability to edit table through UI. (dipayanb)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/151d2f16
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/151d2f16
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/151d2f16
Branch: refs/heads/branch-2.5
Commit: 151d2f1671c42db3e77c0305b29f6b1a5672f7a9
Parents: 90d1ff1
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Wed Feb 8 21:05:23 2017 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Wed Feb 8 21:05:23 2017 +0530
----------------------------------------------------------------------
.../view/hive20/internal/dto/ColumnInfo.java | 28 +-
.../view/hive20/internal/dto/TableStats.java | 11 +
.../internal/parsers/TableMetaParserImpl.java | 8 +
.../generators/AlterTableQueryGenerator.java | 82 +++---
.../query/generators/QueryGenerationUtils.java | 5 +-
.../view/hive20/resources/browser/DDLProxy.java | 2 +-
.../src/main/resources/ui/app/adapters/table.js | 6 +
.../resources/ui/app/components/column-item.js | 1 +
.../resources/ui/app/components/edit-table.js | 220 ++++++++++++++
.../ui/app/components/property-item.js | 1 +
.../app/components/table-advanced-settings.js | 5 +
.../ui/app/components/table-columns.js | 3 +-
.../ui/app/components/table-properties.js | 3 +-
.../resources/ui/app/configs/edit-table-tabs.js | 48 +++
.../hive20/src/main/resources/ui/app/router.js | 1 +
.../databases/database/tables/table/edit.js | 86 ++++++
.../ui/app/services/table-operations.js | 24 ++
.../src/main/resources/ui/app/styles/app.scss | 3 +
.../ui/app/templates/components/column-item.hbs | 13 +-
.../ui/app/templates/components/edit-table.hbs | 65 ++++
.../app/templates/components/property-item.hbs | 10 +-
.../components/table-advanced-settings.hbs | 295 ++++++++++---------
.../app/templates/components/table-columns.hbs | 1 +
.../templates/components/table-properties.hbs | 1 +
.../templates/components/table-statistics.hbs | 4 +
.../databases/database/tables/table.hbs | 2 +-
.../databases/database/tables/table/edit.hbs | 45 +++
.../AlterTableQueryGenerationSpecTest.groovy | 59 ----
.../AlterTableQueryGeneratorTest.java | 161 +++++++++-
29 files changed, 911 insertions(+), 282 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java
index 5daab91..9f179d1 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/ColumnInfo.java
@@ -20,6 +20,8 @@ package org.apache.ambari.view.hive20.internal.dto;
import org.apache.commons.lang3.builder.EqualsBuilder;
+import java.util.Objects;
+
/**
*
*/
@@ -82,28 +84,20 @@ public class ColumnInfo {
}
@Override
- public int hashCode() {
- int result = name.hashCode();
- result = 31 * result + type.hashCode();
- result = 31 * result + (precision != null ? precision.hashCode() : 0);
- result = 31 * result + (scale != null ? scale.hashCode() : 0);
- result = 31 * result + (comment != null ? comment.hashCode() : 0);
- return result;
- }
-
- @Override
public boolean equals(Object o) {
if (this == o) return true;
-
if (o == null || getClass() != o.getClass()) return false;
-
ColumnInfo that = (ColumnInfo) o;
+ return ((name == that.name) || (name != null && name.equalsIgnoreCase(that.name))) &&
+ ((type == that.type) || (type != null && type.equalsIgnoreCase(that.type))) &&
+ Objects.equals(precision, that.precision) &&
+ Objects.equals(scale, that.scale) &&
+ Objects.equals(comment, that.comment);
+ }
- return new EqualsBuilder()
- .append(getName(), that.getName())
- .append(getType(), that.getType())
- .append(getComment(), that.getComment())
- .isEquals();
+ @Override
+ public int hashCode() {
+ return Objects.hash(name);
}
@Override
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java
index b8b4f07..3048d22 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/dto/TableStats.java
@@ -24,12 +24,14 @@ package org.apache.ambari.view.hive20.internal.dto;
*/
public class TableStats {
public static final String NUM_FILES = "numFiles";
+ public static final String NUM_ROWS = "numRows";
public static final String COLUMN_STATS_ACCURATE = "COLUMN_STATS_ACCURATE";
public static final String RAW_DATA_SIZE = "rawDataSize";
public static final String TOTAL_SIZE = "totalSize";
private Boolean isTableStatsEnabled;
private Integer numFiles;
+ private Integer numRows;
private String columnStatsAccurate;
private Integer rawDataSize;
private Integer totalSize;
@@ -74,11 +76,20 @@ public class TableStats {
this.totalSize = totalSize;
}
+ public Integer getNumRows() {
+ return numRows;
+ }
+
+ public void setNumRows(Integer numRows) {
+ this.numRows = numRows;
+ }
+
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("TableStats{");
sb.append("isStatsEnabled='").append(isTableStatsEnabled).append('\'');
sb.append(", numFiles='").append(numFiles).append('\'');
+ sb.append(", numRows='").append(numRows).append('\'');
sb.append(", columnStatsAccurate='").append(columnStatsAccurate).append('\'');
sb.append(", rawDataSize='").append(rawDataSize).append('\'');
sb.append(", totalSize='").append(totalSize).append('\'');
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java
index b0c9fe4..f2a1933 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/parsers/TableMetaParserImpl.java
@@ -86,6 +86,9 @@ public class TableMetaParserImpl implements TableMetaParser<TableMeta> {
String numFiles = tableInfo.getParameters().get(TableStats.NUM_FILES);
tableInfo.getParameters().remove(TableStats.NUM_FILES);
+ String numRows = tableInfo.getParameters().get(TableStats.NUM_ROWS);
+ tableInfo.getParameters().remove(TableStats.NUM_ROWS);
+
String columnStatsAccurate = tableInfo.getParameters().get(TableStats.COLUMN_STATS_ACCURATE);
tableInfo.getParameters().remove(TableStats.COLUMN_STATS_ACCURATE);
@@ -100,6 +103,11 @@ public class TableMetaParserImpl implements TableMetaParser<TableMeta> {
tableStats.setNumFiles(Integer.valueOf(numFiles.trim()));
}
+ if(!Strings.isNullOrEmpty(numRows) && !Strings.isNullOrEmpty(numRows.trim())){
+ tableStats.setTableStatsEnabled(true);
+ tableStats.setNumRows(Integer.valueOf(numRows.trim()));
+ }
+
if(!Strings.isNullOrEmpty(rawDataSize) && !Strings.isNullOrEmpty(rawDataSize.trim())){
tableStats.setTableStatsEnabled(true);
tableStats.setRawDataSize(Integer.valueOf(rawDataSize.trim()));
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java
index 73f8266..b119f6a 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerator.java
@@ -31,16 +31,15 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import static org.apache.ambari.view.hive20.internal.query.generators.QueryGenerationUtils.isNullOrEmpty;
public class AlterTableQueryGenerator implements QueryGenerator {
private static final Logger LOG = LoggerFactory.getLogger(AlterTableQueryGenerator.class);
+ public static List<String> SYSTEM_PROPERTY_LIST = Arrays.asList("last_modified_time", "transient_lastDdlTime", "last_modified_by", "numRows", "numFiles", "rawDataSize", "totalSize", "COLUMN_STATS_ACCURATE");
+
private final TableMeta oldMeta;
private final TableMeta newMeta;
@@ -65,11 +64,6 @@ public class AlterTableQueryGenerator implements QueryGenerator {
public Optional<String> getQuery() {
List<Optional<String>> queries = new LinkedList<>();
- // TODO: rename of table name has to be handled separately as other queries depend on new name.
-// Optional<String> tableRenameQuery = this.generateTableRenameQuery(this.getOldMeta().getDatabase(),
-// this.getOldMeta().getTable(), this.getNewMeta().getDatabase(), this.getNewMeta().getTable());
-// queries.add(tableRenameQuery);
-
Optional<List<Optional<String>>> columnQuery = this.generateColumnQuery();
if (columnQuery.isPresent()) {
queries.addAll(columnQuery.get());
@@ -81,28 +75,30 @@ public class AlterTableQueryGenerator implements QueryGenerator {
queries.add(tablePropertiesQuery);
}
- if (null != this.getOldMeta().getStorageInfo() && null != this.getNewMeta().getStorageInfo()) {
- String oldSerde = this.getOldMeta().getStorageInfo().getSerdeLibrary();
- String newSerde = this.getNewMeta().getStorageInfo().getSerdeLibrary();
- Map<String, String> oldParameters = this.getOldMeta().getStorageInfo().getParameters();
- Map<String, String> newParameters = this.getNewMeta().getStorageInfo().getParameters();
-
- Optional<String> serdeProperties = this.generateSerdeQuery(oldSerde, oldParameters, newSerde, newParameters);
- queries.add(serdeProperties);
- }
-
- if (null != this.getOldMeta().getStorageInfo() && null != this.getNewMeta().getStorageInfo()) {
- List<String> oldBucketCols = this.getOldMeta().getStorageInfo().getBucketCols();
- List<ColumnOrder> oldSortCols = this.getOldMeta().getStorageInfo().getSortCols();
- String oldNumBuckets = this.getOldMeta().getStorageInfo().getNumBuckets();
-
- List<String> newBucketCols = this.getNewMeta().getStorageInfo().getBucketCols();
- List<ColumnOrder> newSortCols = this.getNewMeta().getStorageInfo().getSortCols();
- String newNumBuckets = this.getNewMeta().getStorageInfo().getNumBuckets();
-
- Optional<String> storagePropertyQuery = this.generateStoragePropertyQuery(oldBucketCols, oldSortCols, oldNumBuckets, newBucketCols, newSortCols, newNumBuckets);
- queries.add(storagePropertyQuery);
- }
+ // storage change is not required to be handled.
+// if (null != this.getOldMeta().getStorageInfo() && null != this.getNewMeta().getStorageInfo()) {
+// String oldSerde = this.getOldMeta().getStorageInfo().getSerdeLibrary();
+// String newSerde = this.getNewMeta().getStorageInfo().getSerdeLibrary();
+// Map<String, String> oldParameters = this.getOldMeta().getStorageInfo().getParameters();
+// Map<String, String> newParameters = this.getNewMeta().getStorageInfo().getParameters();
+//
+// Optional<String> serdeProperties = this.generateSerdeQuery(oldSerde, oldParameters, newSerde, newParameters);
+// queries.add(serdeProperties);
+// }
+
+ // change of bucketed columns is not required right now
+// if (null != this.getOldMeta().getStorageInfo() && null != this.getNewMeta().getStorageInfo()) {
+// List<String> oldBucketCols = this.getOldMeta().getStorageInfo().getBucketCols();
+// List<ColumnOrder> oldSortCols = this.getOldMeta().getStorageInfo().getSortCols();
+// String oldNumBuckets = this.getOldMeta().getStorageInfo().getNumBuckets();
+//
+// List<String> newBucketCols = this.getNewMeta().getStorageInfo().getBucketCols();
+// List<ColumnOrder> newSortCols = this.getNewMeta().getStorageInfo().getSortCols();
+// String newNumBuckets = this.getNewMeta().getStorageInfo().getNumBuckets();
+//
+// Optional<String> storagePropertyQuery = this.generateStoragePropertyQuery(oldBucketCols, oldSortCols, oldNumBuckets, newBucketCols, newSortCols, newNumBuckets);
+// queries.add(storagePropertyQuery);
+// }
List<String> queryList = FluentIterable.from(queries).filter(new Predicate<Optional<String>>() {
@@ -322,19 +318,33 @@ public class AlterTableQueryGenerator implements QueryGenerator {
return Optional.absent();
}
- Optional<String> generateTablePropertiesQuery(Map oldProps, Map newProps) {
+ Optional<String> generateTablePropertiesQuery(Map<String, String> oldProps, Map<String, String> newProps) {
Optional<String> query = createTablePropertiesQuery(oldProps, newProps);
if (query.isPresent()) return Optional.of(getQueryPerfix() + query.get());
else return Optional.absent();
}
- static Optional<String> createTablePropertiesQuery(Map oldProps, Map newProps) {
+ static Optional<String> createTablePropertiesQuery(Map<String, String> oldProps, Map<String, String> newProps) {
+ if( null == newProps && null == oldProps){
+ return Optional.absent();
+ }
+
if (null == newProps) {
- newProps = new HashMap();
+ newProps = new HashMap<>();
}
-// TODO ignore system generated table properties during comparison
- if (!QueryGenerationUtils.isEqual(oldProps, newProps)) {
+
+ if(null == oldProps){
+ oldProps = new HashMap<>();
+ }
+ // ignore system generated table properties during comparison
+
+ for(String prop : SYSTEM_PROPERTY_LIST){
+ newProps.remove(prop);
+ oldProps.remove(prop);
+ }
+
+ if (!QueryGenerationUtils.isEqual(oldProps, newProps) && !newProps.isEmpty()) {
return Optional.of(" SET TBLPROPERTIES (" + QueryGenerationUtils.getPropertiesAsKeyValues(newProps) + ")");
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java
index d9dc6e1..db219c4 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/internal/query/generators/QueryGenerationUtils.java
@@ -81,8 +81,11 @@ public class QueryGenerationUtils {
Map<Object, Object> modified = new HashMap<>();
Map<Object, Object> deleted = new HashMap<>();
- if(oldProps == null && newProps == null) return Optional.of(ret);
+ if(oldProps == null && newProps == null) return Optional.absent();
+ if(oldProps == null && newProps != null){
+ oldProps = new HashMap();
+ }
if(oldProps != null && newProps != null){
Set<Map.Entry> entrySet = oldProps.entrySet();
for(Map.Entry e : entrySet){
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java
index f75b008..f5ecdee 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/browser/DDLProxy.java
@@ -279,7 +279,7 @@ public class DDLProxy {
if(alterQuery.isPresent()){
return alterQuery.get();
}else{
- throw new ServiceException("Failed to generate alter table query for table " + oldTableMeta.getDatabase() + "." + oldTableMeta.getTable());
+ throw new ServiceException("Failed to generate alter table query for table " + oldTableMeta.getDatabase() + "." + oldTableMeta.getTable() + ". No difference was found.");
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
index 47174e4..e133419 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/table.js
@@ -44,6 +44,12 @@ export default DDLAdapter.extend({
return this.ajax(postURL, 'POST', { data: { tableInfo: tableMetaInfo } });
},
+ editTable(tableMetaInfo) {
+ let postURL = this.buildURL('table', null, null, 'query',
+ { databaseId: tableMetaInfo.database, tableName: tableMetaInfo.table });
+ return this.ajax(postURL, 'PUT', { data: { tableInfo: tableMetaInfo } });
+ },
+
deleteTable(database, tableName) {
let deletURL = this.buildURL('table', null, null, 'query', { databaseId: database, tableName: tableName });
return this.ajax(deletURL, 'DELETE');
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js b/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js
index d4e43f3..f2e45bd 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/column-item.js
@@ -23,6 +23,7 @@ export default Ember.Component.extend({
tagName: 'tr',
advancedOption: false,
datatypes: Ember.copy(datatypes),
+ editMode: false,
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/edit-table.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/edit-table.js b/contrib/views/hive20/src/main/resources/ui/app/components/edit-table.js
new file mode 100644
index 0000000..439dbcf
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/edit-table.js
@@ -0,0 +1,220 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.
+ */
+
+import Ember from 'ember';
+import datatypes from '../configs/datatypes';
+import Column from '../models/column';
+import Helper from '../configs/helpers';
+import TableProperty from '../models/table-property';
+
+export default Ember.Component.extend({
+
+ init() {
+ this._super(...arguments);
+ this.set('columns', Ember.A());
+ this.set('properties', []);
+ this.set('settings', {});
+ this.set('shouldAddBuckets', null);
+ this.set('settingErrors', []);
+ },
+
+ didReceiveAttrs() {
+ this.get('tabs').setEach('active', false);
+ let firstTab = this.get('tabs.firstObject');
+ firstTab.set('active', true);
+ this.set('columns', this._transformColumns());
+ this.set('properties', this._extractParameters());
+ this.set('settings', this._extractSettings());
+ },
+
+ actions: {
+ cancel() {
+ this.sendAction('cancel');
+ },
+
+ edit() {
+ if (this.validate()) {
+ this.sendAction('edit', {
+ database: this.get('table.database'),
+ table: this.get('table.table'),
+ columns: this.get('columns'),
+ settings: this.get('settings'),
+ properties: this.get('properties')
+ });
+ }
+ }
+ },
+
+ _transformColumns() {
+ let columns = [];
+ columns.pushObjects(this.get('table.columns').map((item) => {
+ return this._getColumnEntry(item, false, this._isClustered(this.get('table'), item.name))
+ }));
+
+ if (!Ember.isEmpty(this.get('table.partitionInfo'))) {
+ columns.pushObjects(this.get('table.partitionInfo.columns').map((item) => {
+ return this._getColumnEntry(item, true, false);
+ }));
+ }
+
+ return columns;
+ },
+
+ _getColumnEntry(column, isPartitioned, isClustered) {
+ return Column.create({
+ name: column.name,
+ type: this._getType(column.type),
+ comment: column.comment,
+ precision: column.precision,
+ scale: column.scale,
+ isPartitioned: isPartitioned,
+ isClustered: isClustered,
+ editing: !(isPartitioned || isClustered),
+ newColumn: false
+ });
+ },
+
+ _getType(typeString) {
+ return datatypes.find((item) => item.label.toLowerCase() === typeString.toLowerCase());
+ },
+
+ _isClustered(tableInfo, columnName) {
+ if (!Ember.isEmpty(tableInfo.get('storageInfo.bucketCols'))) {
+ return tableInfo.get('storageInfo.bucketCols').contains(columnName);
+ } else {
+ return false;
+ }
+ },
+
+ _extractParameters() {
+ if (!Ember.isEmpty(this.get('table.detailedInfo.parameters'))) {
+ let tableProperties = this.get('table.detailedInfo.parameters');
+ return Object.keys(tableProperties)
+ .filter((item) => item !== 'transactional')
+ .map((item) => {
+ return TableProperty.create({
+ key: item,
+ value: tableProperties[item],
+ editing: false,
+ newProperty: false
+ });
+ })
+ } else {
+ return [];
+ }
+ },
+
+ _extractSettings() {
+ let settings = {};
+ let tableInfo = this.get('table');
+
+ // filter out transaction parameter to set if transactional
+ if (!Ember.isEmpty(this.get('table.detailedInfo.parameters'))) {
+ let tableProperties = this.get('table.detailedInfo.parameters');
+ let transactional = Object.keys(tableProperties)
+ .filter((item) => item === 'transactional');
+ if (!Ember.isEmpty(transactional)) {
+ settings.transactional = true;
+ }
+ }
+
+ // Find if already clustered, then set number of buckets
+ if (!Ember.isEmpty(tableInfo.get('storageInfo.bucketCols'))) {
+ settings.numBuckets = parseInt(tableInfo.get('storageInfo.numBuckets'))
+ this.set('shouldAddBuckets', true);
+ }
+
+ return settings;
+ },
+
+ validate() {
+ if (!(this.checkColumnUniqueness() &&
+ this.validateColumns())) {
+ this.selectTab("edit.table.columns");
+ return false;
+ }
+
+ if(!(this.validateNumBuckets())) {
+ this.selectTab("edit.table.advanced");
+ return false;
+ }
+
+ if (!(this.validateTableProperties())) {
+ this.selectTab("edit.table.properties");
+ return false;
+ }
+ return true;
+ },
+
+ checkColumnUniqueness() {
+ let columnNames = [];
+ for (let i = 0; i < this.get('columns.length'); i++) {
+ let column = this.get('columns').objectAt(i);
+ column.clearError();
+ if (columnNames.indexOf(column.get('name')) === -1) {
+ columnNames.pushObject(column.get('name'));
+ } else {
+ column.get('errors').push({type: 'name', error: 'Name should be unique'});
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ validateColumns() {
+ for (let i = 0; i < this.get('columns.length'); i++) {
+ let column = this.get('columns').objectAt(i);
+ if (!column.validate()) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ validateTableProperties() {
+ for (let i = 0; i < this.get('properties.length'); i++) {
+ let property = this.get('properties').objectAt(i);
+ if (!property.validate()) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ validateNumBuckets() {
+ let clusteredColumns = this.get('columns').filterBy('isClustered', true);
+ if(clusteredColumns.get('length') > 0 &&
+ (Ember.isEmpty(this.get('settings.numBuckets')) ||
+ !Helper.isInteger(this.get('settings.numBuckets')))) {
+ this.get('settingErrors').pushObject({type: 'numBuckets', error: "Some columns are clustered, Number of buckets are required."});
+ return false;
+ }
+
+ return true;
+ },
+
+ selectTab(link) {
+ this.get('tabs').setEach('active', false);
+ let selectedTab = this.get('tabs').findBy('link', link);
+ if (!Ember.isEmpty(selectedTab)) {
+ selectedTab.set('active', true);
+ }
+ }
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js b/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js
index 96ef473..edc2c44 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/property-item.js
@@ -20,6 +20,7 @@ import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'tr',
+ editMode: false,
didInsertElement() {
Ember.run.later( () => {
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js b/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js
index 5e50a5c..99a9bb6 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/table-advanced-settings.js
@@ -29,6 +29,8 @@ export default Ember.Component.extend({
showRowFormatInput: false,
shouldAddBuckets: false,
errors: [],
+ editMode: false,
+ disableTransactionInput: false,
settings: {},
@@ -67,6 +69,9 @@ export default Ember.Component.extend({
this.set('selectedNullDefinition', this.get('settings.rowFormat.nullDefinedAs'));
this.set('selectedEscapeDefinition', this.get('settings.rowFormat.escapeDefinedAs'));
}
+ if(!Ember.isEmpty(this.get('settings.transactional')) && this.get('settings.transactional') && this.get('editMode')) {
+ this.set('disableTransactionInput', true);
+ }
},
locationInputObserver: Ember.observer('showLocationInput', function () {
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js b/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js
index 5479496..7d83353 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/table-columns.js
@@ -21,6 +21,7 @@ import Column from '../models/column';
export default Ember.Component.extend({
columns: [],
+ editMode: false,
shouldAddBuckets: null,
clusteredColumnObserver: Ember.observer('columns.@each.isClustered', function(sender, key, value, rev) {
@@ -37,7 +38,7 @@ export default Ember.Component.extend({
actions: {
addNewColumn() {
- let newEmptyColumn = Column.create({editing: true});
+ let newEmptyColumn = Column.create({editing: true, newColumn: true});
this.get('columns').pushObject(newEmptyColumn);
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js b/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js
index 1ba15cc..f1ee645 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/components/table-properties.js
@@ -21,10 +21,11 @@ import TableProperty from '../models/table-property';
export default Ember.Component.extend({
properties: [],
+ editMode: false,
actions: {
addNewRow() {
- let emptyProperty = TableProperty.create({editing: true});
+ let emptyProperty = TableProperty.create({editing: true, newProperty: true});
this.get('properties').pushObject(emptyProperty);
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/configs/edit-table-tabs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/configs/edit-table-tabs.js b/contrib/views/hive20/src/main/resources/ui/app/configs/edit-table-tabs.js
new file mode 100644
index 0000000..49e702f
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/configs/edit-table-tabs.js
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.
+ */
+
+import Ember from 'ember';
+
+let editTableTabs = [
+ Ember.Object.create({
+ name: 'columns',
+ label: 'COLUMNS',
+ transition: false,
+ link: 'edit.table.columns',
+ faIcon: 'list'
+ }),
+
+ Ember.Object.create({
+ name: 'advanced',
+ label: 'ADVANCED',
+ transition: false,
+ link: 'edit.table.advanced',
+ faIcon: 'file-text-o'
+ }),
+
+ Ember.Object.create({
+ name: 'properties',
+ label: 'TABLE PROPERTIES',
+ transition: false,
+ link: 'edit.table.properties',
+ faIcon: 'file-text-o'
+ })
+
+];
+
+export default editTableTabs;
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/router.js b/contrib/views/hive20/src/main/resources/ui/app/router.js
index c781a34..ffb0f83 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/router.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/router.js
@@ -45,6 +45,7 @@ Router.map(function() {
this.route('new');
this.route('upload-table');
this.route('table', {path: '/:name'}, function() {
+ this.route('edit');
this.route('rename');
this.route('columns');
this.route('partitions');
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/edit.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/edit.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/edit.js
new file mode 100644
index 0000000..47340ba
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/edit.js
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.
+ */
+
+import TableMetaRouter from './table-meta-router';
+import tabs from '../../../../../configs/edit-table-tabs';
+
+export default TableMetaRouter.extend({
+
+ tableOperations: Ember.inject.service(),
+
+ activate() {
+ let tableController = this.controllerFor('databases.database.tables.table');
+ this.set('existingTabs', tableController.get('tabs'));
+ tableController.set('tabs', []);
+ },
+
+ deactivate() {
+ let tableController = this.controllerFor('databases.database.tables.table');
+ tableController.set('tabs', this.get('existingTabs'));
+ },
+
+ setupController(controller, model) {
+ this._super(controller, model);
+ controller.set('tabs', Ember.copy(tabs));
+ },
+
+ actions: {
+
+ cancel() {
+ this.transitionTo('databases.database.tables');
+ },
+
+ edit(settings) {
+ this._modalStatus(true, 'Submitting request to edit table');
+ this.get('tableOperations').editTable(settings).then((job) => {
+ this._modalStatus(true, 'Waiting for the table edit job to complete');
+ return this.get('tableOperations').waitForJobToComplete(job.get('id'), 5 * 1000);
+ }).then((status) => {
+ this._modalStatus(true, 'Successfully edited the table');
+ this._transitionToTables();
+ }).catch((err) => {
+ this._modalStatus(true, 'Failed to edit table');
+ this._alertMessage('Failed to edit table', err);
+ this._transitionToTables();
+ });
+ }
+
+ },
+
+ _modalStatus(status, message) {
+ this.controller.set('showModal', status);
+ if(status) {
+ this.controller.set('modalMessage', message);
+ }
+ },
+
+ _transitionToTables() {
+ Ember.run.later(() => {
+ this._modalStatus(false);
+ this.send('refreshTableInfo');
+ this.transitionTo('databases.database.tables.table');
+ }, 2000);
+ },
+
+ _alertMessage(message, err) {
+ console.log(message, err);
+ // TODO: user alert message here
+ }
+
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
index d11816c..a5be574 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/services/table-operations.js
@@ -45,6 +45,30 @@ export default Ember.Service.extend({
});
},
+ editTable(settings) {
+ let detailedInfo = this._getDetailedInfo(settings);
+ let storageInfo = this._getStorageInfo(settings);
+ let columns = this._getColumns(settings);
+ let partitionColumns = this._getPartitionColumns(settings);
+
+ let tableInfo = Ember.Object.create({
+ database: settings.database,
+ table: settings.table,
+ columns: columns,
+ partitionInfo: { columns: partitionColumns },
+ detailedInfo: detailedInfo,
+ storageInfo: storageInfo
+ });
+ return new Promise((resolve, reject) => {
+ this.get('store').adapterFor('table').editTable(tableInfo).then((data) => {
+ this.get('store').pushPayload(data);
+ resolve(this.get('store').peekRecord('job', data.job.id));
+ }, (err) => {
+ reject(err);
+ });
+ });
+ },
+
deleteTable(database, table) {
return new Ember.RSVP.Promise((resolve, reject) => {
this.get('store').adapterFor('table').deleteTable(database, table).then((data) => {
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
index bce9f69..968d3b3 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
+++ b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
@@ -270,6 +270,9 @@ pre {
.create-table-controls {
padding-top: 15px;
padding-bottom: 15px;
+ .warning {
+ margin-top: 15px;
+ }
}
.column-precision {
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
index 73fac89..b649d5b 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/column-item.hbs
@@ -27,7 +27,7 @@
</td>
<td>
{{#power-select
- disabled=notEditing
+ disabled=(not column.editing)
selected=column.type
options=datatypes
searchField="label"
@@ -114,10 +114,13 @@
</td>
<td>
<div class="text-center">
- {{#unless column.editing}}
- <button class="btn btn-success" {{action "edit"}}>{{fa-icon "check"}} Edit</button>
- {{/unless}}
- <button class="btn btn-danger" {{action "delete"}}>{{fa-icon "times"}} Delete</button>
+ {{#if (or column.newColumn (not editMode)) }}
+ {{#unless column.editing}}
+ <button class="btn btn-success" {{action "edit"}}>{{fa-icon "check"}} Edit</button>
+ {{/unless}}
+ <button class="btn btn-danger" {{action "delete"}}>{{fa-icon "times"}} Delete</button>
+ {{/if}}
+
</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/edit-table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/edit-table.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/edit-table.hbs
new file mode 100644
index 0000000..70e7824
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/edit-table.hbs
@@ -0,0 +1,65 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF 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.
+}}
+
+<div class="col-md-12">
+ {{#tabs-pane tabs=tabs inverse=true as |tab|}}
+ {{tabs-item tab=tab tabs=tabs}}
+ {{/tabs-pane}}
+
+ <div class="create-table-inner">
+ <div class="row">
+ {{#each tabs as |tab|}}
+ {{#if tab.active}}
+ {{#if (eq tab.link "edit.table.columns")}}
+ {{#if hasEmptyColumnsError}}
+ <div class="alert alert-danger create-table-error">
+ {{emptyColumnsErrorText}}
+ </div>
+ {{/if}}
+ {{table-columns columns=columns shouldAddBuckets=shouldAddBuckets editMode=true}}
+ {{/if}}
+ {{#if (eq tab.link "edit.table.properties")}}
+ {{table-properties properties=properties editMode=true}}
+ {{/if}}
+ {{#if (eq tab.link "edit.table.advanced")}}
+ {{table-advanced-settings settings=settings shouldAddBuckets=shouldAddBuckets
+ errors=settingErrors editMode=true}}
+ {{/if}}
+ {{/if}}
+ {{/each}}
+ </div>
+
+ </div>
+ <div class="create-table-controls">
+ <div class="row">
+ <div class="col-md-2">
+ <button class="btn btn-success" {{action "edit"}}>{{fa-icon "edit"}} Edit</button>
+ <button class="btn btn-warning" {{action "cancel"}}>{{fa-icon "times"}} Cancel</button>
+ </div>
+ </div>
+ <div class="row">
+ <div class=" col-md-12 warning">
+ <div class="alert alert-danger">
+ <p>{{fa-icon "exclamation-circle" size="2"}} <strong>Warning:</strong> Operation is executed as multiple statements and they are not transactional in its entirety.</p>
+ </div>
+ </div>
+ </div>
+ </div>
+
+
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs
index e0ba696..26e5d9b 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/property-item.hbs
@@ -37,9 +37,11 @@
<td>
<div class="text-center">
- {{#unless property.editing}}
- <button class="btn btn-success" {{action "edit"}}>{{fa-icon "check"}} Edit</button>
- {{/unless}}
- <button class="btn btn-danger" {{action "delete"}}>{{fa-icon "times"}} Delete</button>
+ {{#if (or property.newProperty (not editMode)) }}
+ {{#unless property.editing}}
+ <button class="btn btn-success" {{action "edit"}}>{{fa-icon "check"}} Edit</button>
+ {{/unless}}
+ <button class="btn btn-danger" {{action "delete"}}>{{fa-icon "times"}} Delete</button>
+ {{/if}}
</div>
</td>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs
index 18f22f9..f7a92ce 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-advanced-settings.hbs
@@ -29,7 +29,7 @@
<label class="col-md-2 control-label">Transactional</label>
<div class="col-md-4">
<label>
- {{input type="checkbox" checked=settings.transactional}}
+ {{input type="checkbox" checked=settings.transactional disabled=disableTransactionInput}}
</label>
</div>
</div>
@@ -39,7 +39,6 @@
<label class="col-md-2 control-label">Number of buckets</label>
<div class="col-md-6">
<div class="{{if hasNumBucketError 'has-error'}}">
-
{{input type="number" class="form-control" value=settings.numBuckets}}
{{#if hasNumBucketError}}
<span class="help-block">{{numBucketErrorText}}</span>
@@ -53,174 +52,178 @@
</div>
-<div class="panel panel-info">
- <div class="panel-heading">
- <div class="panel-title">
- <button class="btn btn-primary {{if showLocationInput 'active'}}" {{action "toggleLocation"}}>
- {{fa-icon (if showLocationInput "minus" "plus")}}
- </button>
- Add Location
+{{#if (not editMode)}}
+ <div class="panel panel-info">
+ <div class="panel-heading">
+ <div class="panel-title">
+ <button class="btn btn-primary {{if showLocationInput 'active'}}" {{action "toggleLocation"}}>
+ {{fa-icon (if showLocationInput "minus" "plus")}}
+ </button>
+ Add Location
+ </div>
</div>
- </div>
- {{#if showLocationInput}}
- <div class="panel-body">
- <div class="row">
- <div class="col-md-6">
- {{input type="text" class="form-control" value=settings.location}}
+ {{#if showLocationInput}}
+ <div class="panel-body">
+ <div class="row">
+ <div class="col-md-6">
+ {{input type="text" class="form-control" value=settings.location}}
+ </div>
+ <button class="btn btn-success" {{action "toggleDirectoryViewer"}}>Select HDFS Directory</button>
</div>
- <button class="btn btn-success" {{action "toggleDirectoryViewer"}}>Select HDFS Directory</button>
+ {{#if showDirectoryViewer}}
+ {{hdfs-viewer-modal
+ showSelectedPath=true
+ close="closeHdfsModal"
+ selected="hdfsPathSelected"
+ }}
+ {{/if}}
</div>
- {{#if showDirectoryViewer}}
- {{hdfs-viewer-modal
- showSelectedPath=true
- close="closeHdfsModal"
- selected="hdfsPathSelected"
- }}
- {{/if}}
- </div>
- {{/if}}
-</div>
+ {{/if}}
+ </div>
-<div class="panel panel-info">
- <div class="panel-heading">
- <div class="panel-title">
- <button class="btn btn-primary {{if showFileFormatInput 'active'}}" {{action "toggleFileFormat"}}>
- {{fa-icon (if showFileFormatInput "minus" "plus")}}
- </button>
- Add File Format
+ <div class="panel panel-info">
+ <div class="panel-heading">
+ <div class="panel-title">
+ <button class="btn btn-primary {{if showFileFormatInput 'active'}}" {{action "toggleFileFormat"}}>
+ {{fa-icon (if showFileFormatInput "minus" "plus")}}
+ </button>
+ Add File Format
+ </div>
</div>
- </div>
- {{#if showFileFormatInput}}
- <div class="panel-body">
- <div class="row">
- <div class="col-md-6">
- {{#power-select
- selected=selectedFileFormat
- options=fileFormats
- searchField="name"
- searchPlaceholder="Enter data type"
- onchange=(action "fileFormatSelected") as |parameter|}}
- {{parameter.name}}
- {{/power-select}}
+ {{#if showFileFormatInput}}
+ <div class="panel-body">
+ <div class="row">
+ <div class="col-md-6">
+ {{#power-select
+ selected=selectedFileFormat
+ options=fileFormats
+ searchField="name"
+ searchPlaceholder="Enter data type"
+ onchange=(action "fileFormatSelected") as |parameter|}}
+ {{parameter.name}}
+ {{/power-select}}
+ </div>
</div>
- </div>
- {{#if customFileFormat}}
- <div class="row fileformat-custom-row">
- <div class="col-md-6 form-horizontal">
- <div class="form-group">
- <label class="col-md-3 control-label">Input Format</label>
- <div class="col-md-9">
- {{input type="text" class="form-control" value=settings.fileFormat.inputFormat
- placeholder="Input format class"}}
+ {{#if customFileFormat}}
+ <div class="row fileformat-custom-row">
+ <div class="col-md-6 form-horizontal">
+ <div class="form-group">
+ <label class="col-md-3 control-label">Input Format</label>
+ <div class="col-md-9">
+ {{input type="text" class="form-control" value=settings.fileFormat.inputFormat
+ placeholder="Input format class"}}
+ </div>
</div>
- </div>
- <div class="form-group">
- <label class="col-md-3 control-label">Output Format</label>
- <div class="col-md-9">
- {{input type="text" class="form-control" value=settings.fileFormat.outputFormat
- placeholder="Output format class"}}
+ <div class="form-group">
+ <label class="col-md-3 control-label">Output Format</label>
+ <div class="col-md-9">
+ {{input type="text" class="form-control" value=settings.fileFormat.outputFormat
+ placeholder="Output format class"}}
+ </div>
</div>
</div>
</div>
- </div>
- {{/if}}
+ {{/if}}
- </div>
- {{/if}}
-</div>
+ </div>
+ {{/if}}
+ </div>
-<div class="panel panel-info">
- <div class="panel-heading">
- <div class="panel-title">
- <button class="btn btn-primary {{if showRowFormatInput 'active'}}" {{action "toggleRowFormat"}}>
- {{fa-icon (if showRowFormatInput "minus" "plus")}}
- </button>
- Add Row Format
+ <div class="panel panel-info">
+ <div class="panel-heading">
+ <div class="panel-title">
+ <button class="btn btn-primary {{if showRowFormatInput 'active'}}" {{action "toggleRowFormat"}}>
+ {{fa-icon (if showRowFormatInput "minus" "plus")}}
+ </button>
+ Add Row Format
+ </div>
</div>
- </div>
- {{#if showRowFormatInput}}
- <div class="panel-body rowformat-custom-row">
- <div class="row">
- <div class="col-md-6 form-horizontal">
- <div class="form-group">
- <label class="col-md-4 control-label">Fields Terminated By</label>
- <div class="col-md-7">
- {{#power-select
- selected=selectedFieldTerminator
- options=terminationChars
- searchField="name"
- searchPlaceholder="Enter terminator character"
- onchange=(action "fieldTerminatorSelected") as |parameter|}}
- {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
- {{/power-select}}
- </div>
- <div class="col-md-1">
- <a class="text-danger" {{action "clearFieldTerminator"}}>{{fa-icon "times" size="lg"}}</a>
+ {{#if showRowFormatInput}}
+ <div class="panel-body rowformat-custom-row">
+ <div class="row">
+ <div class="col-md-6 form-horizontal">
+ <div class="form-group">
+ <label class="col-md-4 control-label">Fields Terminated By</label>
+ <div class="col-md-7">
+ {{#power-select
+ selected=selectedFieldTerminator
+ options=terminationChars
+ searchField="name"
+ searchPlaceholder="Enter terminator character"
+ onchange=(action "fieldTerminatorSelected") as |parameter|}}
+ {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
+ {{/power-select}}
+ </div>
+ <div class="col-md-1">
+ <a class="text-danger" {{action "clearFieldTerminator"}}>{{fa-icon "times" size="lg"}}</a>
+ </div>
</div>
</div>
</div>
- </div>
- <div class="row">
- <div class="col-md-6 form-horizontal">
- <div class="form-group">
- <label class="col-md-4 control-label">Lines Terminated By</label>
- <div class="col-md-7">
- {{#power-select
- selected=selectedLinesTerminator
- options=terminationChars
- searchField="name"
- searchPlaceholder="Enter terminator character"
- onchange=(action "linesTerminatorSelected") as |parameter|}}
- {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
- {{/power-select}}
- </div>
- <div class="col-md-1">
- <a class="text-danger" {{action "clearLinesTerminator"}}>{{fa-icon "times" size="lg"}}</a>
+ <div class="row">
+ <div class="col-md-6 form-horizontal">
+ <div class="form-group">
+ <label class="col-md-4 control-label">Lines Terminated By</label>
+ <div class="col-md-7">
+ {{#power-select
+ selected=selectedLinesTerminator
+ options=terminationChars
+ searchField="name"
+ searchPlaceholder="Enter terminator character"
+ onchange=(action "linesTerminatorSelected") as |parameter|}}
+ {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
+ {{/power-select}}
+ </div>
+ <div class="col-md-1">
+ <a class="text-danger" {{action "clearLinesTerminator"}}>{{fa-icon "times" size="lg"}}</a>
+ </div>
</div>
</div>
</div>
- </div>
- <div class="row">
- <div class="col-md-6 form-horizontal">
- <div class="form-group">
- <label class="col-md-4 control-label">Null Defined As</label>
- <div class="col-md-7">
- {{#power-select
- selected=selectedNullDefinition
- options=terminationChars
- searchField="name"
- searchPlaceholder="Enter terminator character"
- onchange=(action "nullDefinedAsSelected") as |parameter|}}
- {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
- {{/power-select}}
- </div>
- <div class="col-md-1">
- <a class="text-danger" {{action "clearNullDefinition"}}>{{fa-icon "times" size="lg"}}</a>
+ <div class="row">
+ <div class="col-md-6 form-horizontal">
+ <div class="form-group">
+ <label class="col-md-4 control-label">Null Defined As</label>
+ <div class="col-md-7">
+ {{#power-select
+ selected=selectedNullDefinition
+ options=terminationChars
+ searchField="name"
+ searchPlaceholder="Enter terminator character"
+ onchange=(action "nullDefinedAsSelected") as |parameter|}}
+ {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
+ {{/power-select}}
+ </div>
+ <div class="col-md-1">
+ <a class="text-danger" {{action "clearNullDefinition"}}>{{fa-icon "times" size="lg"}}</a>
+ </div>
</div>
</div>
</div>
- </div>
- <div class="row">
- <div class="col-md-6 form-horizontal">
- <div class="form-group">
- <label class="col-md-4 control-label">Escape Defined As</label>
- <div class="col-md-7">
- {{#power-select
- selected=selectedEscapeDefinition
- options=terminationChars
- searchField="name"
- searchPlaceholder="Enter terminator chanracter"
- onchange=(action "escapeDefinedAsSelected") as |parameter|}}
- {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
- {{/power-select}}
- </div>
- <div class="col-md-1">
- <a class="text-danger" {{action "clearEscapeDefinition"}}>{{fa-icon "times" size="lg"}}</a>
+ <div class="row">
+ <div class="col-md-6 form-horizontal">
+ <div class="form-group">
+ <label class="col-md-4 control-label">Escape Defined As</label>
+ <div class="col-md-7">
+ {{#power-select
+ selected=selectedEscapeDefinition
+ options=terminationChars
+ searchField="name"
+ searchPlaceholder="Enter terminator chanracter"
+ onchange=(action "escapeDefinedAsSelected") as |parameter|}}
+ {{parameter.name}}{{#if parameter.description}} - {{parameter.description}}{{/if}}
+ {{/power-select}}
+ </div>
+ <div class="col-md-1">
+ <a class="text-danger" {{action "clearEscapeDefinition"}}>{{fa-icon "times" size="lg"}}</a>
+ </div>
</div>
</div>
</div>
</div>
- </div>
- {{/if}}
-</div>
+ {{/if}}
+ </div>
+{{/if}}
+
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs
index f5fc547..b942136 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-columns.hbs
@@ -31,6 +31,7 @@
{{column-item column=column
columnDeleted="columnDeleted"
columnUpdated="columnUpdated"
+ editMode=editMode
}}
{{/each}}
<tr class="new-settings text-center">
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
index 953ef84..802941e 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
@@ -29,6 +29,7 @@
{{property-item property=property
propertyItemDeleted="itemDeleted"
propertyItemUpdated="itemUpdated"
+ editMode=editMode
}}
{{/each}}
<tr class="new-settings text-center">
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs
index 0ee3b13..5f62fca 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-statistics.hbs
@@ -51,6 +51,10 @@
<td>{{tableStats.numFiles}}</td>
</tr>
<tr>
+ <td>Number of Rows</td>
+ <td>{{tableStats.numRows}}</td>
+ </tr>
+ <tr>
<td>Raw Data Size</td>
<td>{{tableStats.rawDataSize}}</td>
</tr>
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
index e3fe400..9a1306a 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table.hbs
@@ -25,7 +25,7 @@
{{fa-icon "navicon"}}
</button>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1">
- <li><a href="#" class="text-uppercase" {{action "editTable" model}}>{{fa-icon "edit"}} Edit</a></li>
+ <li>{{#link-to "databases.database.tables.table.edit" class="text-uppercase"}}{{fa-icon "edit"}} Edit{{/link-to}}</li>
<li>{{#link-to "databases.database.tables.table.rename" class="text-uppercase"}}{{fa-icon "edit"}} Rename{{/link-to}}</li>
<li><a href="#" class="text-uppercase" {{action "deleteTable" model}}>{{fa-icon "trash"}} Delete</a></li>
</ul>
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/edit.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/edit.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/edit.hbs
new file mode 100644
index 0000000..79f1701
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/edit.hbs
@@ -0,0 +1,45 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF 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.
+}}
+
+<div class="row">
+ <div class="alert alert-info">
+ <p class="lead">{{fa-icon "pencil-square-o" size=1}} Edit table <strong class="text-uppercase">{{table.table}}</strong></p>
+ </div>
+</div>
+
+<div class="row">
+ {{edit-table tabs=tabs
+ table=table
+ cancel="cancel"
+ edit="edit"}}
+</div>
+
+{{#if showModal}}
+ {{#modal-dialog
+ translucentOverlay=true
+ container-class="modal-dialog modal-sm"}}
+ <div class="modal-content">
+ <div class="modal-header text-danger">
+ <p class="modal-title">{{fa-icon "plus"}} Create Database</p>
+ </div>
+ <div class="modal-body text-center text-primary">
+ <p>{{modalMessage}}</p>
+ </div>
+ </div><!-- /.modal-content -->
+ {{/modal-dialog}}
+{{/if}}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerationSpecTest.groovy
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerationSpecTest.groovy b/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerationSpecTest.groovy
deleted file mode 100644
index 874e268..0000000
--- a/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGenerationSpecTest.groovy
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF 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.
-*/
-
-
-package org.apache.ambari.view.hive20.internal.query.generators
-
-import spock.lang.Specification
-
-class AlterTableQueryGenerationSpecTest extends Specification {
-// def "alter simple table"() {
-// // blocks go here
-// setup:
-// def oldTableMeta = new TableMeta()
-// def newTableMeta = new TableMeta()
-// def oldCols = new ArrayList<>();
-// oldCols.add(new ColumnInfo())
-// oldTableMeta.setColumns()
-//
-// when:
-// stack.push(elem)
-//
-// then:
-// println "inside AlterTableQueryGenerationSpecTest"
-// !stack.empty
-// stack.size() == 1
-// stack.peek() == elem
-// }
-//
-// def "pushing again an element on the stack"() {
-// // blocks go here
-// setup:
-// def stack = new Stack()
-// def elem = "push me"
-//
-// when:
-// stack.push(elem)
-//
-// then:
-// println "inside AlterTableQueryGenerationSpecTest"
-// !stack.empty
-// stack.size() == 1
-// stack.peek() == elem
-// }
-}
http://git-wip-us.apache.org/repos/asf/ambari/blob/151d2f16/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java b/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java
index 45f29da..35ea416 100644
--- a/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java
+++ b/contrib/views/hive20/src/test/java/org/apache/ambari/view/hive20/internal/query/generators/AlterTableQueryGeneratorTest.java
@@ -19,24 +19,19 @@
package org.apache.ambari.view.hive20.internal.query.generators;
import com.google.common.base.Optional;
+import com.google.gson.Gson;
import org.apache.ambari.view.hive20.internal.dto.ColumnInfo;
import org.apache.ambari.view.hive20.internal.dto.TableMeta;
import org.junit.Assert;
import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.List;
public class AlterTableQueryGeneratorTest {
- @Test
- public void getQuery() throws Exception {
-
- }
-
- @Test
- public void generateColumnQuery() throws Exception {
-
- }
+ private static final Logger LOG = LoggerFactory.getLogger(AlterTableQueryGeneratorTest.class);
@Test
public void createColumnQueriesForSuccessfulChangeColumn() throws Exception {
@@ -86,9 +81,155 @@ public class AlterTableQueryGeneratorTest {
List<String> queries = query.get();
Assert.assertEquals("Expected number of column update queries were different.", 4, queries.size());
- System.out.println(queries);
String[] expectedQueries = new String[]{" CHANGE COLUMN `col1` `col4` VARCHAR(10) COMMENT \'COMMENT 4\'", " CHANGE COLUMN `col2` `col5` STRING COMMENT \'COMMENT 5\'", " CHANGE COLUMN `col3` `col6` INT"," ADD COLUMNS ( `col7` DATE, `col8` BOOLEAN COMMENT \'COMMENT 8\' )" };
Assert.assertArrayEquals("Column change queries were not equal ", expectedQueries, queries.toArray());
}
+
+ @Test
+ public void createColumnQueriesForSuccessfulChangeSomeColumns() throws Exception {
+
+ TableMeta oldMeta = new TableMeta();
+ TableMeta newMeta = new TableMeta();
+
+ ColumnInfo colInfo1 = new ColumnInfo("col1", "CHAR(1)", "COMMENT 1"); // with comment
+ ColumnInfo colInfo2 = new ColumnInfo("col2", "DECIMAL(10,5)"); // no comment
+ ColumnInfo colInfo3 = new ColumnInfo("col3", "STRING", "COMMENT-3");
+ ColumnInfo colInfo4 = new ColumnInfo("col4", "VARCHAR(10)", "COMMENT 4");
+ ColumnInfo colInfo5 = new ColumnInfo("col5", "STRING", "COMMENT 5");
+ ColumnInfo colInfo6 = new ColumnInfo("col6", "INT");
+ ColumnInfo colInfo7 = new ColumnInfo("col7", "DATE");
+ ColumnInfo colInfo8 = new ColumnInfo("col8", "BOOLEAN", "COMMENT 8");
+
+ List<ColumnInfo> oldColumns = Arrays.asList(colInfo1, colInfo2, colInfo3);
+ oldMeta.setColumns(oldColumns);
+
+ List<ColumnInfo> newColumns = Arrays.asList(colInfo1, colInfo5, colInfo6); // all changed
+ oldMeta.setColumns(newColumns);
+
+ Optional<List<String>> query = AlterTableQueryGenerator.createColumnQueries(oldColumns, newColumns, false);
+
+ Assert.assertTrue(query.isPresent());
+ List<String> queries = query.get();
+
+ Assert.assertEquals("Expected number of column update queries were different.", 2, queries.size());
+ String[] expectedQueries = new String[]{" CHANGE COLUMN `col2` `col5` STRING COMMENT 'COMMENT 5'", " CHANGE COLUMN `col3` `col6` INT"};
+
+ Assert.assertArrayEquals("Column change queries were not equal ", expectedQueries, queries.toArray());
+ }
+
+ @Test
+ public void createColumnQueriesForSuccessfulAddColumns() throws Exception {
+
+ TableMeta oldMeta = new TableMeta();
+ TableMeta newMeta = new TableMeta();
+
+ ColumnInfo colInfo1 = new ColumnInfo("col1", "CHAR(1)", "COMMENT 1"); // with comment
+ ColumnInfo colInfo2 = new ColumnInfo("col2", "DECIMAL(10,5)"); // no comment
+ ColumnInfo colInfo3 = new ColumnInfo("col3", "STRING", "COMMENT-3");
+ ColumnInfo colInfo4 = new ColumnInfo("col4", "VARCHAR(10)", "COMMENT 4");
+ ColumnInfo colInfo5 = new ColumnInfo("col5", "STRING", "COMMENT 5");
+ ColumnInfo colInfo6 = new ColumnInfo("col6", "INT");
+ ColumnInfo colInfo7 = new ColumnInfo("col7", "DATE");
+ ColumnInfo colInfo8 = new ColumnInfo("col8", "BOOLEAN", "COMMENT 8");
+
+ List<ColumnInfo> oldColumns = Arrays.asList(colInfo1, colInfo2, colInfo3);
+ oldMeta.setColumns(oldColumns);
+
+ List<ColumnInfo> newColumns = Arrays.asList(colInfo1, colInfo2, colInfo3, colInfo5, colInfo6); // all changed
+ oldMeta.setColumns(newColumns);
+
+ Optional<List<String>> query = AlterTableQueryGenerator.createColumnQueries(oldColumns, newColumns, false);
+
+ Assert.assertTrue(query.isPresent());
+ List<String> queries = query.get();
+
+ Assert.assertEquals("Expected number of column update queries were different.", 1, queries.size());
+ String[] expectedQueries = new String[]{" ADD COLUMNS ( `col5` STRING COMMENT 'COMMENT 5', `col6` INT )"};
+
+ Assert.assertArrayEquals("Column change queries were not equal ", expectedQueries, queries.toArray());
+ }
+
+ @Test
+ public void getQueryWithAlterColumn(){
+ String origMetaString = "{ " +
+ " \"database\": \"default\", " +
+ " \"table\": \"table2\", " +
+ " \"columns\": [{ " +
+ " \"name\": \"COL1\", " +
+ " \"type\": \"TINYINT\", " +
+ " \"comment\": \"\", " +
+ " \"precision\": null, " +
+ " \"scale\": null " +
+ " }, { " +
+ " \"name\": \"col2\", " +
+ " \"type\": \"VARCHAR\", " +
+ " \"comment\": \"\", " +
+ " \"precision\": \"333\", " +
+ " \"scale\": null " +
+ " }, { " +
+ " \"name\": \"col3\", " +
+ " \"type\": \"DECIMAL\", " +
+ " \"comment\": \"\", " +
+ " \"precision\": \"33\", " +
+ " \"scale\": \"3\" " +
+ " }], " +
+ " \"partitionInfo\": { " +
+ " \"columns\": [] " +
+ " }, " +
+ " \"detailedInfo\": { " +
+ " \"parameters\": {} " +
+ " }, " +
+ " \"storageInfo\": {} " +
+ " }";
+
+ String newMetaString = "{ " +
+ " \"database\": \"default\", " +
+ " \"table\": \"table2\", " +
+ " \"columns\": [{ " +
+ " \"name\": \"col1\", " +
+ " \"type\": \"TINYINT\", " +
+ " \"comment\": \"\", " +
+ " \"precision\": null, " +
+ " \"scale\": null " +
+ " }, { " +
+ " \"name\": \"col3\", " +
+ " \"type\": \"STRING\", " +
+ " \"comment\": \"\", " +
+ " \"precision\": \"333\", " +
+ " \"scale\": null " +
+ " }, { " +
+ " \"name\": \"col4\", " +
+ " \"type\": \"TINYINT\", " +
+ " \"comment\": \"\", " +
+ " \"precision\": null, " +
+ " \"scale\": null " +
+ " }], " +
+ " \"partitionInfo\": { " +
+ " \"columns\": [] " +
+ " }, " +
+ " \"detailedInfo\": { " +
+ " \"parameters\": {} " +
+ " }, " +
+ " \"storageInfo\": {} " +
+ " }";
+
+ Gson gson = new Gson();
+ TableMeta origTableMeta = gson.fromJson(origMetaString, TableMeta.class);
+ TableMeta updatedTableMeta = gson.fromJson(newMetaString, TableMeta.class);
+
+ LOG.info("origTableMeta : {},\n\nupdatedTableMeta : {}", origMetaString, updatedTableMeta);
+
+ AlterTableQueryGenerator generator = new AlterTableQueryGenerator(origTableMeta, updatedTableMeta);
+
+ Optional<String> query = generator.getQuery();
+ Assert.assertTrue(query.isPresent());
+ String hqlQuery = query.get();
+
+ LOG.info("hqlQuery : {}", hqlQuery);
+
+ String expectedQuery = " ALTER TABLE `default.table2` CHANGE COLUMN `col2` `col3` STRING(333);\n" +
+ " ALTER TABLE `default.table2` CHANGE COLUMN `col3` `col4` TINYINT";
+ Assert.assertEquals("Alter Edit table query did not match ", expectedQuery, hqlQuery);
+ }
}
\ No newline at end of file