check columns for UDT types as well as Tables

This commit is contained in:
Albert Shift 2015-06-07 00:24:31 -07:00
parent a46421fcce
commit fe3782bf10
13 changed files with 394 additions and 44 deletions

View file

@ -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<SchemaStatement> alterUserType(UserType userType,
CasserEntity entity, boolean dropUnusedColumns) {
if (entity.getType() != CasserEntityType.UDT) {
throw new CasserMappingException("expected UDT entity " + entity);
}
List<SchemaStatement> result = new ArrayList<SchemaStatement>();
/**
* TODO: In future replace SchemaBuilder.alterTable by SchemaBuilder.alterType when it will exist
*/
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
final Set<String> visitedColumns = dropUnusedColumns ? new HashSet<String>()
: Collections.<String> 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;
}
}

View file

@ -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<? super CasserEntity> action) {
Set<CasserEntity> createdSet = new HashSet<CasserEntity>();
Set<CasserEntity> processedSet = new HashSet<CasserEntity>();
Set<CasserEntity> stack = new HashSet<CasserEntity>();
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<CasserEntity> createdSet, Set<CasserEntity> stack, UserTypeOperations userTypeOps) {
private void eachUserTypeInRecursion(CasserEntity e, Set<CasserEntity> processedSet, Set<CasserEntity> stack, UserTypeOperations userTypeOps, Consumer<? super CasserEntity> action) {
stack.add(e);
Collection<CasserEntity> 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);
}
}

View file

@ -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;

View file

@ -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<SchemaStatement> 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<SchemaStatement> list) {
list.forEach(s -> {
sessionOps.execute(s, true);
});
}
}

View file

@ -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();

View file

@ -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) {

View file

@ -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();
}

View file

@ -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);

View file

@ -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<DataType> 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

View file

@ -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<DataType> 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

View file

@ -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<DataType> 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

View file

@ -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<DataType> 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

View file

@ -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<DataType> 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