From 3d51fc150f376ab6362b990e38d5705b3a8127c9 Mon Sep 17 00:00:00 2001 From: john-mcpeek Date: Sat, 14 Dec 2013 13:17:27 -0500 Subject: [PATCH] Added CqlGenerators for Keyspace. --- .../generator/AlterKeyspaceCqlGenerator.java | 121 +++++++++++ .../generator/CreateKeyspaceCqlGenerator.java | 201 ++++++++++++++++++ .../generator/DropKeyspaceCqlGenerator.java | 37 ++++ .../cql/generator/KeyspaceCqlGenerator.java | 80 +++++++ .../generator/KeyspaceNameCqlGenerator.java | 51 +++++ .../KeyspaceOptionsCqlGenerator.java | 80 +++++++ 6 files changed, 570 insertions(+) create mode 100644 spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/AlterKeyspaceCqlGenerator.java create mode 100644 spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/CreateKeyspaceCqlGenerator.java create mode 100644 spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/DropKeyspaceCqlGenerator.java create mode 100644 spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceCqlGenerator.java create mode 100644 spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceNameCqlGenerator.java create mode 100644 spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceOptionsCqlGenerator.java diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/AlterKeyspaceCqlGenerator.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/AlterKeyspaceCqlGenerator.java new file mode 100644 index 000000000..beb0c08da --- /dev/null +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/AlterKeyspaceCqlGenerator.java @@ -0,0 +1,121 @@ +/* + * Copyright 2011-2013 the original author or authors. + * + * 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 org.springframework.cassandra.core.cql.generator; + +import static org.springframework.cassandra.core.cql.CqlStringUtils.noNull; + +import java.util.Map; + +import org.springframework.cassandra.core.keyspace.AddColumnSpecification; +import org.springframework.cassandra.core.keyspace.AlterColumnSpecification; +import org.springframework.cassandra.core.keyspace.AlterKeyspaceSpecification; +import org.springframework.cassandra.core.keyspace.ColumnChangeSpecification; +import org.springframework.cassandra.core.keyspace.DropColumnSpecification; +import org.springframework.cassandra.core.keyspace.Option; + +/** + * CQL generator for generating ALTER TABLE statements. + * + * @author Matthew T. Adams + */ +public class AlterKeyspaceCqlGenerator extends KeyspaceOptionsCqlGenerator { + + public AlterKeyspaceCqlGenerator(AlterKeyspaceSpecification specification) { + super(specification); + } + + public StringBuilder toCql(StringBuilder cql) { + cql = noNull(cql); + + preambleCql(cql); +// changesCql(cql); +// optionsCql(cql); + + cql.append(";"); + + return cql; + } + + protected StringBuilder preambleCql(StringBuilder cql) { + return noNull(cql).append("ALTER KEYSPACE ").append(spec().getNameAsIdentifier()).append(" "); + } + +// protected StringBuilder changesCql(StringBuilder cql) { +// cql = noNull(cql); +// +// boolean first = true; +// for (ColumnChangeSpecification change : spec().getChanges()) { +// if (first) { +// first = false; +// } else { +// cql.append(" "); +// } +// getCqlGeneratorFor(change).toCql(cql); +// } +// +// return cql; +// } +// +// protected ColumnChangeCqlGenerator getCqlGeneratorFor(ColumnChangeSpecification change) { +// if (change instanceof AddColumnSpecification) { +// return new AddColumnCqlGenerator((AddColumnSpecification) change); +// } +// if (change instanceof DropColumnSpecification) { +// return new DropColumnCqlGenerator((DropColumnSpecification) change); +// } +// if (change instanceof AlterColumnSpecification) { +// return new AlterColumnCqlGenerator((AlterColumnSpecification) change); +// } +// throw new IllegalArgumentException("unknown ColumnChangeSpecification type: " + change.getClass().getName()); +// } +// +// @SuppressWarnings("unchecked") +// protected StringBuilder optionsCql(StringBuilder cql) { +// cql = noNull(cql); +// +// Map options = spec().getOptions(); +// if (options == null || options.isEmpty()) { +// return cql; +// } +// +// cql.append(" WITH "); +// boolean first = true; +// for (String key : options.keySet()) { +// if (first) { +// first = false; +// } else { +// cql.append(" AND "); +// } +// +// cql.append(key); +// +// Object value = options.get(key); +// if (value == null) { +// continue; +// } +// cql.append(" = "); +// +// if (value instanceof Map) { +// optionValueMap((Map) value, cql); +// continue; +// } +// +// // else just use value as string +// cql.append(value.toString()); +// } +// return cql; +// } +} diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/CreateKeyspaceCqlGenerator.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/CreateKeyspaceCqlGenerator.java new file mode 100644 index 000000000..66a999f62 --- /dev/null +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/CreateKeyspaceCqlGenerator.java @@ -0,0 +1,201 @@ +/* + * Copyright 2011-2013 the original author or authors. + * + * 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 org.springframework.cassandra.core.cql.generator; + +import static org.springframework.cassandra.core.PrimaryKeyType.CLUSTERED; +import static org.springframework.cassandra.core.PrimaryKeyType.PARTITIONED; +import static org.springframework.cassandra.core.cql.CqlStringUtils.noNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.springframework.cassandra.core.keyspace.ColumnSpecification; +import org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification; +import org.springframework.cassandra.core.keyspace.Option; + +/** + * CQL generator for generating a CREATE TABLE statement. + * + * @author Matthew T. Adams + * @author Alex Shvid + */ +public class CreateKeyspaceCqlGenerator extends KeyspaceCqlGenerator { + + public CreateKeyspaceCqlGenerator(CreateKeyspaceSpecification specification) { + super(specification); + } + + public StringBuilder toCql(StringBuilder cql) { + + cql = noNull(cql); + + preambleCql(cql); + optionsCql(cql); + + cql.append(";"); + + return cql; + } + + protected StringBuilder preambleCql(StringBuilder cql) { + return noNull(cql).append("CREATE KEYSPACE ").append(spec().getIfNotExists() ? "IF NOT EXISTS " : "") + .append(spec().getNameAsIdentifier()); + } + + protected void optionsCql(StringBuilder cql) { + cql = noNull(cql); + + cql.append("WITH REPLICATION ="); + } + + +// @SuppressWarnings("unchecked") +// protected StringBuilder columnsAndOptionsCql(StringBuilder cql) { +// +// cql = noNull(cql); +// +// // begin columns +// cql.append(" ("); +// +// List partitionKeys = new ArrayList(); +// List clusterKeys = new ArrayList(); +// for (ColumnSpecification col : spec().getColumns()) { +// col.toCql(cql).append(", "); +// +// if (col.getKeyType() == PARTITIONED) { +// partitionKeys.add(col); +// } else if (col.getKeyType() == CLUSTERED) { +// clusterKeys.add(col); +// } +// } +// +// // begin primary key clause +// cql.append("PRIMARY KEY ("); +// +// if (partitionKeys.size() > 1) { +// // begin partition key clause +// cql.append("("); +// } +// +// appendColumnNames(cql, partitionKeys); +// +// if (partitionKeys.size() > 1) { +// cql.append(")"); +// // end partition key clause +// } +// +// if (!clusterKeys.isEmpty()) { +// cql.append(", "); +// } +// +// appendColumnNames(cql, clusterKeys); +// +// cql.append(")"); +// // end primary key clause +// +// cql.append(")"); +// // end columns +// +// StringBuilder ordering = createOrderingClause(clusterKeys); +// // begin options +// // begin option clause +// Map options = spec().getOptions(); +// +// if (ordering != null || !options.isEmpty()) { +// +// // option preamble +// boolean first = true; +// cql.append(" WITH "); +// // end option preamble +// +// if (ordering != null) { +// cql.append(ordering); +// first = false; +// } +// if (!options.isEmpty()) { +// for (String name : options.keySet()) { +// // append AND if we're not on first option +// if (first) { +// first = false; +// } else { +// cql.append(" AND "); +// } +// +// // append = +// cql.append(name); +// +// Object value = options.get(name); +// if (value == null) { // then assume string-only, valueless option like "COMPACT STORAGE" +// continue; +// } +// +// cql.append(" = "); +// +// if (value instanceof Map) { +// optionValueMap((Map) value, cql); +// continue; // end non-empty value map +// } +// +// // else just use value as string +// cql.append(value.toString()); +// } +// } +// } +// // end options +// +// return cql; +// } + +// private static StringBuilder createOrderingClause(List columns) { +// StringBuilder ordering = null; +// boolean first = true; +// for (ColumnSpecification col : columns) { +// +// if (col.getOrdering() != null) { // then ordering specified +// if (ordering == null) { // then initialize ordering clause +// ordering = new StringBuilder().append("CLUSTERING ORDER BY ("); +// } +// if (first) { +// first = false; +// } else { +// ordering.append(", "); +// } +// ordering.append(col.getName()).append(" ").append(col.getOrdering().cql()); +// } +// } +// if (ordering != null) { // then end ordering option +// ordering.append(")"); +// } +// return ordering; +// } +// +// private static void appendColumnNames(StringBuilder str, List columns) { +// +// boolean first = true; +// for (ColumnSpecification col : columns) { +// if (first) { +// first = false; +// } else { +// str.append(", "); +// } +// str.append(col.getName()); +// +// } +// +// } + +} diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/DropKeyspaceCqlGenerator.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/DropKeyspaceCqlGenerator.java new file mode 100644 index 000000000..63382bd88 --- /dev/null +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/DropKeyspaceCqlGenerator.java @@ -0,0 +1,37 @@ +/* + * Copyright 2011-2013 the original author or authors. + * + * 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 org.springframework.cassandra.core.cql.generator; + +import static org.springframework.cassandra.core.cql.CqlStringUtils.noNull; + +import org.springframework.cassandra.core.keyspace.DropKeyspaceSpecification; + +/** + * CQL generator for generating a DROP TABLE statement. + * + * @author Matthew T. Adams + */ +public class DropKeyspaceCqlGenerator extends KeyspaceNameCqlGenerator { + + public DropKeyspaceCqlGenerator(DropKeyspaceSpecification specification) { + super(specification); + } + + public StringBuilder toCql(StringBuilder cql) { + return noNull(cql).append("DROP KEYSPACE ").append(spec().getIfExists() ? "IF EXISTS " : "") + .append(spec().getNameAsIdentifier()).append(";"); + } +} diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceCqlGenerator.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceCqlGenerator.java new file mode 100644 index 000000000..32f504fb3 --- /dev/null +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceCqlGenerator.java @@ -0,0 +1,80 @@ +/* + * Copyright 2011-2013 the original author or authors. + * + * 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 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.KeyspaceSpecification; +import org.springframework.cassandra.core.keyspace.Option; + +/** + * 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 KeyspaceCqlGenerator> extends + KeyspaceOptionsCqlGenerator> { + + public KeyspaceCqlGenerator(KeyspaceSpecification 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/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceNameCqlGenerator.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceNameCqlGenerator.java new file mode 100644 index 000000000..fbaa6b7dc --- /dev/null +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceNameCqlGenerator.java @@ -0,0 +1,51 @@ +/* + * Copyright 2011-2013 the original author or authors. + * + * 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 org.springframework.cassandra.core.cql.generator; + +import org.springframework.cassandra.core.keyspace.KeyspaceNameSpecification; +import org.springframework.util.Assert; + +public abstract class KeyspaceNameCqlGenerator> { + + public abstract StringBuilder toCql(StringBuilder cql); + + private KeyspaceNameSpecification specification; + + public KeyspaceNameCqlGenerator(KeyspaceNameSpecification specification) { + setSpecification(specification); + } + + protected void setSpecification(KeyspaceNameSpecification 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/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceOptionsCqlGenerator.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceOptionsCqlGenerator.java new file mode 100644 index 000000000..8078ebf4c --- /dev/null +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/cql/generator/KeyspaceOptionsCqlGenerator.java @@ -0,0 +1,80 @@ +/* + * Copyright 2011-2013 the original author or authors. + * + * 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 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.KeyspaceOptionsSpecification; +import org.springframework.cassandra.core.keyspace.Option; + +/** + * 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 KeyspaceOptionsCqlGenerator> extends + KeyspaceNameCqlGenerator> { + + public KeyspaceOptionsCqlGenerator(KeyspaceOptionsSpecification 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; + } +}