diff --git a/src/main/java/com/noorq/casser/core/SchemaUtil.java b/src/main/java/com/noorq/casser/core/SchemaUtil.java index 0889117..367a0ad 100644 --- a/src/main/java/com/noorq/casser/core/SchemaUtil.java +++ b/src/main/java/com/noorq/casser/core/SchemaUtil.java @@ -24,9 +24,11 @@ import java.util.stream.Collectors; import com.datastax.driver.core.ColumnMetadata; import com.datastax.driver.core.ColumnMetadata.IndexMetadata; +import com.datastax.driver.core.DataType; import com.datastax.driver.core.RegularStatement; import com.datastax.driver.core.SimpleStatement; import com.datastax.driver.core.TableMetadata; +import com.datastax.driver.core.UserType; import com.datastax.driver.core.schemabuilder.Alter; import com.datastax.driver.core.schemabuilder.Create; import com.datastax.driver.core.schemabuilder.Create.Options; @@ -38,6 +40,7 @@ import com.noorq.casser.mapping.CasserEntityType; import com.noorq.casser.mapping.CasserProperty; import com.noorq.casser.mapping.ColumnType; import com.noorq.casser.mapping.OrderingDirection; +import com.noorq.casser.mapping.type.OptionalColumnMetadata; import com.noorq.casser.support.CasserMappingException; import com.noorq.casser.support.CqlUtil; @@ -58,7 +61,7 @@ public final class SchemaUtil { public static SchemaStatement createUserType(CasserEntity entity) { if (entity.getType() != CasserEntityType.UDT) { - throw new CasserMappingException("expected user defined type entity " + entity); + throw new CasserMappingException("expected UDT entity " + entity); } CreateType create = SchemaBuilder.createType(entity.getName().toCql()); @@ -71,13 +74,79 @@ public final class SchemaUtil { throw new CasserMappingException("primary key columns are not supported in UserDefinedType for " + prop.getPropertyName() + " in entity " + entity); } - prop.getDataType().addColumn(create, prop.getColumnName()); + try { + prop.getDataType().addColumn(create, prop.getColumnName()); + } + catch(IllegalArgumentException e) { + throw new CasserMappingException("invalid column name '" + prop.getColumnName() + "' in entity '" + entity.getName().getName() + "'", e); + } } return create; } + public static List alterUserType(UserType userType, + CasserEntity entity, boolean dropUnusedColumns) { + + if (entity.getType() != CasserEntityType.UDT) { + throw new CasserMappingException("expected UDT entity " + entity); + } + + List result = new ArrayList(); + + /** + * TODO: In future replace SchemaBuilder.alterTable by SchemaBuilder.alterType when it will exist + */ + + Alter alter = SchemaBuilder.alterTable(entity.getName().toCql()); + + final Set visitedColumns = dropUnusedColumns ? new HashSet() + : Collections. emptySet(); + + for (CasserProperty prop : entity.getOrderedProperties()) { + + String columnName = prop.getColumnName().getName(); + + if (dropUnusedColumns) { + visitedColumns.add(columnName); + } + + ColumnType columnType = prop.getColumnType(); + + if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) { + continue; + } + + DataType dataType = userType.getFieldType(columnName); + SchemaStatement stmt = prop.getDataType().alterColumn(alter, prop.getColumnName(), optional(columnName, dataType)); + + if (stmt != null) { + result.add(stmt); + } + + } + + if (dropUnusedColumns) { + for (String field : userType.getFieldNames()) { + if (!visitedColumns.contains(field)) { + + result.add(alter.dropColumn(field)); + + } + } + } + + return result; + + } + + public static SchemaStatement dropUserType(CasserEntity entity) { + + if (entity.getType() != CasserEntityType.UDT) { + throw new CasserMappingException("expected UDT entity " + entity); + } + return SchemaBuilder.dropType(entity.getName().toCql()); } @@ -143,7 +212,7 @@ public final class SchemaUtil { } ColumnMetadata columnMetadata = tmd.getColumn(columnName); - SchemaStatement stmt = prop.getDataType().alterColumn(alter, prop.getColumnName(), columnMetadata); + SchemaStatement stmt = prop.getDataType().alterColumn(alter, prop.getColumnName(), optional(columnMetadata)); if (stmt != null) { result.add(stmt); @@ -267,4 +336,43 @@ public final class SchemaUtil { + "' type is '" + prop.getJavaType() + "' in the entity " + prop.getEntity()); } + + private static OptionalColumnMetadata optional(final ColumnMetadata columnMetadata) { + if (columnMetadata != null) { + return new OptionalColumnMetadata() { + + @Override + public String getName() { + return columnMetadata.getName(); + } + + @Override + public DataType getType() { + return columnMetadata.getType(); + } + + }; + } + return null; + } + + private static OptionalColumnMetadata optional(final String name, final DataType dataType) { + if (dataType != null) { + return new OptionalColumnMetadata() { + + @Override + public String getName() { + return name; + } + + @Override + public DataType getType() { + return dataType; + } + + }; + } + return null; + } + } diff --git a/src/main/java/com/noorq/casser/core/SessionInitializer.java b/src/main/java/com/noorq/casser/core/SessionInitializer.java index d41b70a..1fe4120 100644 --- a/src/main/java/com/noorq/casser/core/SessionInitializer.java +++ b/src/main/java/com/noorq/casser/core/SessionInitializer.java @@ -24,6 +24,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import java.util.function.Consumer; import com.datastax.driver.core.KeyspaceMetadata; import com.datastax.driver.core.Session; @@ -218,31 +219,32 @@ public final class SessionInitializer extends AbstractSessionOperations { initList.forEach(dsl -> sessionRepository.add(dsl)); TableOperations tableOps = new TableOperations(this, dropUnusedColumns, dropUnusedIndexes); - UserTypeOperations userTypeOps = new UserTypeOperations(this); + UserTypeOperations userTypeOps = new UserTypeOperations(this, dropUnusedColumns); + switch(autoDdl) { case CREATE: case CREATE_DROP: - - createUserTypesInOrder(userTypeOps); + eachUserTypeInOrder(userTypeOps, e -> userTypeOps.createUserType(e)); + sessionRepository.entities().stream().filter(e -> e.getType() == CasserEntityType.TABLE) .forEach(e -> tableOps.createTable(e)); break; case VALIDATE: - sessionRepository.entities().stream().filter(e -> e.getType() == CasserEntityType.UDT) - .forEach(e -> userTypeOps.validateUserType(getUserType(e), e)); + + eachUserTypeInOrder(userTypeOps, e -> userTypeOps.validateUserType(getUserType(e), e)); sessionRepository.entities().stream().filter(e -> e.getType() == CasserEntityType.TABLE) .forEach(e -> tableOps.validateTable(getTableMetadata(e), e)); break; case UPDATE: - sessionRepository.entities().stream().filter(e -> e.getType() == CasserEntityType.UDT) - .forEach(e -> userTypeOps.updateUserType(getUserType(e), e)); + + eachUserTypeInOrder(userTypeOps, e -> userTypeOps.updateUserType(getUserType(e), e)); sessionRepository.entities().stream().filter(e -> e.getType() == CasserEntityType.TABLE) .forEach(e -> tableOps.updateTable(getTableMetadata(e), e)); @@ -258,9 +260,9 @@ public final class SessionInitializer extends AbstractSessionOperations { } - private void createUserTypesInOrder(UserTypeOperations userTypeOps) { + private void eachUserTypeInOrder(UserTypeOperations userTypeOps, Consumer action) { - Set createdSet = new HashSet(); + Set processedSet = new HashSet(); Set stack = new HashSet(); sessionRepository.entities().stream() @@ -268,29 +270,29 @@ public final class SessionInitializer extends AbstractSessionOperations { .forEach(e -> { stack.clear(); - createUserTypeInRecursion(e, createdSet, stack, userTypeOps); + eachUserTypeInRecursion(e, processedSet, stack, userTypeOps, action); }); } - private void createUserTypeInRecursion(CasserEntity e, Set createdSet, Set stack, UserTypeOperations userTypeOps) { + private void eachUserTypeInRecursion(CasserEntity e, Set processedSet, Set stack, UserTypeOperations userTypeOps, Consumer action) { stack.add(e); Collection createBefore = sessionRepository.getUserTypeUses(e); for (CasserEntity be : createBefore) { - if (!createdSet.contains(be) && !stack.contains(be)) { - createUserTypeInRecursion(be, createdSet, stack, userTypeOps); - createdSet.add(be); + if (!processedSet.contains(be) && !stack.contains(be)) { + eachUserTypeInRecursion(be, processedSet, stack, userTypeOps, action); + processedSet.add(be); } } - if (!createdSet.contains(e)) { - userTypeOps.createUserType(e); - createdSet.add(e); + if (!processedSet.contains(e)) { + action.accept(e); + processedSet.add(e); } } diff --git a/src/main/java/com/noorq/casser/core/TableOperations.java b/src/main/java/com/noorq/casser/core/TableOperations.java index 388d8cd..fe4d9b9 100644 --- a/src/main/java/com/noorq/casser/core/TableOperations.java +++ b/src/main/java/com/noorq/casser/core/TableOperations.java @@ -17,10 +17,7 @@ package com.noorq.casser.core; import java.util.List; -import com.datastax.driver.core.RegularStatement; import com.datastax.driver.core.TableMetadata; -import com.datastax.driver.core.querybuilder.Batch; -import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.schemabuilder.SchemaStatement; import com.noorq.casser.mapping.CasserEntity; import com.noorq.casser.support.CasserException; diff --git a/src/main/java/com/noorq/casser/core/UserTypeOperations.java b/src/main/java/com/noorq/casser/core/UserTypeOperations.java index 8d51864..887c7e9 100644 --- a/src/main/java/com/noorq/casser/core/UserTypeOperations.java +++ b/src/main/java/com/noorq/casser/core/UserTypeOperations.java @@ -15,29 +15,61 @@ */ package com.noorq.casser.core; +import java.util.List; + import com.datastax.driver.core.UserType; +import com.datastax.driver.core.schemabuilder.SchemaStatement; import com.noorq.casser.mapping.CasserEntity; +import com.noorq.casser.support.CasserException; public final class UserTypeOperations { private final AbstractSessionOperations sessionOps; + private final boolean dropUnusedColumns; - public UserTypeOperations(AbstractSessionOperations sessionOps) { + public UserTypeOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns) { this.sessionOps = sessionOps; + this.dropUnusedColumns = dropUnusedColumns; } public void createUserType(CasserEntity entity) { + sessionOps.execute(SchemaUtil.createUserType(entity), true); + } public void validateUserType(UserType userType, CasserEntity entity) { + if (userType == null) { + throw new CasserException("userType not exists " + entity.getName() + "for entity " + entity.getMappingInterface()); + } + + List list = SchemaUtil.alterUserType(userType, entity, dropUnusedColumns); + + if (!list.isEmpty()) { + throw new CasserException("schema changed for entity " + entity.getMappingInterface() + ", apply this command: " + list); + } + } public void updateUserType(UserType userType, CasserEntity entity) { + if (userType == null) { + createUserType(entity); + return; + } + + executeBatch(SchemaUtil.alterUserType(userType, entity, dropUnusedColumns)); + } + private void executeBatch(List list) { + + list.forEach(s -> { + sessionOps.execute(s, true); + }); + + } } diff --git a/src/main/java/com/noorq/casser/mapping/type/AbstractDataType.java b/src/main/java/com/noorq/casser/mapping/type/AbstractDataType.java index 097073c..a424315 100644 --- a/src/main/java/com/noorq/casser/mapping/type/AbstractDataType.java +++ b/src/main/java/com/noorq/casser/mapping/type/AbstractDataType.java @@ -15,7 +15,6 @@ */ package com.noorq.casser.mapping.type; -import com.datastax.driver.core.ColumnMetadata; import com.datastax.driver.core.schemabuilder.Alter; import com.datastax.driver.core.schemabuilder.Create; import com.datastax.driver.core.schemabuilder.CreateType; @@ -30,7 +29,7 @@ public abstract class AbstractDataType { public abstract void addColumn(CreateType create, IdentityName columnName); - public abstract SchemaStatement alterColumn(Alter alter, IdentityName columnName, ColumnMetadata columnMetadata); + public abstract SchemaStatement alterColumn(Alter alter, IdentityName columnName, OptionalColumnMetadata columnInformation); public abstract Class[] getTypeArguments(); diff --git a/src/main/java/com/noorq/casser/mapping/type/DTDataType.java b/src/main/java/com/noorq/casser/mapping/type/DTDataType.java index f506a6b..e3746ec 100644 --- a/src/main/java/com/noorq/casser/mapping/type/DTDataType.java +++ b/src/main/java/com/noorq/casser/mapping/type/DTDataType.java @@ -153,7 +153,7 @@ public final class DTDataType extends AbstractDataType { } @Override - public SchemaStatement alterColumn(Alter alter, IdentityName columnName, ColumnMetadata columnMetadata) { + public SchemaStatement alterColumn(Alter alter, IdentityName columnName, OptionalColumnMetadata columnMetadata) { if (columnMetadata != null) { diff --git a/src/main/java/com/noorq/casser/mapping/type/OptionalColumnMetadata.java b/src/main/java/com/noorq/casser/mapping/type/OptionalColumnMetadata.java new file mode 100644 index 0000000..cb2eedd --- /dev/null +++ b/src/main/java/com/noorq/casser/mapping/type/OptionalColumnMetadata.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 Noorq, Inc. + * + * Licensed 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 com.noorq.casser.mapping.type; + +import com.datastax.driver.core.DataType; + +public interface OptionalColumnMetadata { + + String getName(); + + DataType getType(); + +} diff --git a/src/main/java/com/noorq/casser/mapping/type/UDTDataType.java b/src/main/java/com/noorq/casser/mapping/type/UDTDataType.java index 4a414db..11e4ef2 100644 --- a/src/main/java/com/noorq/casser/mapping/type/UDTDataType.java +++ b/src/main/java/com/noorq/casser/mapping/type/UDTDataType.java @@ -15,7 +15,6 @@ */ package com.noorq.casser.mapping.type; -import com.datastax.driver.core.ColumnMetadata; import com.datastax.driver.core.DataType; import com.datastax.driver.core.UserType; import com.datastax.driver.core.schemabuilder.Alter; @@ -88,7 +87,7 @@ public final class UDTDataType extends AbstractDataType { @Override public SchemaStatement alterColumn(Alter alter, IdentityName columnName, - ColumnMetadata columnMetadata) { + OptionalColumnMetadata columnMetadata) { ensureSimpleColumn(columnName); diff --git a/src/main/java/com/noorq/casser/mapping/type/UDTKeyMapDataType.java b/src/main/java/com/noorq/casser/mapping/type/UDTKeyMapDataType.java index 621d263..d071b26 100644 --- a/src/main/java/com/noorq/casser/mapping/type/UDTKeyMapDataType.java +++ b/src/main/java/com/noorq/casser/mapping/type/UDTKeyMapDataType.java @@ -15,8 +15,10 @@ */ package com.noorq.casser.mapping.type; -import com.datastax.driver.core.ColumnMetadata; +import java.util.List; + import com.datastax.driver.core.DataType; +import com.datastax.driver.core.UserType; import com.datastax.driver.core.schemabuilder.Alter; import com.datastax.driver.core.schemabuilder.Create; import com.datastax.driver.core.schemabuilder.CreateType; @@ -71,8 +73,40 @@ public final class UDTKeyMapDataType extends AbstractDataType { @Override public SchemaStatement alterColumn(Alter alter, IdentityName columnName, - ColumnMetadata columnMetadata) { - throw new CasserMappingException("alter of UDTMap column is not possible now for " + columnName); + OptionalColumnMetadata columnMetadata) { + + if (columnMetadata == null) { + return notSupportedOperation("add", columnName); + } + + DataType schemaDataType = columnMetadata.getType(); + if (schemaDataType.getName() != DataType.Name.MAP) { + return notSupportedOperation("alter", columnName); + } + + List args = columnMetadata.getType().getTypeArguments(); + if (args.size() != 2 || !args.get(1).equals(valueType)) { + return notSupportedOperation("alter", columnName); + } + + DataType keyDataType = args.get(0); + if (keyDataType.getName() != DataType.Name.UDT || + !(keyDataType instanceof UserType)) { + return notSupportedOperation("alter", columnName); + } + + UserType udtKeyType = (UserType) keyDataType; + + if (!keyType.getName().equals(udtKeyType.getTypeName())) { + return notSupportedOperation("alter", columnName); + } + + // equals + return null; + } + + private SchemaStatement notSupportedOperation(String op, IdentityName columnName) { + throw new CasserMappingException(op + " UDTMap column is not supported by Cassandra Driver for column '" + columnName + "'"); } @Override diff --git a/src/main/java/com/noorq/casser/mapping/type/UDTListDataType.java b/src/main/java/com/noorq/casser/mapping/type/UDTListDataType.java index 6cbacd6..cccb36c 100644 --- a/src/main/java/com/noorq/casser/mapping/type/UDTListDataType.java +++ b/src/main/java/com/noorq/casser/mapping/type/UDTListDataType.java @@ -15,7 +15,10 @@ */ package com.noorq.casser.mapping.type; -import com.datastax.driver.core.ColumnMetadata; +import java.util.List; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.UserType; import com.datastax.driver.core.schemabuilder.Alter; import com.datastax.driver.core.schemabuilder.Create; import com.datastax.driver.core.schemabuilder.CreateType; @@ -64,8 +67,41 @@ public final class UDTListDataType extends AbstractDataType { @Override public SchemaStatement alterColumn(Alter alter, IdentityName columnName, - ColumnMetadata columnMetadata) { - throw new CasserMappingException("alter of UDTList column is not possible now for " + columnName); + OptionalColumnMetadata columnMetadata) { + + if (columnMetadata == null) { + return notSupportedOperation("add", columnName); + } + + DataType schemaDataType = columnMetadata.getType(); + if (schemaDataType.getName() != DataType.Name.LIST) { + return notSupportedOperation("alter", columnName); + } + + List args = columnMetadata.getType().getTypeArguments(); + if (args.size() != 1) { + return notSupportedOperation("alter", columnName); + } + + DataType valueDataType = args.get(0); + if (valueDataType.getName() != DataType.Name.UDT || + !(valueDataType instanceof UserType)) { + return notSupportedOperation("alter", columnName); + } + + UserType udtValueType = (UserType) valueDataType; + + if (!udtName.getName().equals(udtValueType.getTypeName())) { + return notSupportedOperation("alter", columnName); + } + + // equals + return null; + + } + + private SchemaStatement notSupportedOperation(String op, IdentityName columnName) { + throw new CasserMappingException(op + " UDTList column is not supported by Cassandra Driver for column '" + columnName + "'"); } @Override diff --git a/src/main/java/com/noorq/casser/mapping/type/UDTMapDataType.java b/src/main/java/com/noorq/casser/mapping/type/UDTMapDataType.java index 1c15860..c62417e 100644 --- a/src/main/java/com/noorq/casser/mapping/type/UDTMapDataType.java +++ b/src/main/java/com/noorq/casser/mapping/type/UDTMapDataType.java @@ -15,7 +15,10 @@ */ package com.noorq.casser.mapping.type; -import com.datastax.driver.core.ColumnMetadata; +import java.util.List; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.UserType; import com.datastax.driver.core.schemabuilder.Alter; import com.datastax.driver.core.schemabuilder.Create; import com.datastax.driver.core.schemabuilder.CreateType; @@ -82,8 +85,52 @@ public final class UDTMapDataType extends AbstractDataType { @Override public SchemaStatement alterColumn(Alter alter, IdentityName columnName, - ColumnMetadata columnMetadata) { - throw new CasserMappingException("alter of UDTMap column is not possible now for " + columnName); + OptionalColumnMetadata columnMetadata) { + + if (columnMetadata == null) { + return notSupportedOperation("add", columnName); + } + + DataType schemaDataType = columnMetadata.getType(); + if (schemaDataType.getName() != DataType.Name.MAP) { + return notSupportedOperation("alter", columnName); + } + + List args = columnMetadata.getType().getTypeArguments(); + if (args.size() != 2) { + return notSupportedOperation("alter", columnName); + } + + DataType keyDataType = args.get(0); + if (keyDataType.getName() != DataType.Name.UDT || + !(keyDataType instanceof UserType)) { + return notSupportedOperation("alter", columnName); + } + + UserType udtKeyType = (UserType) keyDataType; + + if (!keyType.getName().equals(udtKeyType.getTypeName())) { + return notSupportedOperation("alter", columnName); + } + + DataType valueDataType = args.get(1); + if (valueDataType.getName() != DataType.Name.UDT || + !(valueDataType instanceof UserType)) { + return notSupportedOperation("alter", columnName); + } + + UserType udtValueType = (UserType) valueDataType; + + if (!valueType.getName().equals(udtValueType.getTypeName())) { + return notSupportedOperation("alter", columnName); + } + + // equals + return null; + } + + private SchemaStatement notSupportedOperation(String op, IdentityName columnName) { + throw new CasserMappingException(op + " UDTMap column is not supported by Cassandra Driver for column '" + columnName + "'"); } @Override diff --git a/src/main/java/com/noorq/casser/mapping/type/UDTSetDataType.java b/src/main/java/com/noorq/casser/mapping/type/UDTSetDataType.java index 16ca4a3..56ea7a3 100644 --- a/src/main/java/com/noorq/casser/mapping/type/UDTSetDataType.java +++ b/src/main/java/com/noorq/casser/mapping/type/UDTSetDataType.java @@ -15,7 +15,10 @@ */ package com.noorq.casser.mapping.type; -import com.datastax.driver.core.ColumnMetadata; +import java.util.List; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.UserType; import com.datastax.driver.core.schemabuilder.Alter; import com.datastax.driver.core.schemabuilder.Create; import com.datastax.driver.core.schemabuilder.CreateType; @@ -64,8 +67,41 @@ public final class UDTSetDataType extends AbstractDataType { @Override public SchemaStatement alterColumn(Alter alter, IdentityName columnName, - ColumnMetadata columnMetadata) { - throw new CasserMappingException("alter of UDTSet column is not possible now for " + columnName); + OptionalColumnMetadata columnMetadata) { + + if (columnMetadata == null) { + return notSupportedOperation("add", columnName); + } + + DataType schemaDataType = columnMetadata.getType(); + if (schemaDataType.getName() != DataType.Name.SET) { + return notSupportedOperation("alter", columnName); + } + + List args = columnMetadata.getType().getTypeArguments(); + if (args.size() != 1) { + return notSupportedOperation("alter", columnName); + } + + DataType valueDataType = args.get(0); + if (valueDataType.getName() != DataType.Name.UDT || + !(valueDataType instanceof UserType)) { + return notSupportedOperation("alter", columnName); + } + + UserType udtValueType = (UserType) valueDataType; + + if (!udtName.getName().equals(udtValueType.getTypeName())) { + return notSupportedOperation("alter", columnName); + } + + // equals + return null; + + } + + private SchemaStatement notSupportedOperation(String op, IdentityName columnName) { + throw new CasserMappingException(op + " UDTSet column is not supported by Cassandra Driver for column '" + columnName + "'"); } @Override diff --git a/src/main/java/com/noorq/casser/mapping/type/UDTValueMapDataType.java b/src/main/java/com/noorq/casser/mapping/type/UDTValueMapDataType.java index 96af66c..8499cd0 100644 --- a/src/main/java/com/noorq/casser/mapping/type/UDTValueMapDataType.java +++ b/src/main/java/com/noorq/casser/mapping/type/UDTValueMapDataType.java @@ -15,8 +15,10 @@ */ package com.noorq.casser.mapping.type; -import com.datastax.driver.core.ColumnMetadata; +import java.util.List; + import com.datastax.driver.core.DataType; +import com.datastax.driver.core.UserType; import com.datastax.driver.core.schemabuilder.Alter; import com.datastax.driver.core.schemabuilder.Create; import com.datastax.driver.core.schemabuilder.CreateType; @@ -71,8 +73,40 @@ public final class UDTValueMapDataType extends AbstractDataType { @Override public SchemaStatement alterColumn(Alter alter, IdentityName columnName, - ColumnMetadata columnMetadata) { - throw new CasserMappingException("alter of UDTMap column is not possible now for " + columnName); + OptionalColumnMetadata columnMetadata) { + + if (columnMetadata == null) { + return notSupportedOperation("add", columnName); + } + + DataType schemaDataType = columnMetadata.getType(); + if (schemaDataType.getName() != DataType.Name.MAP) { + return notSupportedOperation("alter", columnName); + } + + List args = columnMetadata.getType().getTypeArguments(); + if (args.size() != 2 || !args.get(0).equals(keyType)) { + return notSupportedOperation("alter", columnName); + } + + DataType valueDataType = args.get(1); + if (valueDataType.getName() != DataType.Name.UDT || + !(valueDataType instanceof UserType)) { + return notSupportedOperation("alter", columnName); + } + + UserType udtValueType = (UserType) valueDataType; + + if (!valueType.getName().equals(udtValueType.getTypeName())) { + return notSupportedOperation("alter", columnName); + } + + // equals + return null; + } + + private SchemaStatement notSupportedOperation(String op, IdentityName columnName) { + throw new CasserMappingException(op + " UDTMap column is not supported by Cassandra Driver for column '" + columnName + "'"); } @Override