DATACASS-172 - Add CQL specifications/generators and UserDefinedType annotation.

This commit is contained in:
Fabio Mendes
2016-09-06 08:08:11 +02:00
committed by John Blum
parent 3c80b2cb80
commit ac868d2f0a
12 changed files with 709 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2013-2014 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.AddColumnSpecification;
import org.springframework.cassandra.core.keyspace.AlterColumnSpecification;
import org.springframework.cassandra.core.keyspace.AlterUserTypeSpecification;
import org.springframework.cassandra.core.keyspace.ColumnChangeSpecification;
import org.springframework.cassandra.core.keyspace.DropColumnSpecification;
/**
* CQL generator for generating <code>ALTER TYPE</code> statements.
*
* @author Fabio J. Mendes
*/
public class AlterUserTypeCqlGenerator extends UserTypeCqlGenerator<AlterUserTypeSpecification> {
public static String toCql(AlterUserTypeSpecification specification) {
return new AlterUserTypeCqlGenerator(specification).toCql();
}
public AlterUserTypeCqlGenerator(AlterUserTypeSpecification specification) {
super(specification);
}
@Override
public StringBuilder toCql(StringBuilder cql) {
cql = noNull(cql);
preambleCql(cql);
changesCql(cql);
cql.append(";");
return cql;
}
protected StringBuilder preambleCql(StringBuilder cql) {
return noNull(cql).append("ALTER TYPE ").append(spec().getName()).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());
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2013-2014 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.ColumnSpecification;
import org.springframework.cassandra.core.keyspace.CreateUserTypeSpecification;
/**
* CQL generator for generating a <code>CREATE TYPE</code> statement.
*
* @author Fabio J. Mendes
*/
public class CreateUserTypeCqlGenerator extends UserTypeCqlGenerator<CreateUserTypeSpecification> {
public static String toCql(CreateUserTypeSpecification specification) {
return new CreateUserTypeCqlGenerator(specification).toCql();
}
public CreateUserTypeCqlGenerator(CreateUserTypeSpecification specification) {
super(specification);
}
@Override
public StringBuilder toCql(StringBuilder cql) {
cql = noNull(cql);
preambleCql(cql);
columns(cql);
cql.append(";");
return cql;
}
protected StringBuilder preambleCql(StringBuilder cql) {
return noNull(cql).append("CREATE TYPE ").append(spec().getIfNotExists() ? "IF NOT EXISTS " : "")
.append(spec().getName());
}
protected StringBuilder columns(StringBuilder cql) {
cql = noNull(cql);
// begin columns
cql.append(" (");
for (ColumnSpecification col : spec().getColumns()) {
col.toCql(cql).append(", ");
}
cql.delete(cql.length() - 2, cql.length());
cql.append(")");
// end columns
return cql;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2013-2014 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.DropUserTypeSpecification;
/**
* CQL generator for generating a <code>DROP TYPE</code> statement.
*
* @author Fabio J. Mendes
*/
public class DropUserTypeCqlGenerator extends UserTypeNameCqlGenerator<DropUserTypeSpecification> {
public static String toCql(DropUserTypeSpecification specification) {
return new DropUserTypeCqlGenerator(specification).toCql();
}
public DropUserTypeCqlGenerator(DropUserTypeSpecification specification) {
super(specification);
}
@Override
public StringBuilder toCql(StringBuilder cql) {
return noNull(cql).append("DROP TYPE ")
// .append(spec().getIfExists() ? "IF EXISTS " : "")
.append(spec().getName()).append(";");
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2013-2014 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.UserTypeNameSpecification;
import org.springframework.util.Assert;
/**
* @author Fabio J. Mendes
*
* @param <T>
*/
public abstract class UserTypeNameCqlGenerator<T extends UserTypeNameSpecification<T>> {
public abstract StringBuilder toCql(StringBuilder cql);
private UserTypeNameSpecification<T> specification;
public UserTypeNameCqlGenerator(UserTypeNameSpecification<T> specification) {
setSpecification(specification);
}
protected void setSpecification(UserTypeNameSpecification<T> 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();
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2013-2014 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.keyspace;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.cassandra.core.cql.CqlIdentifier;
import com.datastax.driver.core.DataType;
/**
* Builder class to construct an <code>ALTER TYPE</code> specification.
*
* @author Fabio J. Mendes
*/
public class AlterUserTypeSpecification extends UserTypeSpecification<AlterUserTypeSpecification> {
/**
* Entry point into the {@link AlterUserTypeSpecification}'s fluent API to alter a type. Convenient if imported
* statically.
*/
public static AlterUserTypeSpecification alterType() {
return new AlterUserTypeSpecification();
}
/**
* Entry point into the {@link AlterUserTypeSpecification}'s fluent API to alter a type. Convenient if imported
* statically.
*/
public static AlterUserTypeSpecification alterType(CqlIdentifier tableName) {
return (AlterUserTypeSpecification) new AlterUserTypeSpecification().name(tableName);
}
/**
* Entry point into the {@link AlterUserTypeSpecification}'s fluent API to alter a type. Convenient if imported
* statically.
*/
public static AlterUserTypeSpecification alterType(String tableName) {
return (AlterUserTypeSpecification) new AlterUserTypeSpecification().name(tableName);
}
@Override
public AlterUserTypeSpecification name(String name) {
return (AlterUserTypeSpecification) super.name(name);
}
/**
* The list of column changes.
*/
private List<ColumnChangeSpecification> changes = new ArrayList<ColumnChangeSpecification>();
/*
* Adds a <code>DROP</code> to the list of column changes.
*
* DW Removed as this only works in C* 2.0
*/
// public AlterUserTypeSpecification drop(String column) {
// changes.add(new DropColumnSpecification(column));
// return this;
// }
/**
* Adds an <code>ADD</code> to the list of column changes.
*/
public AlterUserTypeSpecification add(String column, DataType type) {
changes.add(new AddColumnSpecification(column, type));
return this;
}
/**
* Adds an <code>ALTER</code> to the list of column changes.
*/
public AlterUserTypeSpecification alter(String column, DataType type) {
changes.add(new AlterColumnSpecification(column, type));
return this;
}
/**
* Returns an unmodifiable list of column changes.
*/
public List<ColumnChangeSpecification> getChanges() {
return Collections.unmodifiableList(changes);
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2013-2014 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.keyspace;
import org.springframework.cassandra.core.cql.CqlIdentifier;
/**
* Builder class to construct a <code>CREATE TYPE</code> specification.
*
* @author Fabio J. Mendes
*/
public class CreateUserTypeSpecification extends UserTypeSpecification<CreateUserTypeSpecification> {
/**
* Entry point into the {@link CreateUserTypeSpecification}'s fluent API to create a type. Convenient if imported
* statically.
*/
public static CreateUserTypeSpecification createType() {
return new CreateUserTypeSpecification();
}
/**
* Entry point into the {@link CreateUserTypeSpecification}'s fluent API to create a type. Convenient if imported
* statically.
*/
public static CreateUserTypeSpecification createType(CqlIdentifier name) {
return new CreateUserTypeSpecification().name(name);
}
/**
* Entry point into the {@link CreateUserTypeSpecification}'s fluent API to create a type. Convenient if imported
* statically.
*/
public static CreateUserTypeSpecification createType(String name) {
return new CreateUserTypeSpecification().name(name);
}
private boolean ifNotExists = false;
@Override
public CreateUserTypeSpecification name(CqlIdentifier name) {
return (CreateUserTypeSpecification) super.name(name);
}
/**
* Causes the inclusion of an <code>IF NOT EXISTS</code> clause.
*
* @return this
*/
public CreateUserTypeSpecification ifNotExists() {
return ifNotExists(true);
}
/**
* Toggles the inclusion of an <code>IF NOT EXISTS</code> clause.
*
* @return this
*/
public CreateUserTypeSpecification ifNotExists(boolean ifNotExists) {
this.ifNotExists = ifNotExists;
return this;
}
public boolean getIfNotExists() {
return ifNotExists;
}
@Override
public CreateUserTypeSpecification name(String name) {
return (CreateUserTypeSpecification) super.name(name);
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2013-2014 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.keyspace;
import org.springframework.cassandra.core.cql.CqlIdentifier;
/**
* Builder class that supports the construction of <code>DROP TYPE</code> specifications.
*
* @author Fabio J. Mendes
*/
public class DropUserTypeSpecification extends UserTypeNameSpecification<DropUserTypeSpecification> {
// private boolean ifExists;
// Added in Cassandra 2.0.
// public DropTableSpecification ifExists() {
// return ifExists(true);
// }
//
// public DropTableSpecification ifExists(boolean ifExists) {
// this.ifExists = ifExists;
// return this;
// }
//
// public boolean getIfExists() {
// return ifExists;
// }
/**
* Entry point into the {@link DropUserTypeSpecification}'s fluent API to drop a type. Convenient if imported
* statically.
*/
public static DropUserTypeSpecification dropType() {
return new DropUserTypeSpecification();
}
/**
* Entry point into the {@link DropUserTypeSpecification}'s fluent API to drop a type. Convenient if imported
* statically. This static method is shorter than the no-arg form, which would be
* <code>dropType().name(typeName)</code>.
*
* @param typeName The name of the type to drop.
*/
public static DropUserTypeSpecification dropType(CqlIdentifier typeName) {
return new DropUserTypeSpecification().name(typeName);
}
/**
* Entry point into the {@link DropUserTypeSpecification}'s fluent API to drop a type. Convenient if imported
* statically. This static method is shorter than the no-arg form, which would be
* <code>dropType().name(typeName)</code>.
*
* @param typeName The name of the type to drop.
*/
public static DropUserTypeSpecification dropType(String typeName) {
return new DropUserTypeSpecification().name(typeName);
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2013-2014 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.keyspace;
import static org.springframework.cassandra.core.cql.CqlIdentifier.cqlId;
import org.springframework.cassandra.core.cql.CqlIdentifier;
import org.springframework.util.Assert;
/**
* Abstract builder class to support the construction of user type specifications.
*
* @author Fabio J. Mendes
* @param <T> The subtype of the {@link UserTypeNameSpecification}
*/
public abstract class UserTypeNameSpecification<T extends UserTypeNameSpecification<T>> {
/**
* The name of the type.
*/
private CqlIdentifier name;
/**
* Sets the type name.
*
* @return this
*/
public T name(String name) {
return name(cqlId(name));
}
@SuppressWarnings("unchecked")
public T name(CqlIdentifier name) {
Assert.notNull(name);
this.name = name;
return (T) this;
}
public CqlIdentifier getName() {
return name;
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2013-2014 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.keyspace;
import static org.springframework.cassandra.core.cql.CqlIdentifier.cqlId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.cassandra.core.cql.CqlIdentifier;
import com.datastax.driver.core.DataType;
/**
* Builder class to support the construction of user type specifications that have columns. This class can also be used as a
* standalone {@link UserTypeDescriptor}, independent of {@link CreateUserTypeSpecification}.
*
* @author Fabio J. Mendes
*/
public class UserTypeSpecification<T> extends UserTypeNameSpecification<UserTypeSpecification<T>> implements UserTypeDescriptor {
/**
* List of all columns.
*/
private List<ColumnSpecification> columns = new ArrayList<ColumnSpecification>();
/**
* Adds the given column to the type.
*
* @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(cqlId(name), type, false);
}
/**
* Adds the given column to the type.
*
* @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(CqlIdentifier name, DataType type) {
return column(name, type, false);
}
@SuppressWarnings("unchecked")
protected T column(CqlIdentifier name, DataType type, boolean frozen) {
ColumnSpecification column = new ColumnSpecification().name(name).type(type);
columns.add(column);
return (T) this;
}
/**
* Returns an unmodifiable list of all columns.
*/
@Override
public List<ColumnSpecification> getColumns() {
return Collections.unmodifiableList(columns);
}
}

View File

@@ -20,6 +20,7 @@ import java.util.Map;
import org.springframework.cassandra.core.cql.CqlIdentifier;
import com.datastax.driver.core.TableMetadata;
import com.datastax.driver.core.UserType;
/**
* Operations for managing a Cassandra keyspace.
@@ -77,4 +78,11 @@ public interface CassandraAdminOperations extends CassandraOperations {
* @return
*/
TableMetadata getTableMetadata(String keyspace, CqlIdentifier tableName);
/**
* @param keyspace
* @param userTypeName
* @return
*/
UserType getUserTypeMetadata(String keyspace, CqlIdentifier userTypeName);
}

View File

@@ -32,6 +32,7 @@ import org.springframework.util.Assert;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.TableMetadata;
import com.datastax.driver.core.UserType;
/**
* Default implementation of {@link CassandraAdminOperations}.
@@ -139,4 +140,17 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
}
});
}
@Override
public UserType getUserTypeMetadata(final String keyspace, final CqlIdentifier userTypeName) {
Assert.notNull(userTypeName);
return execute(new SessionCallback<UserType>() {
@Override
public UserType doInSession(Session s) {
return s.getCluster().getMetadata().getKeyspace(keyspace).getUserType(userTypeName.toCql());
}
});
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2016 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.data.cassandra.mapping;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Fabio J. Mendes
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface UserDefinedType {
/**
* The name of the UDT; must be a valid CQL identifier or quoted identifier.
*/
String value() default "";
/**
* Whether to cause the UDT name to be force-quoted.
*/
boolean forceQuote() default false;
}