DATACASS-33: WIP: renames, added first test for compound pk

This commit is contained in:
Matthew Adams
2014-01-13 14:23:10 -06:00
parent fb3b99ddba
commit 21049c2979
32 changed files with 248 additions and 99 deletions

View File

@@ -15,12 +15,15 @@
*/
package org.springframework.cassandra.core;
import java.util.Comparator;
/**
* Enum for Cassandra primary key column ordering.
* Enum for Cassandra primary key column ordering. Implements {@link Comparator} in that {@link Ordering#ASCENDING} is
* ordered before {@link Ordering#DESCENDING}.
*
* @author Matthew T. Adams
*/
public enum Ordering {
public enum Ordering implements Comparator<Ordering> {
/**
* Ascending Cassandra column ordering.
@@ -44,4 +47,18 @@ public enum Ordering {
public String cql() {
return cql;
}
@Override
public int compare(Ordering l, Ordering r) {
if (l == r) {
return 0;
}
if (l == null && r != null) {
return 1;
}
if (l != null && r == null) {
return -1;
}
return (l == ASCENDING && r == DESCENDING) ? 1 : -1;
}
}

View File

@@ -15,13 +15,16 @@
*/
package org.springframework.cassandra.core;
import java.util.Comparator;
/**
* Values representing primary key column types.
* Values representing primary key column types. Implements {@link Comparator} in that
* {@link PrimaryKeyType#PARTITIONED} is ordered before {@link PrimaryKeyType#CLUSTERED}.
*
* @author Matthew T. Adams
* @author Alex Shvid
*/
public enum PrimaryKeyType {
public enum PrimaryKeyType implements Comparator<PrimaryKeyType> {
/**
* Used for a column that is part of the partition key.
@@ -31,5 +34,19 @@ public enum PrimaryKeyType {
/**
* Used for a column that is clustered key.
*/
CLUSTERED
CLUSTERED;
@Override
public int compare(PrimaryKeyType l, PrimaryKeyType r) {
if (l == r) {
return 0;
}
if (l == null && r != null) {
return 1;
}
if (l != null && r == null) {
return -1;
}
return l == PARTITIONED && r == CLUSTERED ? 1 : -1;
}
}

View File

@@ -55,10 +55,7 @@ public class CassandraPropertyValueProvider implements PropertyValueProvider<Cas
this.evaluator = evaluator;
}
/*
* (non-Javadoc)
* @see org.springframework.data.convert.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
*/
@Override
@SuppressWarnings("unchecked")
public <T> T getPropertyValue(CassandraPersistentProperty property) {
@@ -75,10 +72,6 @@ public class CassandraPropertyValueProvider implements PropertyValueProvider<Cas
log.debug(columnType.getName().name());
/*
* Dave Webb - Added handler for text since getBytes was throwing
* InvalidTypeException when using getBytes on a text column.
*/
// TODO Might need to qualify all DataTypes as we encounter them.
if (columnType.equals(DataType.text())) {
return (T) source.getString(columnName);

View File

@@ -94,7 +94,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
throw new MappingException("No mapping metadata found for " + rawType.getName());
}
return readRowInternal(persistentEntity, row);
return readEntityFromRow(persistentEntity, row);
}
@Override
@@ -108,7 +108,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
this.spELContext = new SpELContext(this.spELContext, applicationContext);
}
protected <S extends Object> S readRowInternal(final CassandraPersistentEntity<S> entity, final Row row) {
protected <S extends Object> S readEntityFromRow(final CassandraPersistentEntity<S> entity, final Row row) {
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(row, spELContext);
@@ -290,7 +290,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
if (pkProp.isPartitionKeyColumn()) {
spec.partitionKeyColumn(pkProp.getColumnName(), pkProp.getDataType());
} else {
spec.clusteredKeyColumn(pkProp.getColumnName(), pkProp.getDataType(), pkProp.getOrdering());
spec.clusteredKeyColumn(pkProp.getColumnName(), pkProp.getDataType(), pkProp.getPrimaryKeyOrdering());
}
}

View File

@@ -1,6 +0,0 @@
package org.springframework.data.cassandra.core;
import org.springframework.core.convert.converter.Converter;
public interface ClassNameToTableNameConverter extends Converter<String, String> {
}

View File

@@ -1,6 +0,0 @@
package org.springframework.data.cassandra.core;
import org.springframework.core.convert.converter.Converter;
public interface ColumnNameToFieldNameConverter extends Converter<String, String> {
}

View File

@@ -1,6 +0,0 @@
package org.springframework.data.cassandra.core;
import org.springframework.core.convert.converter.Converter;
public interface FieldNameToColumnNameConverter extends Converter<String, String> {
}

View File

@@ -1,6 +0,0 @@
package org.springframework.data.cassandra.core;
import org.springframework.core.convert.converter.Converter;
public interface TableNameToClassNameConverter extends Converter<String, String> {
}

View File

@@ -51,7 +51,7 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
*/
public BasicCassandraPersistentEntity(TypeInformation<T> typeInformation) {
super(typeInformation, CassandraPersistentPropertyColumnNameComparator.INSTANCE);
super(typeInformation, DefaultCassandraPersistentPropertyColumnComparator.IT);
this.parser = new SpelExpressionParser();
this.context = new StandardEvaluationContext();
@@ -59,7 +59,7 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
Class<?> rawType = typeInformation.getType();
Table anno = rawType.getAnnotation(Table.class);
this.table = anno != null && StringUtils.hasText(anno.name()) ? anno.name() : CassandraNamingUtils
this.table = anno != null && StringUtils.hasText(anno.value()) ? anno.value() : CassandraNamingUtils
.getPreferredTableName(rawType);
}

View File

@@ -64,7 +64,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
@Override
public boolean isCompositePrimaryKey() {
return getField().getType().isAnnotationPresent(CompositePrimaryKey.class);
return getField().getType().isAnnotationPresent(PrimaryKeyClass.class);
}
@Override
@@ -85,6 +85,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
return (CassandraPersistentEntity<?>) ClassTypeInformation.from(getCompositePrimaryKeyType());
}
@Override
public String getColumnName() {
// first check @Column annotation
@@ -93,23 +94,25 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
return column.value();
}
// else check @KeyColumn annotation
// else check @PrimaryKeyColumn annotation
PrimaryKeyColumn pk = findAnnotation(PrimaryKeyColumn.class);
if (pk != null && StringUtils.hasText(pk.value())) {
return pk.value();
if (pk != null && StringUtils.hasText(pk.name())) {
return pk.name();
}
// else default
return field.getName().toLowerCase();
return field.getName().toLowerCase(); // TODO: replace with naming strategy class
}
public Ordering getOrdering() {
@Override
public Ordering getPrimaryKeyOrdering() {
PrimaryKeyColumn anno = findAnnotation(PrimaryKeyColumn.class);
return anno == null ? null : anno.ordering();
}
@Override
public DataType getDataType() {
CassandraType annotation = findAnnotation(CassandraType.class);
@@ -180,10 +183,12 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
}
}
@Override
public boolean isIndexed() {
return isAnnotationPresent(Indexed.class);
}
@Override
public boolean isPartitionKeyColumn() {
PrimaryKeyColumn anno = findAnnotation(PrimaryKeyColumn.class);

View File

@@ -97,10 +97,10 @@ public class CachingCassandraPersistentProperty extends BasicCassandraPersistent
}
@Override
public Ordering getOrdering() {
public Ordering getPrimaryKeyOrdering() {
if (!orderingCached) {
ordering = super.getOrdering();
ordering = super.getPrimaryKeyOrdering();
orderingCached = true;
}
return ordering;

View File

@@ -53,7 +53,7 @@ public interface CassandraPersistentProperty extends PersistentProperty<Cassandr
/**
* The ordering for the column. Valid only for clustered columns.
*/
Ordering getOrdering();
Ordering getPrimaryKeyOrdering();
/**
* The column's data type.

View File

@@ -48,7 +48,7 @@ import java.lang.annotation.Target;
public @interface Column {
/**
* The name of the column in the table.
* The name of the column in the table; must be a valid CQL identifier or quoted identifier.
*/
String value() default "";
}

View File

@@ -8,10 +8,14 @@ import java.util.Comparator;
* @author Alex Shvid
* @author Matthew T. Adams
*/
public enum CassandraPersistentPropertyColumnNameComparator implements Comparator<CassandraPersistentProperty> {
public enum DefaultCassandraPersistentPropertyColumnComparator implements Comparator<CassandraPersistentProperty> {
INSTANCE;
/**
* The sole instance of this class.
*/
IT;
@Override
public int compare(CassandraPersistentProperty o1, CassandraPersistentProperty o2) {
return o1.getColumnName().compareTo(o2.getColumnName());
}

View File

@@ -0,0 +1,49 @@
package org.springframework.data.cassandra.mapping;
import java.util.Comparator;
import org.springframework.cassandra.core.Ordering;
import org.springframework.cassandra.core.PrimaryKeyType;
/**
* {@link Comparator} implementation that uses, in order, the
* <ul>
* <li>{@link PrimaryKeyColumn#type()}, then, if ordered the same,</li>
* <li>{@link PrimaryKeyColumn#ordinal()}, then, if ordered the same</li>
* <li>{@link PrimaryKeyColumn#name()}, then, if ordered the same,</li>
* <li>{@link PrimaryKeyColumn#ordering()}.</li>
* </ul>
*
* @see PrimaryKeyType#compareTo(PrimaryKeyType)
* @see Ordering#compareTo(Ordering)
*
* @author Matthew T. Adams
*/
public enum DefaultCassandraPrimaryKeyColumnComparator implements Comparator<PrimaryKeyColumn> {
/**
* The sole instance of this class.
*/
IT;
@Override
public int compare(PrimaryKeyColumn o1, PrimaryKeyColumn o2) {
int comparison = o1.type().compareTo(o2.type());
if (comparison != 0) {
return comparison;
}
comparison = new Integer(o1.ordinal()).compareTo(o2.ordinal());
if (comparison != 0) {
return comparison;
}
comparison = o1.name().compareTo(o2.name());
if (comparison != 0) {
return comparison;
}
return o1.ordering().compareTo(o2.ordering());
}
}

View File

@@ -24,7 +24,11 @@ import org.springframework.data.annotation.Id;
/**
* Identifies the primary key field of the entity, which may be of a basic type or of a type that represents a composite
* primary key class. This field corresponds to the <code>PRIMARY KEY</code> of the corresponding Cassandra table.
* primary key class. This field corresponds to the <code>PRIMARY KEY</code> of the corresponding Cassandra table. Only
* one field in a given type hierarchy may be annotated with this annotation.
* <p/>
* Remember, if the Cassandra table has multiple primary key columns, then you must define a class annotated with
* {@link PrimaryKeyClass} to represent the primary key!
*
* @author Alex Shvid
* @author Matthew T. Adams

View File

@@ -22,7 +22,10 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Defines composite primary key class in the Cassandra table that contains several fields.
* Annotates a type that represents the identity type of another class whose instances are stored in a table.
* <p/>
* If your Cassandra table has multiple primary key columns, then you must define a primary key class, annotate it with
* this annotation, and use that class as the {@link PrimaryKey} of your entity class!
*
* @author Alex Shvid
* @author Matthew T. Adams
@@ -30,5 +33,5 @@ import java.lang.annotation.Target;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface CompositePrimaryKey {
public @interface PrimaryKeyClass {
}

View File

@@ -26,6 +26,8 @@ import org.springframework.cassandra.core.PrimaryKeyType;
/**
* Identifies the annotated field of a composite primary key class as a primary key field that is either a partition or
* cluster key field.
*
* @author Matthew T. Adams
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@@ -34,10 +36,10 @@ public @interface PrimaryKeyColumn {
/**
* The name of the column in the table.
*/
String value() default "";
String name() default "";
/**
* The order of this column among all primary key columns.
* The order of this column relative to other primary key columns.
*/
int ordinal();

View File

@@ -27,6 +27,7 @@ import org.springframework.data.annotation.Persistent;
* Identifies a domain object to be persisted to Cassandra as a table.
*
* @author Alex Shvid
* @author Matthew T. Adams
*/
@Persistent
@Inherited
@@ -34,6 +35,8 @@ import org.springframework.data.annotation.Persistent;
@Target({ ElementType.TYPE })
public @interface Table {
String name() default "";
/**
* The name of the table; must be a valid CQL identifier or quoted identifier.
*/
String value() default "";
}

View File

@@ -25,7 +25,6 @@ import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.thrift.transport.TTransportException;
import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -70,19 +69,19 @@ public class BasicCassandraPersistentEntityIntegrationTests {
}
@Test
public void collectionAllowsReferencingSpringBean() {
public void tableAllowsReferencingSpringBean() {
MappingBean bean = new MappingBean();
bean.userLine = "user_line";
TableNameHolderThingy bean = new TableNameHolderThingy();
bean.tableName = "my_user_line";
when(context.getBean("mappingBean")).thenReturn(bean);
when(context.containsBean("mappingBean")).thenReturn(true);
when(context.getBean("tableNameHolderThingy")).thenReturn(bean);
when(context.containsBean("tableNameHolderThingy")).thenReturn(true);
BasicCassandraPersistentEntity<UserLine> entity = new BasicCassandraPersistentEntity<UserLine>(
ClassTypeInformation.from(UserLine.class));
entity.setApplicationContext(context);
assertThat(entity.getTableName(), is("user_line"));
assertThat(entity.getTableName(), is(bean.tableName));
}
@After
@@ -90,36 +89,31 @@ public class BasicCassandraPersistentEntityIntegrationTests {
EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();
}
@AfterClass
public static void stopCassandra() {
EmbeddedCassandraServerHelper.stopEmbeddedCassandra();
}
@Table(name = "messages")
class Message {
@Table("messages")
static class Message {
}
class Notification extends Message {
static class Notification extends Message {
}
@Table(name = "#{123}")
class Area {
@Table("#{123}")
static class Area {
}
@Table(name = "#{mappingBean.userLine}")
class UserLine {
@Table("#{tableNameHolderThingy.tableName}")
static class UserLine {
}
class MappingBean {
static class TableNameHolderThingy {
String userLine;
String tableName;
public String getUserLine() {
return userLine;
public String getTableName() {
return tableName;
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.test.integration.mapping;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Field;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.cassandra.mapping.BasicCassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.BasicCassandraPersistentProperty;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.mapping.CassandraSimpleTypeHolder;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.util.ReflectionUtils;
/**
* Integration test for {@link BasicCassandraPersistentProperty}.
*
* @author Alex Shvid
*/
public class CompoundPrimaryKeyIntegrationTests {
@PrimaryKeyClass
static class TimelineKey {
@PrimaryKeyColumn(ordinal = 0)
String id;
@PrimaryKeyColumn(ordinal = 1)
Date dt;
}
static class Timeline {
@PrimaryKey
TimelineKey id;
@Column("message")
String text;
}
CassandraPersistentEntity<Timeline> entity;
@Before
public void setup() {
entity = new BasicCassandraPersistentEntity<Timeline>(ClassTypeInformation.from(Timeline.class));
}
@Test
public void checksIdProperty() {
Field field = ReflectionUtils.findField(Timeline.class, "id");
CassandraPersistentProperty property = getPropertyFor(field);
assertTrue(property.isIdProperty());
}
private CassandraPersistentProperty getPropertyFor(Field field) {
return new BasicCassandraPersistentProperty(field, null, entity, new CassandraSimpleTypeHolder());
}
}

View File

@@ -24,7 +24,7 @@ import org.springframework.data.cassandra.mapping.Table;
* @author David Webb
*
*/
@Table(name = "book")
@Table("book")
public class Book {
@PrimaryKey
@@ -93,6 +93,7 @@ public class Book {
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("isbn -> " + isbn).append("\n");

View File

@@ -30,7 +30,7 @@ import com.datastax.driver.core.DataType;
*
* @author Alex Shvid
*/
@Table(name = "comments")
@Table("comments")
public class Comment {
/*

View File

@@ -18,7 +18,7 @@ package org.springframework.data.cassandra.test.integration.table;
import java.util.Date;
import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.CompositePrimaryKey;
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.mapping.CassandraType;
@@ -30,7 +30,7 @@ import com.datastax.driver.core.DataType;
* @author Alex Shvid
*/
@CompositePrimaryKey
@PrimaryKeyClass
public class CommentPK {
/*

View File

@@ -26,7 +26,7 @@ import org.springframework.data.cassandra.mapping.Table;
*
* @author Alex Shvid
*/
@Table(name = "log_entry")
@Table("log_entry")
public class LogEntry {
/*

View File

@@ -29,7 +29,7 @@ import org.springframework.data.cassandra.mapping.Table;
*
* @author Alex Shvid
*/
@Table(name = "notifications")
@Table("notifications")
public class Notification {
/*

View File

@@ -18,7 +18,7 @@ package org.springframework.data.cassandra.test.integration.table;
import java.util.Date;
import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.CompositePrimaryKey;
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.mapping.CassandraType;
@@ -32,7 +32,7 @@ import com.datastax.driver.core.DataType;
*
* @author Alex Shvid
*/
@CompositePrimaryKey
@PrimaryKeyClass
public class NotificationPK {
/*

View File

@@ -31,7 +31,7 @@ import org.springframework.data.cassandra.mapping.Table;
*
* @author Alex Shvid
*/
@Table(name = "posts")
@Table("posts")
public class Post {
/*

View File

@@ -18,7 +18,7 @@ package org.springframework.data.cassandra.test.integration.table;
import java.util.Date;
import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.CompositePrimaryKey;
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
/**
@@ -31,7 +31,7 @@ import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
* @author Alex Shvid
*/
@CompositePrimaryKey
@PrimaryKeyClass
public class PostPK {
/*

View File

@@ -29,7 +29,7 @@ import org.springframework.data.cassandra.mapping.Table;
*
* @author Alex Shvid
*/
@Table(name = "timeline")
@Table("timeline")
public class Timeline {
/*

View File

@@ -18,7 +18,7 @@ package org.springframework.data.cassandra.test.integration.table;
import java.util.Date;
import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.CompositePrimaryKey;
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
/**
@@ -31,7 +31,7 @@ import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
* @author Alex Shvid
*/
@CompositePrimaryKey
@PrimaryKeyClass
public class TimelinePK {
/*

View File

@@ -30,7 +30,7 @@ import org.springframework.data.cassandra.mapping.Table;
*
* @author Alex Shvid
*/
@Table(name = "users")
@Table("users")
public class User {
/*