diff --git a/build.gradle b/build.gradle index c9dae6657..f47f1d4fe 100644 --- a/build.gradle +++ b/build.gradle @@ -60,6 +60,7 @@ dependencies { testCompile("javax.annotation:jsr250-api:1.0", optional) testCompile("com.thoughtworks.xstream:xstream:1.3", optional) testCompile "org.cassandraunit:cassandra-unit:$cassandraUnitVersion" + testCompile "org.cassandraunit:cassandra-unit-spring:$cassandraUnitVersion" testCompile "cglib:cglib-nodep:$cglibVersion" } diff --git a/src/main/java/org/springframework/cassandra/core/cql/generator/AlterTableCqlGenerator.java b/src/main/java/org/springframework/cassandra/core/cql/generator/AlterTableCqlGenerator.java index cbb920656..64ed9e5b7 100644 --- a/src/main/java/org/springframework/cassandra/core/cql/generator/AlterTableCqlGenerator.java +++ b/src/main/java/org/springframework/cassandra/core/cql/generator/AlterTableCqlGenerator.java @@ -16,7 +16,7 @@ import org.springframework.cassandra.core.keyspace.Option; * * @author Matthew T. Adams */ -public class AlterTableCqlGenerator extends AbstractTableOperationCqlGenerator { +public class AlterTableCqlGenerator extends TableOptionsCqlGenerator { public AlterTableCqlGenerator(AlterTableSpecification specification) { super(specification); diff --git a/src/main/java/org/springframework/cassandra/core/cql/generator/CreateTableCqlGenerator.java b/src/main/java/org/springframework/cassandra/core/cql/generator/CreateTableCqlGenerator.java index 38f21b6fc..df0369e62 100644 --- a/src/main/java/org/springframework/cassandra/core/cql/generator/CreateTableCqlGenerator.java +++ b/src/main/java/org/springframework/cassandra/core/cql/generator/CreateTableCqlGenerator.java @@ -17,7 +17,7 @@ import org.springframework.cassandra.core.keyspace.Option; * * @author Matthew T. Adams */ -public class CreateTableCqlGenerator extends AbstractTableOperationCqlGenerator { +public class CreateTableCqlGenerator extends TableCqlGenerator { public CreateTableCqlGenerator(CreateTableSpecification specification) { super(specification); @@ -110,7 +110,7 @@ public class CreateTableCqlGenerator extends AbstractTableOperationCqlGenerator< clustering.append(")"); } - boolean parenthesize = partitionKeys.size() + primaryKeys.size() > 1; + boolean parenthesize = true;// partitionKeys.size() + primaryKeys.size() > 1; cql.append(parenthesize ? "(" : ""); cql.append(partitions); @@ -118,6 +118,8 @@ public class CreateTableCqlGenerator extends AbstractTableOperationCqlGenerator< cql.append(primaries); cql.append(parenthesize ? ")" : ""); // end primary key clause + + cql.append(")"); // end columns // begin options diff --git a/src/main/java/org/springframework/cassandra/core/cql/generator/DropTableCqlGenerator.java b/src/main/java/org/springframework/cassandra/core/cql/generator/DropTableCqlGenerator.java index 9f8a66ec1..21049e638 100644 --- a/src/main/java/org/springframework/cassandra/core/cql/generator/DropTableCqlGenerator.java +++ b/src/main/java/org/springframework/cassandra/core/cql/generator/DropTableCqlGenerator.java @@ -3,32 +3,20 @@ package org.springframework.cassandra.core.cql.generator; import static org.springframework.cassandra.core.cql.CqlStringUtils.noNull; import org.springframework.cassandra.core.keyspace.DropTableSpecification; -import org.springframework.util.Assert; /** * CQL generator for generating a DROP TABLE statement. * * @author Matthew T. Adams */ -public class DropTableCqlGenerator { - - protected DropTableSpecification specification; +public class DropTableCqlGenerator extends TableNameCqlGenerator { public DropTableCqlGenerator(DropTableSpecification specification) { - setSpecification(specification); - } - - protected void setSpecification(DropTableSpecification specification) { - Assert.notNull(specification); - this.specification = specification; + super(specification); } public StringBuilder toCql(StringBuilder cql) { - return noNull(cql).append("DROP TABLE ").append(specification.getIfExists() ? "IF EXISTS " : "") - .append(specification.getNameAsIdentifier()); - } - - public String toCql() { - return toCql(null).toString(); + return noNull(cql).append("DROP TABLE ").append(spec().getIfExists() ? "IF EXISTS " : "") + .append(spec().getNameAsIdentifier()).append(";"); } } diff --git a/src/main/java/org/springframework/cassandra/core/cql/generator/AbstractTableOperationCqlGenerator.java b/src/main/java/org/springframework/cassandra/core/cql/generator/TableCqlGenerator.java similarity index 65% rename from src/main/java/org/springframework/cassandra/core/cql/generator/AbstractTableOperationCqlGenerator.java rename to src/main/java/org/springframework/cassandra/core/cql/generator/TableCqlGenerator.java index 89b94bf5f..3887f01bc 100644 --- a/src/main/java/org/springframework/cassandra/core/cql/generator/AbstractTableOperationCqlGenerator.java +++ b/src/main/java/org/springframework/cassandra/core/cql/generator/TableCqlGenerator.java @@ -6,9 +6,8 @@ import static org.springframework.cassandra.core.cql.CqlStringUtils.singleQuote; import java.util.Map; -import org.springframework.cassandra.core.keyspace.AbstractTableSpecification; import org.springframework.cassandra.core.keyspace.Option; -import org.springframework.util.Assert; +import org.springframework.cassandra.core.keyspace.TableSpecification; /** * Base class that contains behavior common to CQL generation for table operations. @@ -16,31 +15,16 @@ import org.springframework.util.Assert; * @author Matthew T. Adams * @param T The subtype of this class for which this is a CQL generator. */ -public abstract class AbstractTableOperationCqlGenerator> { +public abstract class TableCqlGenerator> extends + TableOptionsCqlGenerator> { - public abstract StringBuilder toCql(StringBuilder cql); - - private AbstractTableSpecification specification; - - public AbstractTableOperationCqlGenerator(AbstractTableSpecification specification) { - setSpecification(specification); - } - - protected void setSpecification(AbstractTableSpecification specification) { - Assert.notNull(specification); - this.specification = specification; + public TableCqlGenerator(TableSpecification specification) { + super(specification); } @SuppressWarnings("unchecked") - public T getSpecification() { - return (T) specification; - } - - /** - * Convenient synonymous method of {@link #getSpecification()}. - */ protected T spec() { - return getSpecification(); + return (T) getSpecification(); } protected StringBuilder optionValueMap(Map valueMap, StringBuilder cql) { @@ -78,8 +62,4 @@ public abstract class AbstractTableOperationCqlGenerator> { + + public abstract StringBuilder toCql(StringBuilder cql); + + private TableNameSpecification specification; + + public TableNameCqlGenerator(TableNameSpecification specification) { + setSpecification(specification); + } + + protected void setSpecification(TableNameSpecification specification) { + Assert.notNull(specification); + this.specification = specification; + } + + @SuppressWarnings("unchecked") + public T getSpecification() { + return (T) specification; + } + + /** + * Convenient synonymous method of {@link #getSpecification()}. + */ + protected T spec() { + return getSpecification(); + } + + public String toCql() { + return toCql(null).toString(); + } +} diff --git a/src/main/java/org/springframework/cassandra/core/cql/generator/TableOptionsCqlGenerator.java b/src/main/java/org/springframework/cassandra/core/cql/generator/TableOptionsCqlGenerator.java new file mode 100644 index 000000000..3ddbaa40a --- /dev/null +++ b/src/main/java/org/springframework/cassandra/core/cql/generator/TableOptionsCqlGenerator.java @@ -0,0 +1,65 @@ +package org.springframework.cassandra.core.cql.generator; + +import static org.springframework.cassandra.core.cql.CqlStringUtils.escapeSingle; +import static org.springframework.cassandra.core.cql.CqlStringUtils.noNull; +import static org.springframework.cassandra.core.cql.CqlStringUtils.singleQuote; + +import java.util.Map; + +import org.springframework.cassandra.core.keyspace.Option; +import org.springframework.cassandra.core.keyspace.TableOptionsSpecification; + +/** + * Base class that contains behavior common to CQL generation for table operations. + * + * @author Matthew T. Adams + * @param T The subtype of this class for which this is a CQL generator. + */ +public abstract class TableOptionsCqlGenerator> extends + TableNameCqlGenerator> { + + public TableOptionsCqlGenerator(TableOptionsSpecification specification) { + super(specification); + } + + @SuppressWarnings("unchecked") + protected T spec() { + return (T) getSpecification(); + } + + protected StringBuilder optionValueMap(Map valueMap, StringBuilder cql) { + cql = noNull(cql); + + if (valueMap == null || valueMap.isEmpty()) { + return cql; + } + // else option value is a non-empty map + + // append { 'name' : 'value', ... } + cql.append("{ "); + boolean mapFirst = true; + for (Map.Entry entry : valueMap.entrySet()) { + if (mapFirst) { + mapFirst = false; + } else { + cql.append(", "); + } + + Option option = entry.getKey(); + cql.append(singleQuote(option.getName())); // entries in map keys are always quoted + cql.append(" : "); + Object entryValue = entry.getValue(); + entryValue = entryValue == null ? "" : entryValue.toString(); + if (option.escapesValue()) { + entryValue = escapeSingle(entryValue); + } + if (option.quotesValue()) { + entryValue = singleQuote(entryValue); + } + cql.append(entryValue); + } + cql.append(" }"); + + return cql; + } +} diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/AlterTableSpecification.java b/src/main/java/org/springframework/cassandra/core/keyspace/AlterTableSpecification.java index 6f1d9fd7d..7e192133e 100644 --- a/src/main/java/org/springframework/cassandra/core/keyspace/AlterTableSpecification.java +++ b/src/main/java/org/springframework/cassandra/core/keyspace/AlterTableSpecification.java @@ -6,25 +6,45 @@ import java.util.List; import com.datastax.driver.core.DataType; -public class AlterTableSpecification extends AbstractTableSpecification { +/** + * Builder class to construct an ALTER TABLE specification. + * + * @author Matthew T. Adams + */ +public class AlterTableSpecification extends TableOptionsSpecification { + /** + * The list of column changes. + */ private List changes = new ArrayList(); + /** + * Adds a DROP to the list of column changes. + */ public AlterTableSpecification drop(String column) { changes.add(new DropColumnSpecification(column)); return this; } + /** + * Adds an ADD to the list of column changes. + */ public AlterTableSpecification add(String column, DataType type) { changes.add(new AddColumnSpecification(column, type)); return this; } + /** + * Adds an ALTER to the list of column changes. + */ public AlterTableSpecification alter(String column, DataType type) { changes.add(new AlterColumnSpecification(column, type)); return this; } + /** + * Returns an unmodifiable list of column changes. + */ public List getChanges() { return Collections.unmodifiableList(changes); } diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/CreateTableSpecification.java b/src/main/java/org/springframework/cassandra/core/keyspace/CreateTableSpecification.java index 6f14a4021..28981ede9 100644 --- a/src/main/java/org/springframework/cassandra/core/keyspace/CreateTableSpecification.java +++ b/src/main/java/org/springframework/cassandra/core/keyspace/CreateTableSpecification.java @@ -1,27 +1,13 @@ package org.springframework.cassandra.core.keyspace; -import static org.springframework.data.cassandra.mapping.KeyType.PARTITION; -import static org.springframework.data.cassandra.mapping.KeyType.PRIMARY; -import static org.springframework.data.cassandra.mapping.Ordering.ASCENDING; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.springframework.data.cassandra.mapping.KeyType; -import org.springframework.data.cassandra.mapping.Ordering; - -import com.datastax.driver.core.DataType; - /** - * Builder class to construct CQL for a CREATE TABLE statement. Not threadsafe. + * Builder class to construct a CREATE TABLE specification. * * @author Matthew T. Adams */ -public class CreateTableSpecification extends AbstractTableSpecification { +public class CreateTableSpecification extends TableSpecification { private boolean ifNotExists = false; - private List columns = new ArrayList(); /** * Causes the inclusion of an IF NOT EXISTS clause. @@ -42,36 +28,7 @@ public class CreateTableSpecification extends AbstractTableSpecification columns() { - return columns == null ? columns = new ArrayList() : columns; - } - public boolean getIfNotExists() { return ifNotExists; } - - public List getColumns() { - return Collections.unmodifiableList(columns); - } } diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/DefaultTableDescriptor.java b/src/main/java/org/springframework/cassandra/core/keyspace/DefaultTableDescriptor.java new file mode 100644 index 000000000..0e7c24638 --- /dev/null +++ b/src/main/java/org/springframework/cassandra/core/keyspace/DefaultTableDescriptor.java @@ -0,0 +1,17 @@ +package org.springframework.cassandra.core.keyspace; + +/** + * Convenient default implementation of {@link TableDescriptor} as an extension of {@link TableSpecification} that + * doesn't require the use of generics. + * + * @author Matthew T. Adams + */ +public class DefaultTableDescriptor extends TableSpecification { + + /** + * Factory method to produce a new {@link DefaultTableDescriptor}. Convenient if imported statically. + */ + public static DefaultTableDescriptor table() { + return new DefaultTableDescriptor(); + } +} diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/DropTableSpecification.java b/src/main/java/org/springframework/cassandra/core/keyspace/DropTableSpecification.java index 0b219c53e..a3e66b274 100644 --- a/src/main/java/org/springframework/cassandra/core/keyspace/DropTableSpecification.java +++ b/src/main/java/org/springframework/cassandra/core/keyspace/DropTableSpecification.java @@ -1,19 +1,14 @@ package org.springframework.cassandra.core.keyspace; -import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier; -import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; +/** + * Builder class that supports the construction of DROP TABLE specifications. + * + * @author Matthew T. Adams + */ +public class DropTableSpecification extends TableNameSpecification { -public class DropTableSpecification { - - private String name; private boolean ifExists; - public DropTableSpecification name(String name) { - checkIdentifier(name); - this.name = name; - return this; - } - public DropTableSpecification ifExists() { return ifExists(true); } @@ -26,8 +21,4 @@ public class DropTableSpecification { public boolean getIfExists() { return ifExists; } - - public String getNameAsIdentifier() { - return identifize(name); - } } diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/TableDescriptor.java b/src/main/java/org/springframework/cassandra/core/keyspace/TableDescriptor.java new file mode 100644 index 000000000..2a17486a0 --- /dev/null +++ b/src/main/java/org/springframework/cassandra/core/keyspace/TableDescriptor.java @@ -0,0 +1,52 @@ +package org.springframework.cassandra.core.keyspace; + +import java.util.List; +import java.util.Map; + +/** + * Describes a table. + * + * @author Matthew T. Adams + */ +public interface TableDescriptor { + + /** + * Returns the name of the table. + */ + String getName(); + + /** + * Returns the name of the table as an identifer or quoted identifier as appropriate. + */ + String getNameAsIdentifier(); + + /** + * Returns an unmodifiable {@link List} of {@link ColumnSpecification}s. + */ + List getColumns(); + + /** + * Returns an unmodifiable list of all partition key columns. + */ + public List getPartitionKeyColumns(); + + /** + * Returns an unmodifiable list of all primary key columns that are not also partition key columns. + */ + public List getPrimaryKeyColumns(); + + /** + * Returns an unmodifiable list of all partition and primary key columns. + */ + public List getKeyColumns(); + + /** + * Returns an unmodifiable list of all non-key columns. + */ + public List getNonKeyColumns(); + + /** + * Returns an unmodifiable {@link Map} of table options. + */ + Map getOptions(); +} diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/TableNameSpecification.java b/src/main/java/org/springframework/cassandra/core/keyspace/TableNameSpecification.java new file mode 100644 index 000000000..2cf3b993e --- /dev/null +++ b/src/main/java/org/springframework/cassandra/core/keyspace/TableNameSpecification.java @@ -0,0 +1,38 @@ +package org.springframework.cassandra.core.keyspace; + +import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier; +import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; + +/** + * Abstract builder class to support the construction of table specifications. + * + * @author Matthew T. Adams + * @param The subtype of the {@link TableNameSpecification} + */ +public abstract class TableNameSpecification> { + + /** + * The name of the table. + */ + private String name; + + /** + * Sets the table name. + * + * @return this + */ + @SuppressWarnings("unchecked") + public T name(String name) { + checkIdentifier(name); + this.name = name; + return (T) this; + } + + public String getName() { + return name; + } + + public String getNameAsIdentifier() { + return identifize(name); + } +} diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/TableOption.java b/src/main/java/org/springframework/cassandra/core/keyspace/TableOption.java index c9cb7d93e..7f6d56fca 100644 --- a/src/main/java/org/springframework/cassandra/core/keyspace/TableOption.java +++ b/src/main/java/org/springframework/cassandra/core/keyspace/TableOption.java @@ -122,9 +122,13 @@ public enum TableOption implements Option { this.value = value; } - public String toString() { + public String getValue() { return value; } + + public String toString() { + return getValue(); + } } /** diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/AbstractTableSpecification.java b/src/main/java/org/springframework/cassandra/core/keyspace/TableOptionsSpecification.java similarity index 75% rename from src/main/java/org/springframework/cassandra/core/keyspace/AbstractTableSpecification.java rename to src/main/java/org/springframework/cassandra/core/keyspace/TableOptionsSpecification.java index 1e1ff0ad8..de6c8d9d2 100644 --- a/src/main/java/org/springframework/cassandra/core/keyspace/AbstractTableSpecification.java +++ b/src/main/java/org/springframework/cassandra/core/keyspace/TableOptionsSpecification.java @@ -1,8 +1,6 @@ package org.springframework.cassandra.core.keyspace; -import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier; import static org.springframework.cassandra.core.cql.CqlStringUtils.escapeSingle; -import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize; import static org.springframework.cassandra.core.cql.CqlStringUtils.singleQuote; import java.util.Collections; @@ -12,39 +10,26 @@ import java.util.Map; import org.springframework.cassandra.core.cql.CqlStringUtils; /** - * Base class that contains behavior common to table operations. + * Abstract builder class to support the construction of table specifications that have table options, that is, those + * options normally specified by WITH ... AND .... + *

+ * It is important to note that although this class depends on {@link TableOption} for convenient and typesafe use, it + * ultimately stores its options in a Map for flexibility. This means that + * {@link #with(TableOption)} and {@link #with(TableOption, Object)} delegate to + * {@link #with(String, Object, boolean, boolean)}. This design allows the API to support new Cassandra options as they + * are introduced without having to update the code immediately. * * @author Matthew T. Adams - * @param T The subtype of AbstractTableBuilder. + * @param The subtype of the {@link TableOptionsSpecification}. */ -public abstract class AbstractTableSpecification> { - - private String name; +public abstract class TableOptionsSpecification> extends + TableNameSpecification> { protected Map options = new LinkedHashMap(); - /** - * Sets the table name. - * - * @return this - */ @SuppressWarnings("unchecked") public T name(String name) { - setName(name); - return (T) this; - } - - public void setName(String name) { - checkIdentifier(name); - this.name = name; - } - - public String getName() { - return name; - } - - public String getNameAsIdentifier() { - return identifize(name); + return (T) super.name(name); } /** diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/TableSpecification.java b/src/main/java/org/springframework/cassandra/core/keyspace/TableSpecification.java new file mode 100644 index 000000000..ba8c70c63 --- /dev/null +++ b/src/main/java/org/springframework/cassandra/core/keyspace/TableSpecification.java @@ -0,0 +1,162 @@ +package org.springframework.cassandra.core.keyspace; + +import static org.springframework.data.cassandra.mapping.KeyType.PARTITION; +import static org.springframework.data.cassandra.mapping.KeyType.PRIMARY; +import static org.springframework.data.cassandra.mapping.Ordering.ASCENDING; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.data.cassandra.mapping.KeyType; +import org.springframework.data.cassandra.mapping.Ordering; + +import com.datastax.driver.core.DataType; + +/** + * Builder class to support the construction of table specifications that have columns. This class can also be used as a + * standalone {@link TableDescriptor}, independent of {@link CreateTableSpecification}. + * + * @author Matthew T. Adams + */ +public class TableSpecification extends TableOptionsSpecification> implements TableDescriptor { + + /** + * List of all columns. + */ + private List columns = new ArrayList(); + + /** + * List of only those columns that comprise the partition key. + */ + private List partitionKeyColumns = new ArrayList(); + + /** + * List of only those columns that comprise the primary key that are not also part of the partition key. + */ + private List primaryKeyColumns = new ArrayList(); + + /** + * List of only those columns that are not partition or primary key columns. + */ + private List nonKeyColumns = new ArrayList(); + + /** + * Adds the given non-key column to the table. Must be specified after all primary key columns. + * + * @param name The column name; must be a valid unquoted or quoted identifier without the surrounding double quotes. + * @param type The data type of the column. + */ + public T column(String name, DataType type) { + return column(name, type, null, null); + } + + /** + * Adds the given partition key column to the table. Must be specified before any other columns. + * + * @param name The column name; must be a valid unquoted or quoted identifier without the surrounding double quotes. + * @param type The data type of the column. + * @return this + */ + public T partitionKeyColumn(String name, DataType type) { + return column(name, type, PARTITION, null); + } + + /** + * Adds the given primary key column to the table with ascending ordering. Must be specified after all partition key + * columns and before any non-key columns. + * + * @param name The column name; must be a valid unquoted or quoted identifier without the surrounding double quotes. + * @param type The data type of the column. + * @return this + */ + public T primaryKeyColumn(String name, DataType type) { + return primaryKeyColumn(name, type, ASCENDING); + } + + /** + * Adds the given primary key column to the table with the given ordering (null meaning ascending). Must + * be specified after all partition key columns and before any non-key columns. + * + * @param name The column name; must be a valid unquoted or quoted identifier without the surrounding double quotes. + * @param type The data type of the column. + * @return this + */ + public T primaryKeyColumn(String name, DataType type, Ordering ordering) { + return column(name, type, PRIMARY, ordering); + } + + /** + * Adds the given info as a new column to the table. Partition key columns must precede primary key columns, which + * must precede non-key columns. + * + * @param name The column name; must be a valid unquoted or quoted identifier without the surrounding double quotes. + * @param type The data type of the column. + * @param keyType Indicates key type. Null means that the column is not a key column. + * @param ordering If the given {@link KeyType} is {@link KeyType#PRIMARY}, then the given ordering is used, else + * ignored. + * @return this + */ + @SuppressWarnings("unchecked") + protected T column(String name, DataType type, KeyType keyType, Ordering ordering) { + + ColumnSpecification column = new ColumnSpecification().name(name).type(type).keyType(keyType) + .ordering(keyType == PRIMARY ? ordering : null); + + columns.add(column); + + if (keyType == KeyType.PARTITION) { + partitionKeyColumns.add(column); + } + + if (keyType == KeyType.PRIMARY) { + primaryKeyColumns.add(column); + } + + if (keyType == null) { + nonKeyColumns.add(column); + } + + return (T) this; + } + + /** + * Returns an unmodifiable list of all columns. + */ + public List getColumns() { + return Collections.unmodifiableList(columns); + } + + /** + * Returns an unmodifiable list of all partition key columns. + */ + public List getPartitionKeyColumns() { + return Collections.unmodifiableList(partitionKeyColumns); + } + + /** + * Returns an unmodifiable list of all primary key columns that are not also partition key columns. + */ + public List getPrimaryKeyColumns() { + return Collections.unmodifiableList(primaryKeyColumns); + } + + /** + * Returns an unmodifiable list of all primary key columns that are not also partition key columns. + */ + public List getKeyColumns() { + + ArrayList keyColumns = new ArrayList(); + keyColumns.addAll(partitionKeyColumns); + keyColumns.addAll(primaryKeyColumns); + + return Collections.unmodifiableList(keyColumns); + } + + /** + * Returns an unmodifiable list of all non-key columns. + */ + public List getNonKeyColumns() { + return Collections.unmodifiableList(nonKeyColumns); + } +} diff --git a/src/main/java/org/springframework/cassandra/core/keyspace/MapBuilder.java b/src/main/java/org/springframework/cassandra/core/util/MapBuilder.java similarity index 98% rename from src/main/java/org/springframework/cassandra/core/keyspace/MapBuilder.java rename to src/main/java/org/springframework/cassandra/core/util/MapBuilder.java index ea68ca38a..7b50dd549 100644 --- a/src/main/java/org/springframework/cassandra/core/keyspace/MapBuilder.java +++ b/src/main/java/org/springframework/cassandra/core/util/MapBuilder.java @@ -1,4 +1,4 @@ -package org.springframework.cassandra.core.keyspace; +package org.springframework.cassandra.core.util; import java.util.Collection; import java.util.LinkedHashMap; diff --git a/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java b/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java index 82bd0e855..c3c421ac9 100644 --- a/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java +++ b/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java @@ -144,7 +144,7 @@ public class CassandraKeyspaceFactoryBean implements FactoryBean, Init // drop the old keyspace if needed if (keyspaceExists && (keyspaceAttributes.isCreate() || keyspaceAttributes.isCreateDrop())) { log.info("Drop keyspace " + keyspace + " on afterPropertiesSet"); - session.execute("DROP KEYSPACE " + keyspace); + session.execute("DROP KEYSPACE " + keyspace + ";"); keyspaceExists = false; } diff --git a/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/AbstractEmbeddedCassandraIntegrationTest.java b/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/AbstractEmbeddedCassandraIntegrationTest.java new file mode 100644 index 000000000..be34c18f3 --- /dev/null +++ b/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/AbstractEmbeddedCassandraIntegrationTest.java @@ -0,0 +1,83 @@ +package org.springframework.cassandra.test.integration.core.cql.generator; + +import java.io.IOException; +import java.util.UUID; + +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.thrift.transport.TTransportException; +import org.cassandraunit.utils.EmbeddedCassandraServerHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.driver.core.Session; + +public abstract class AbstractEmbeddedCassandraIntegrationTest { + + @BeforeClass + public static void beforeClass() throws ConfigurationException, TTransportException, IOException, + InterruptedException { + EmbeddedCassandraServerHelper.startEmbeddedCassandra("cassandra.yaml"); + } + + /** + * Whether to clear the cluster before the next test. + */ + protected boolean clear = true; + /** + * Whether to connect to Cassandra. + */ + protected boolean connect = true; + /** + * The {@link Cluster} that's connected to Cassandra. + */ + protected Cluster cluster; + /** + * If not null, get a {@link Session} for the from the {@link #cluster}. + */ + protected String keyspace = "ks" + UUID.randomUUID().toString().replace("-", ""); + /** + * The {@link Session} for the {@link #keyspace} from the {@link #cluster}. + */ + protected Session session; + + /** + * Returns whether we're currently connected to the cluster. + */ + public boolean connected() { + return session != null; + } + + public Cluster cluster() { + return Cluster.builder().addContactPoint("localhost").withPort(9042).build(); + } + + @Before + public void before() { + if (connect && !connected()) { + cluster = cluster(); + + if (keyspace == null) { + session = cluster.connect(); + } else { + + KeyspaceMetadata kmd = cluster.getMetadata().getKeyspace(keyspace); + if (kmd == null) { // then create keyspace + session = cluster.connect(); + session.execute("CREATE KEYSPACE " + keyspace + + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};"); + session.execute("USE " + keyspace + ";"); + } // else keyspace already exists + } + } + } + + @After + public void after() { + if (clear && connected()) { + EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); + } + } +} diff --git a/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlTableSpecificationAssertions.java b/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlTableSpecificationAssertions.java new file mode 100644 index 000000000..865be7af9 --- /dev/null +++ b/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlTableSpecificationAssertions.java @@ -0,0 +1,144 @@ +package org.springframework.cassandra.test.integration.core.cql.generator; + +import static junit.framework.Assert.assertEquals; + +import java.util.List; +import java.util.Map; + +import org.springframework.cassandra.core.keyspace.ColumnSpecification; +import org.springframework.cassandra.core.keyspace.TableDescriptor; +import org.springframework.cassandra.core.keyspace.TableOption; +import org.springframework.cassandra.core.keyspace.TableOption.CachingOption; + +import com.datastax.driver.core.ColumnMetadata; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.TableMetadata; +import com.datastax.driver.core.TableMetadata.Options; + +public class CqlTableSpecificationAssertions { + + public static double DELTA = 1e-6; // delta for comparisons of doubles + + public static void assertTable(TableDescriptor expected, String keyspace, Session session) { + TableMetadata tmd = session.getCluster().getMetadata().getKeyspace(keyspace.toLowerCase()) + .getTable(expected.getName()); + + assertEquals(expected.getName().toLowerCase(), tmd.getName().toLowerCase()); + assertPartitionKeyColumns(expected, tmd); + assertPrimaryKeyColumns(expected, tmd); + assertColumns(expected.getColumns(), tmd.getColumns()); + assertOptions(expected.getOptions(), tmd.getOptions()); + } + + public static void assertPartitionKeyColumns(TableDescriptor expected, TableMetadata actual) { + assertColumns(expected.getPartitionKeyColumns(), actual.getPartitionKey()); + } + + public static void assertPrimaryKeyColumns(TableDescriptor expected, TableMetadata actual) { + assertColumns(expected.getKeyColumns(), actual.getPrimaryKey()); + } + + public static void assertOptions(Map expected, Options actual) { + + for (String key : expected.keySet()) { + + Object value = expected.get(key); + TableOption tableOption = getTableOptionFor(key); + + if (tableOption == null && key.equalsIgnoreCase(TableOption.COMPACT_STORAGE.getName())) { + // TODO: figure out how to tell if COMPACT STORAGE was used + continue; + } + + assertOption(tableOption, key, value, getOptionFor(tableOption, tableOption.getType(), actual)); + } + } + + @SuppressWarnings({ "unchecked", "incomplete-switch" }) + public static void assertOption(TableOption tableOption, String key, Object expected, Object actual) { + + if (tableOption == null) { // then this is a string-only or unknown value + key.equalsIgnoreCase(actual.toString()); // TODO: determine if this is the right test + } + + switch (tableOption) { + + case BLOOM_FILTER_FP_CHANCE: + case READ_REPAIR_CHANCE: + case DCLOCAL_READ_REPAIR_CHANCE: + assertEquals((Double) expected, (Double) actual, DELTA); + return; + + case CACHING: + assertEquals(CachingOption.valueOf((String) expected).getValue(), actual); + return; + + case COMPACTION: + assertCompaction((Map) expected, (Map) actual); + return; + + case COMPRESSION: + assertCompression((Map) expected, (Map) actual); + return; + } + + assertEquals(expected, actual); + } + + public static void assertCompaction(Map expected, Map actual) { + // TODO + } + + public static void assertCompression(Map expected, Map actual) { + // TODO + } + + public static TableOption getTableOptionFor(String key) { + try { + return TableOption.valueOf(key); + } catch (IllegalArgumentException x) { + return null; + } + } + + @SuppressWarnings("unchecked") + public static T getOptionFor(TableOption option, Class type, Options options) { + switch (option) { + case BLOOM_FILTER_FP_CHANCE: + return (T) (Double) options.getBloomFilterFalsePositiveChance(); + case CACHING: + return (T) options.getCaching(); + case COMMENT: + return (T) options.getComment(); + case COMPACTION: + return (T) options.getCompaction(); + case COMPACT_STORAGE: + throw new Error(); // TODO: figure out + case COMPRESSION: + return (T) options.getCompression(); + case DCLOCAL_READ_REPAIR_CHANCE: + return (T) (Double) options.getReadRepairChance(); + case GC_GRACE_SECONDS: + return (T) new Long(options.getGcGraceInSeconds()); + case READ_REPAIR_CHANCE: + return (T) (Double) options.getReadRepairChance(); + case REPLICATE_ON_WRITE: + return (T) (Boolean) options.getReplicateOnWrite(); + } + return null; + } + + public static void assertColumns(List expected, List actual) { + for (int i = 0; i < expected.size(); i++) { + ColumnSpecification expectedColumn = expected.get(i); + ColumnMetadata actualColumn = actual.get(i); + + assertColumn(expectedColumn, actualColumn); + } + } + + public static void assertColumn(ColumnSpecification expected, ColumnMetadata actual) { + assertEquals(expected.getName().toLowerCase(), actual.getName().toLowerCase()); + assertEquals(expected.getType(), actual.getType()); + } +} \ No newline at end of file diff --git a/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CreateTableCqlGeneratorIntegrationTests.java b/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CreateTableCqlGeneratorIntegrationTests.java new file mode 100644 index 000000000..bd9c91b1e --- /dev/null +++ b/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CreateTableCqlGeneratorIntegrationTests.java @@ -0,0 +1,22 @@ +package org.springframework.cassandra.test.integration.core.cql.generator; + +import static org.springframework.cassandra.test.integration.core.cql.generator.CqlTableSpecificationAssertions.assertTable; + +import org.junit.Test; +import org.springframework.cassandra.test.unit.core.cql.generator.CreateTableCqlGeneratorTests.BasicTest; + +public class CreateTableCqlGeneratorIntegrationTests { + + public static class BasicIntegrationTest extends AbstractEmbeddedCassandraIntegrationTest { + BasicTest unit = new BasicTest(); + + @Test + public void test() { + unit.prepare(); + + session.execute(unit.cql); + + assertTable(unit.specification, keyspace, session); + } + } +} \ No newline at end of file diff --git a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTest.java b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTest.java deleted file mode 100644 index fff4109c1..000000000 --- a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.springframework.cassandra.test.unit.core.cql.generator; - -import static org.springframework.cassandra.core.keyspace.TableOperations.alterTable; - -import org.junit.Test; -import org.springframework.cassandra.core.cql.generator.AlterTableCqlGenerator; -import org.springframework.cassandra.core.keyspace.AlterTableSpecification; - -import com.datastax.driver.core.DataType; - -public class AlterTableCqlGeneratorTest { - - @Test - public void testAlterTableBuilder() throws Exception { - String name = "mytable"; - DataType addedType = DataType.timeuuid(); - String addedName = "added_column"; - DataType alteredType = DataType.text(); - String alteredName = "altered_column"; - String droppedName = "dropped"; - - AlterTableSpecification alter = alterTable().name(name).add(addedName, addedType).alter(alteredName, alteredType) - .drop(droppedName); - AlterTableCqlGenerator generator = new AlterTableCqlGenerator(alter); - System.out.println(generator.toCql()); - } -} diff --git a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTests.java b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTests.java new file mode 100644 index 000000000..420c7b35d --- /dev/null +++ b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/AlterTableCqlGeneratorTests.java @@ -0,0 +1,65 @@ +package org.springframework.cassandra.test.unit.core.cql.generator; + +import static junit.framework.Assert.assertTrue; +import static org.springframework.cassandra.core.keyspace.TableOperations.alterTable; + +import org.junit.Test; +import org.springframework.cassandra.core.cql.generator.AlterTableCqlGenerator; +import org.springframework.cassandra.core.keyspace.AlterTableSpecification; + +import com.datastax.driver.core.DataType; + +public class AlterTableCqlGeneratorTests { + + /** + * Asserts that the preamble is first & correctly formatted in the given CQL string. + */ + public static void assertPreamble(String tableName, String cql) { + assertTrue(cql.startsWith("ALTER TABLE " + tableName + " ")); + } + + /** + * Asserts that the given list of columns definitions are contained in the given CQL string properly. + * + * @param columnSpec IE, "foo text, bar blob" + */ + public static void assertColumnChanges(String columnSpec, String cql) { + assertTrue(cql.contains("")); + } + + /** + * Convenient base class that other test classes can use so as not to repeat the generics declarations. + */ + public static abstract class AlterTableTest extends + TableOperationCqlGeneratorTest { + } + + public static class BasicTest extends AlterTableTest { + + public String name = "mytable"; + public DataType alteredType = DataType.text(); + public String altered = "altered"; + + public DataType addedType = DataType.text(); + public String added = "added"; + + public String dropped = "dropped"; + + public AlterTableSpecification specification() { + return alterTable().name(name).alter(altered, alteredType).add(added, addedType).drop(dropped); + } + + public AlterTableCqlGenerator generator() { + return new AlterTableCqlGenerator(specification); + } + + @Test + public void test() { + prepare(); + + assertPreamble(name, cql); + assertColumnChanges( + String.format("ALTER %s TYPE %s, ADD %s %s, DROP %s", altered, alteredType, added, addedType, dropped), cql); + } + } +} diff --git a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateTableCqlGeneratorTest.java b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateTableCqlGeneratorTest.java deleted file mode 100644 index ae04a8b8e..000000000 --- a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateTableCqlGeneratorTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.springframework.cassandra.test.unit.core.cql.generator; - -import static junit.framework.Assert.assertEquals; -import static org.springframework.cassandra.core.keyspace.MapBuilder.map; -import static org.springframework.cassandra.core.keyspace.TableOperations.createTable; -import static org.springframework.cassandra.core.keyspace.TableOption.BLOOM_FILTER_FP_CHANCE; -import static org.springframework.cassandra.core.keyspace.TableOption.CACHING; -import static org.springframework.cassandra.core.keyspace.TableOption.COMMENT; -import static org.springframework.cassandra.core.keyspace.TableOption.COMPACTION; -import static org.springframework.cassandra.core.keyspace.TableOption.CompactionOption.TOMBSTONE_THRESHOLD; - -import org.junit.Test; -import org.springframework.cassandra.core.cql.generator.CreateTableCqlGenerator; -import org.springframework.cassandra.core.keyspace.CreateTableSpecification; -import org.springframework.cassandra.core.keyspace.TableOption.CachingOption; - -import com.datastax.driver.core.DataType; - -public class CreateTableCqlGeneratorTest { - - @Test - public void createTableTest() { - String name = "my\"\"table"; - DataType type0 = DataType.text(); - String partKey0 = "partitionKey0"; - String partition1 = "partitionKey1"; - String primary0 = "primary0"; - DataType type1 = DataType.text(); - String column1 = "column1"; - DataType type2 = DataType.bigint(); - String column2 = "column2"; - Object comment = "this is a comment"; - Object bloom = "0.00075"; - Object caching = CachingOption.KEYS_ONLY; - - CreateTableSpecification create = createTable().ifNotExists().name(name).partitionKeyColumn(partKey0, type0) - .partitionKeyColumn(partition1, type0).primaryKeyColumn(primary0, type0).column(column1, type1) - .column(column2, type2).with(COMMENT, comment).with(BLOOM_FILTER_FP_CHANCE, bloom) - .with(COMPACTION, map().entry(TOMBSTONE_THRESHOLD, "0.15")).with(CACHING, caching); - - CreateTableCqlGenerator generator = new CreateTableCqlGenerator(create); - String cql = generator.toCql(); - assertEquals( - "CREATE TABLE IF NOT EXISTS \"my\"\"table\" (partitionKey0 text, partitionKey1 text, primary0 text, column1 text, column2 bigint, PRIMARY KEY ((partitionKey0, partitionKey1), primary0) WITH CLUSTERING ORDER BY (primary0 ASC) AND comment = 'this is a comment' AND bloom_filter_fp_chance = 0.00075 AND compaction = { 'tombstone_threshold' : 0.15 } AND caching = keys_only;", - cql); - } -} diff --git a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateTableCqlGeneratorTests.java b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateTableCqlGeneratorTests.java new file mode 100644 index 000000000..6005d22f7 --- /dev/null +++ b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateTableCqlGeneratorTests.java @@ -0,0 +1,71 @@ +package org.springframework.cassandra.test.unit.core.cql.generator; + +import static junit.framework.Assert.assertTrue; +import static org.springframework.cassandra.core.keyspace.TableOperations.createTable; + +import org.junit.Test; +import org.springframework.cassandra.core.cql.generator.CreateTableCqlGenerator; +import org.springframework.cassandra.core.keyspace.CreateTableSpecification; + +import com.datastax.driver.core.DataType; + +public class CreateTableCqlGeneratorTests { + + /** + * Asserts that the preamble is first & correctly formatted in the given CQL string. + */ + public static void assertPreamble(String tableName, String cql) { + assertTrue(cql.startsWith("CREATE TABLE " + tableName + " ")); + } + + /** + * Asserts that the given primary key definition is contained in the given CQL string properly. + * + * @param primaryKeyString IE, "foo", "foo, bar, baz", "(foo, bar), baz", etc + */ + public static void assertPrimaryKey(String primaryKeyString, String cql) { + assertTrue(cql.contains(", PRIMARY KEY (" + primaryKeyString + "))")); + } + + /** + * Asserts that the given list of columns definitions are contained in the given CQL string properly. + * + * @param columnSpec IE, "foo text, bar blob" + */ + public static void assertColumns(String columnSpec, String cql) { + assertTrue(cql.contains("(" + columnSpec + ",")); + } + + /** + * Convenient base class that other test classes can use so as not to repeat the generics declarations. + */ + public static abstract class CreateTableTest extends + TableOperationCqlGeneratorTest { + } + + public static class BasicTest extends CreateTableTest { + + public String name = "mytable"; + public DataType partitionKeyType0 = DataType.text(); + public String partitionKey0 = "partitionKey0"; + public DataType columnType1 = DataType.text(); + public String column1 = "column1"; + + public CreateTableSpecification specification() { + return createTable().name(name).partitionKeyColumn(partitionKey0, partitionKeyType0).column(column1, columnType1); + } + + public CreateTableCqlGenerator generator() { + return new CreateTableCqlGenerator(specification); + } + + @Test + public void test() { + prepare(); + + assertPreamble(name, cql); + assertColumns(partitionKey0 + " " + partitionKeyType0 + ", " + column1 + " " + columnType1, cql); + assertPrimaryKey(partitionKey0, cql); + } + } +} diff --git a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/DropTableCqlGeneratorTest.java b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/DropTableCqlGeneratorTest.java deleted file mode 100644 index 478c10922..000000000 --- a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/DropTableCqlGeneratorTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.springframework.cassandra.test.unit.core.cql.generator; - -import static org.springframework.cassandra.core.keyspace.TableOperations.dropTable; - -import org.junit.Test; -import org.springframework.cassandra.core.cql.generator.DropTableCqlGenerator; -import org.springframework.cassandra.core.keyspace.DropTableSpecification; - -public class DropTableCqlGeneratorTest { - - @Test - public void testDropTableBuilder() throws Exception { - DropTableSpecification drop = dropTable().ifExists().name("mytable"); - - DropTableCqlGenerator generator = new DropTableCqlGenerator(drop); - System.out.println(generator.toCql()); - } -} diff --git a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/DropTableCqlGeneratorTests.java b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/DropTableCqlGeneratorTests.java new file mode 100644 index 000000000..330fe7382 --- /dev/null +++ b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/DropTableCqlGeneratorTests.java @@ -0,0 +1,54 @@ +package org.springframework.cassandra.test.unit.core.cql.generator; + +import static junit.framework.Assert.assertTrue; +import static org.springframework.cassandra.core.keyspace.TableOperations.dropTable; + +import org.junit.Test; +import org.springframework.cassandra.core.cql.generator.DropTableCqlGenerator; +import org.springframework.cassandra.core.keyspace.DropTableSpecification; + +public class DropTableCqlGeneratorTests { + + /** + * Asserts that the preamble is first & correctly formatted in the given CQL string. + */ + public static void assertStatement(String tableName, String cql) { + assertTrue(cql.equals("DROP TABLE " + tableName + ";")); + } + + /** + * Asserts that the given list of columns definitions are contained in the given CQL string properly. + * + * @param columnSpec IE, "foo text, bar blob" + */ + public static void assertColumnChanges(String columnSpec, String cql) { + assertTrue(cql.contains("")); + } + + /** + * Convenient base class that other test classes can use so as not to repeat the generics declarations. + */ + public static abstract class DropTableTest extends + TableOperationCqlGeneratorTest { + } + + public static class BasicTest extends DropTableTest { + + public String name = "mytable"; + + public DropTableSpecification specification() { + return dropTable().name(name); + } + + public DropTableCqlGenerator generator() { + return new DropTableCqlGenerator(specification); + } + + @Test + public void test() { + prepare(); + + assertStatement(name, cql); + } + } +} diff --git a/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/TableOperationCqlGeneratorTest.java b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/TableOperationCqlGeneratorTest.java new file mode 100644 index 000000000..cb5172d2c --- /dev/null +++ b/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/TableOperationCqlGeneratorTest.java @@ -0,0 +1,36 @@ +package org.springframework.cassandra.test.unit.core.cql.generator; + +import org.springframework.cassandra.core.cql.generator.TableNameCqlGenerator; +import org.springframework.cassandra.core.keyspace.TableNameSpecification; + +/** + * Useful test class that specifies just about as much as you can for a CQL generation test. Intended to be extended by + * classes that contain methods annotated with {@link Test}. Everything is public because this is a test class with no + * need for encapsulation, and it makes for easier reuse in other tests like integration tests (hint hint). + * + * @author Matthew T. Adams + * + * @param The type of the {@link TableNameSpecification} + * @param The type of the {@link TableNameCqlGenerator} + */ +public abstract class TableOperationCqlGeneratorTest, G extends TableNameCqlGenerator> { + + public abstract S specification(); + + public abstract G generator(); + + public String tableName; + public S specification; + public G generator; + public String cql; + + public void prepare() { + this.specification = specification(); + this.generator = generator(); + this.cql = generateCql(); + } + + public String generateCql() { + return generator.toCql(); + } +} \ No newline at end of file diff --git a/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml b/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml index 4a603238c..4050ec523 100644 --- a/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml +++ b/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml @@ -7,7 +7,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + location="classpath:/org/springframework/data/cassandra/test/integration/config/cassandra.properties" />