SchemaUtil class to build create/alter cqls
This commit is contained in:
parent
c05d3e2737
commit
ead9866e5a
5 changed files with 176 additions and 53 deletions
121
src/main/java/casser/core/SchemaUtil.java
Normal file
121
src/main/java/casser/core/SchemaUtil.java
Normal file
|
@ -0,0 +1,121 @@
|
|||
package casser.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import casser.mapping.CasserMappingEntity;
|
||||
import casser.mapping.CasserMappingProperty;
|
||||
import casser.support.CasserMappingException;
|
||||
|
||||
import com.datastax.driver.core.ColumnMetadata;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.TableMetadata;
|
||||
import com.datastax.driver.core.schemabuilder.Alter;
|
||||
import com.datastax.driver.core.schemabuilder.Create;
|
||||
import com.datastax.driver.core.schemabuilder.SchemaBuilder;
|
||||
|
||||
public final class SchemaUtil {
|
||||
|
||||
private SchemaUtil() {
|
||||
}
|
||||
|
||||
public static String createTableCql(CasserMappingEntity<?> entity) {
|
||||
|
||||
Create create = SchemaBuilder.createTable(entity.getTableName());
|
||||
|
||||
List<CasserMappingProperty<?>> partitionKeys = new ArrayList<CasserMappingProperty<?>>();
|
||||
List<CasserMappingProperty<?>> clusteringColumns = new ArrayList<CasserMappingProperty<?>>();
|
||||
List<CasserMappingProperty<?>> columns = new ArrayList<CasserMappingProperty<?>>();
|
||||
|
||||
for (CasserMappingProperty<?> prop : entity.getMappingProperties()) {
|
||||
|
||||
if (prop.isPartitionKey()) {
|
||||
partitionKeys.add(prop);
|
||||
} else if (prop.isClusteringColumn()) {
|
||||
clusteringColumns.add(prop);
|
||||
} else {
|
||||
columns.add(prop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Collections
|
||||
.sort(partitionKeys, OrdinalBasedPropertyComparator.INSTANCE);
|
||||
Collections.sort(clusteringColumns,
|
||||
OrdinalBasedPropertyComparator.INSTANCE);
|
||||
|
||||
for (CasserMappingProperty<?> prop : partitionKeys) {
|
||||
create.addPartitionKey(prop.getColumnName(), prop.getDataType());
|
||||
}
|
||||
|
||||
for (CasserMappingProperty<?> prop : clusteringColumns) {
|
||||
create.addClusteringColumn(prop.getColumnName(), prop.getDataType());
|
||||
}
|
||||
|
||||
for (CasserMappingProperty<?> prop : columns) {
|
||||
create.addColumn(prop.getColumnName(), prop.getDataType());
|
||||
}
|
||||
|
||||
return create.buildInternal();
|
||||
|
||||
}
|
||||
|
||||
public static String alterTableCql(TableMetadata tmd,
|
||||
CasserMappingEntity<?> entity, boolean dropRemovedColumns) {
|
||||
|
||||
boolean altered = false;
|
||||
|
||||
Alter alter = SchemaBuilder.alterTable(entity.getTableName());
|
||||
|
||||
final Set<String> visitedColumns = dropRemovedColumns ? new HashSet<String>()
|
||||
: Collections.<String> emptySet();
|
||||
|
||||
for (CasserMappingProperty<?> prop : entity.getMappingProperties()) {
|
||||
|
||||
String columnName = prop.getColumnName();
|
||||
DataType columnDataType = prop.getDataType();
|
||||
|
||||
String loweredColumnName = columnName.toLowerCase();
|
||||
|
||||
if (dropRemovedColumns) {
|
||||
visitedColumns.add(loweredColumnName);
|
||||
}
|
||||
|
||||
ColumnMetadata columnMetadata = tmd.getColumn(loweredColumnName);
|
||||
|
||||
if (columnMetadata != null
|
||||
&& columnDataType.equals(columnMetadata.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prop.isPartitionKey() || prop.isClusteringColumn()) {
|
||||
throw new CasserMappingException(
|
||||
"unable to add or alter column in the primary index "
|
||||
+ columnName + " for entity "
|
||||
+ entity.getName());
|
||||
}
|
||||
|
||||
if (columnMetadata == null) {
|
||||
|
||||
alter.addColumn(columnName).type(columnDataType);
|
||||
altered = true;
|
||||
|
||||
} else {
|
||||
|
||||
alter.alterColumn(columnName).type(columnDataType);
|
||||
altered = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (altered) {
|
||||
return alter.buildInternal();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +1,13 @@
|
|||
package casser.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import casser.mapping.CasserMappingEntity;
|
||||
import casser.mapping.CasserMappingProperty;
|
||||
import casser.support.CasserException;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.TableMetadata;
|
||||
import com.datastax.driver.core.schemabuilder.Create;
|
||||
import com.datastax.driver.core.schemabuilder.SchemaBuilder;
|
||||
|
||||
|
||||
public class SessionInitializer extends AbstractSessionOperations {
|
||||
|
@ -22,6 +16,8 @@ public class SessionInitializer extends AbstractSessionOperations {
|
|||
private boolean showCql = false;
|
||||
private Set<CasserMappingEntity<?>> dropEntitiesOnClose = null;
|
||||
|
||||
private boolean dropRemovedColumns = false;
|
||||
|
||||
SessionInitializer(Session session) {
|
||||
|
||||
if (session == null) {
|
||||
|
@ -46,28 +42,33 @@ public class SessionInitializer extends AbstractSessionOperations {
|
|||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer dropRemovedColumns(boolean enabled) {
|
||||
this.dropRemovedColumns = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isShowCql() {
|
||||
return showCql;
|
||||
}
|
||||
|
||||
public SessionInitializer validate(Object... dsls) {
|
||||
process(AutoDslType.VALIDATE, dsls);
|
||||
process(AutoDdl.VALIDATE, dsls);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer update(Object... dsls) {
|
||||
process(AutoDslType.UPDATE, dsls);
|
||||
process(AutoDdl.UPDATE, dsls);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer create(Object... dsls) {
|
||||
process(AutoDslType.CREATE, dsls);
|
||||
process(AutoDdl.CREATE, dsls);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer createDrop(Object... dsls) {
|
||||
process(AutoDslType.CREATE_DROP, dsls);
|
||||
process(AutoDdl.CREATE_DROP, dsls);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -80,14 +81,14 @@ public class SessionInitializer extends AbstractSessionOperations {
|
|||
return new CasserSession(session, showCql, dropEntitiesOnClose);
|
||||
}
|
||||
|
||||
private enum AutoDslType {
|
||||
private enum AutoDdl {
|
||||
VALIDATE,
|
||||
UPDATE,
|
||||
CREATE,
|
||||
CREATE_DROP;
|
||||
}
|
||||
|
||||
private void process(AutoDslType type, Object[] dsls) {
|
||||
private void process(AutoDdl type, Object[] dsls) {
|
||||
|
||||
for (Object dsl : dsls) {
|
||||
processSingle(type, dsl);
|
||||
|
@ -95,7 +96,7 @@ public class SessionInitializer extends AbstractSessionOperations {
|
|||
|
||||
}
|
||||
|
||||
private void processSingle(AutoDslType type, Object dsl) {
|
||||
private void processSingle(AutoDdl type, Object dsl) {
|
||||
|
||||
Class<?> iface = null;
|
||||
|
||||
|
@ -120,13 +121,13 @@ public class SessionInitializer extends AbstractSessionOperations {
|
|||
|
||||
CasserMappingEntity<?> entity = new CasserMappingEntity(iface);
|
||||
|
||||
if (type == AutoDslType.CREATE || type == AutoDslType.CREATE_DROP) {
|
||||
if (type == AutoDdl.CREATE || type == AutoDdl.CREATE_DROP) {
|
||||
createNewTable(entity);
|
||||
}
|
||||
else {
|
||||
TableMetadata tmd = getTableMetadata(entity);
|
||||
|
||||
if (type == AutoDslType.VALIDATE) {
|
||||
if (type == AutoDdl.VALIDATE) {
|
||||
|
||||
if (tmd == null) {
|
||||
throw new CasserException("table not exists " + entity.getTableName() + "for entity " + entity.getEntityInterface());
|
||||
|
@ -134,7 +135,7 @@ public class SessionInitializer extends AbstractSessionOperations {
|
|||
|
||||
validateTable(tmd, entity);
|
||||
}
|
||||
else if (type == AutoDslType.UPDATE) {
|
||||
else if (type == AutoDdl.UPDATE) {
|
||||
|
||||
if (tmd == null) {
|
||||
createNewTable(entity);
|
||||
|
@ -146,7 +147,7 @@ public class SessionInitializer extends AbstractSessionOperations {
|
|||
}
|
||||
}
|
||||
|
||||
if (type == AutoDslType.CREATE_DROP) {
|
||||
if (type == AutoDdl.CREATE_DROP) {
|
||||
getOrCreateDropEntitiesSet().add(entity);
|
||||
}
|
||||
|
||||
|
@ -169,42 +170,7 @@ public class SessionInitializer extends AbstractSessionOperations {
|
|||
|
||||
private void createNewTable(CasserMappingEntity<?> entity) {
|
||||
|
||||
Create create = SchemaBuilder.createTable(entity.getTableName());
|
||||
|
||||
List<CasserMappingProperty<?>> partitionKeys = new ArrayList<CasserMappingProperty<?>>();
|
||||
List<CasserMappingProperty<?>> clusteringColumns = new ArrayList<CasserMappingProperty<?>>();
|
||||
List<CasserMappingProperty<?>> columns = new ArrayList<CasserMappingProperty<?>>();
|
||||
|
||||
for (CasserMappingProperty<?> prop : entity.getMappingProperties()) {
|
||||
|
||||
if (prop.isPartitionKey()) {
|
||||
partitionKeys.add(prop);
|
||||
}
|
||||
else if (prop.isClusteringColumn()) {
|
||||
clusteringColumns.add(prop);
|
||||
}
|
||||
else {
|
||||
columns.add(prop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Collections.sort(partitionKeys, OrdinalBasedPropertyComparator.INSTANCE);
|
||||
Collections.sort(clusteringColumns, OrdinalBasedPropertyComparator.INSTANCE);
|
||||
|
||||
for (CasserMappingProperty<?> prop : partitionKeys) {
|
||||
create.addPartitionKey(prop.getColumnName(), prop.getDataType());
|
||||
}
|
||||
|
||||
for (CasserMappingProperty<?> prop : clusteringColumns) {
|
||||
create.addClusteringColumn(prop.getColumnName(), prop.getDataType());
|
||||
}
|
||||
|
||||
for (CasserMappingProperty<?> prop : columns) {
|
||||
create.addColumn(prop.getColumnName(), prop.getDataType());
|
||||
}
|
||||
|
||||
String cql = create.getQueryString();
|
||||
String cql = SchemaUtil.createTableCql(entity);
|
||||
|
||||
doExecute(cql);
|
||||
|
||||
|
@ -212,9 +178,19 @@ public class SessionInitializer extends AbstractSessionOperations {
|
|||
|
||||
private void validateTable(TableMetadata tmd, CasserMappingEntity<?> entity) {
|
||||
|
||||
String cql = SchemaUtil.alterTableCql(tmd, entity, dropRemovedColumns);
|
||||
|
||||
if (cql != null) {
|
||||
throw new CasserException("schema changed for entity " + entity.getEntityInterface() + ", apply this command: " + cql);
|
||||
}
|
||||
}
|
||||
|
||||
private void alterTable(TableMetadata tmd, CasserMappingEntity<?> entity) {
|
||||
|
||||
String cql = SchemaUtil.alterTableCql(tmd, entity, dropRemovedColumns);
|
||||
|
||||
if (cql != null) {
|
||||
doExecute(cql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import java.util.Collection;
|
|||
|
||||
public interface CasserEntity<E> {
|
||||
|
||||
String getName();
|
||||
|
||||
String getTableName();
|
||||
|
||||
Collection<CasserProperty<E>> getProperties();
|
||||
|
|
|
@ -61,6 +61,11 @@ public class CasserMappingEntity<E> implements CasserEntity<E> {
|
|||
return iface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return iface.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CasserProperty<E>> getProperties() {
|
||||
return Collections.unmodifiableCollection(props.values());
|
||||
|
|
19
src/main/java/casser/support/CasserMappingException.java
Normal file
19
src/main/java/casser/support/CasserMappingException.java
Normal file
|
@ -0,0 +1,19 @@
|
|||
package casser.support;
|
||||
|
||||
public class CasserMappingException extends CasserException {
|
||||
|
||||
private static final long serialVersionUID = -4730562130753392363L;
|
||||
|
||||
public CasserMappingException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public CasserMappingException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
public CasserMappingException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue