diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractCassandraConfiguration.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractCassandraConfiguration.java index 0009d0010..c8cc1b262 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractCassandraConfiguration.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/AbstractCassandraConfiguration.java @@ -22,7 +22,6 @@ import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.cassandra.core.CassandraOperations; import org.springframework.cassandra.core.CassandraTemplate; -import org.springframework.data.cassandra.core.SpringDataKeyspace; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.Configuration; @@ -32,6 +31,7 @@ import org.springframework.data.cassandra.convert.CassandraConverter; import org.springframework.data.cassandra.convert.MappingCassandraConverter; import org.springframework.data.cassandra.core.CassandraAdminOperations; import org.springframework.data.cassandra.core.CassandraAdminTemplate; +import org.springframework.data.cassandra.core.SpringDataKeyspace; import org.springframework.data.cassandra.mapping.CassandraMappingContext; import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; import org.springframework.data.cassandra.mapping.CassandraPersistentProperty; @@ -74,8 +74,8 @@ public abstract class AbstractCassandraConfiguration implements BeanClassLoaderA public abstract Cluster cluster() throws Exception; /** - * Creates a {@link Session} to be used by the {@link SpringDataKeyspace}. Will use the {@link Cluster} instance configured in - * {@link #cluster()}. + * Creates a {@link Session} to be used by the {@link SpringDataKeyspace}. Will use the {@link Cluster} instance + * configured in {@link #cluster()}. * * @see #cluster() * @see #Keyspace() @@ -93,8 +93,8 @@ public abstract class AbstractCassandraConfiguration implements BeanClassLoaderA } /** - * Creates a {@link SpringDataKeyspace} to be used by the {@link CassandraTemplate}. Will use the {@link Session} instance - * configured in {@link #session()} and {@link CassandraConverter} configured in {@link #converter()}. + * Creates a {@link SpringDataKeyspace} to be used by the {@link CassandraTemplate}. Will use the {@link Session} + * instance configured in {@link #session()} and {@link CassandraConverter} configured in {@link #converter()}. * * @see #cluster() * @see #Keyspace() diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java index ad530226f..eff4dd3d1 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java @@ -83,7 +83,7 @@ public class CassandraAdminTemplate implements CassandraAdminOperations { execute(new SessionCallback() { public Object doInSession(Session s) throws DataAccessException { - String cql = CqlUtils.createTable(tableName, entity); + String cql = CqlUtils.createTable(tableName, entity, mappingContext); log.info("CREATE TABLE CQL -> " + cql); s.execute(cql); return null; diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java index 36aae8114..9444b8772 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraKeyspaceFactoryBean.java @@ -24,7 +24,6 @@ import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; -import org.springframework.data.cassandra.core.SpringDataKeyspace; import org.springframework.cassandra.support.CassandraExceptionTranslator; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -250,7 +249,7 @@ public class CassandraKeyspaceFactoryBean implements FactoryBean entity) throws NoHostAvailableException { - String cql = CqlUtils.createTable(useTableName, entity); + String cql = CqlUtils.createTable(useTableName, entity, mappingContext); log.info("Execute on keyspace " + keyspace + " CQL " + cql); session.execute(cql); for (String indexCQL : CqlUtils.createIndexes(useTableName, entity)) { diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java index bfaa039bb..030be69c6 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java @@ -104,14 +104,6 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity fieldType = getField().getType(); + return fieldType.isAnnotationPresent(CompositePrimaryKey.class); } /** @@ -146,7 +148,16 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP * @return */ public boolean isIndexed() { - return getField().isAnnotationPresent(Index.class); + return getField().isAnnotationPresent(Indexed.class); + } + + /** + * Returns true if the property has Partitioned annotation on this column. + * + * @return + */ + public boolean isPartitioned() { + return getField().isAnnotationPresent(Partitioned.class); } /* diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CachingCassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CachingCassandraPersistentProperty.java index 0e59b5318..3ab27429a 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CachingCassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CachingCassandraPersistentProperty.java @@ -28,9 +28,9 @@ import org.springframework.data.mapping.model.SimpleTypeHolder; public class CachingCassandraPersistentProperty extends BasicCassandraPersistentProperty { private Boolean isIdProperty; - private Boolean isColumnId; private String columnName; private Boolean isIndexed; + private Boolean isPartitioned; /** * Creates a new {@link CachingCassandraPersistentProperty}. @@ -59,20 +59,6 @@ public class CachingCassandraPersistentProperty extends BasicCassandraPersistent return this.isIdProperty; } - /* - * (non-Javadoc) - * @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#isColumnId() - */ - @Override - public boolean isColumnId() { - - if (this.isColumnId == null) { - this.isColumnId = super.isColumnId(); - } - - return this.isColumnId; - } - /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#getFieldName() @@ -100,4 +86,19 @@ public class CachingCassandraPersistentProperty extends BasicCassandraPersistent return this.isIndexed; } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#isPartitioned() + */ + @Override + public boolean isPartitioned() { + + if (this.isPartitioned == null) { + this.isPartitioned = super.isPartitioned(); + } + + return this.isPartitioned; + } + } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java index cdb98d38b..f1460ed86 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentProperty.java @@ -27,11 +27,11 @@ import com.datastax.driver.core.DataType; public interface CassandraPersistentProperty extends PersistentProperty { /** - * For dynamic tables returns true if property value is used as column name. + * Returns the true if the field composite primary key. * * @return */ - boolean isColumnId(); + boolean isCompositePrimaryKey(); /** * Returns the name of the field a property is persisted to. @@ -54,4 +54,11 @@ public interface CassandraPersistentProperty extends PersistentProperty extends CrudRepository { + List findByPartitionKey(ID id); + } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepository.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepository.java index 385a768ed..8bc527e4e 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepository.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/SimpleCassandraRepository.java @@ -108,6 +108,20 @@ public class SimpleCassandraRepository implements Ca return cassandraDataTemplate.selectOne(select, entityInformation.getJavaType()); } + /* + * (non-Javadoc) + * @see org.springframework.data.cassandra.repository.CassandraRepository#findByPartitionKey(java.io.Serializable) + */ + @Override + public List findByPartitionKey(ID id) { + Assert.notNull(id, "The given id must not be null!"); + + Select select = QueryBuilder.select().all().from(entityInformation.getTableName()); + select.where(getIdClause(id)); + + return cassandraDataTemplate.select(select, entityInformation.getJavaType()); + } + /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#exists(java.io.Serializable) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java index c219fd2ed..8630a2d42 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/util/CqlUtils.java @@ -17,6 +17,7 @@ import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; import org.springframework.data.cassandra.mapping.CassandraPersistentProperty; import org.springframework.data.convert.EntityWriter; import org.springframework.data.mapping.PropertyHandler; +import org.springframework.data.mapping.context.MappingContext; import com.datastax.driver.core.ColumnMetadata; import com.datastax.driver.core.DataType; @@ -48,66 +49,95 @@ public abstract class CqlUtils { * @param entity * @return The CQL that can be passed to session.execute() */ - public static String createTable(String tableName, final CassandraPersistentEntity entity) { + public static String createTable(String tableName, final CassandraPersistentEntity entity, + final MappingContext, CassandraPersistentProperty> mappingContext) { final StringBuilder str = new StringBuilder(); str.append("CREATE TABLE "); str.append(tableName); str.append('('); - final List ids = new ArrayList(); - final List idColumns = new ArrayList(); + final List clusteredIds = new ArrayList(); + final List partitionedIds = new ArrayList(); entity.doWithProperties(new PropertyHandler() { public void doWithPersistentProperty(CassandraPersistentProperty prop) { - if (str.charAt(str.length() - 1) != '(') { - str.append(','); - } + if (prop.isCompositePrimaryKey()) { - String columnName = prop.getColumnName(); + CassandraPersistentEntity pkEntity = mappingContext.getPersistentEntity(prop.getRawType()); - str.append(columnName); - str.append(' '); + pkEntity.doWithProperties(new PropertyHandler() { + public void doWithPersistentProperty(CassandraPersistentProperty pkProp) { - DataType dataType = prop.getDataType(); + if (pkProp.isPartitioned()) { + partitionedIds.add(pkProp.getColumnName()); + } else { + clusteredIds.add(pkProp.getColumnName()); + } - str.append(toCQL(dataType)); + if (str.charAt(str.length() - 1) != '(') { + str.append(','); + } - if (prop.isIdProperty()) { - ids.add(prop.getColumnName()); - } + String columnName = pkProp.getColumnName(); - if (prop.isColumnId()) { - idColumns.add(prop.getColumnName()); + str.append(columnName); + str.append(' '); + + DataType dataType = pkProp.getDataType(); + + str.append(toCQL(dataType)); + + } + }); + + } else { + + if (str.charAt(str.length() - 1) != '(') { + str.append(','); + } + + String columnName = prop.getColumnName(); + + str.append(columnName); + str.append(' '); + + DataType dataType = prop.getDataType(); + + str.append(toCQL(dataType)); + + if (prop.isIdProperty()) { + partitionedIds.add(prop.getColumnName()); + } } } }); - if (ids.isEmpty()) { - throw new InvalidDataAccessApiUsageException("not found primary ID in the entity " + entity.getType()); + if (partitionedIds.isEmpty()) { + throw new InvalidDataAccessApiUsageException("not found partition key in the entity " + entity.getType()); } str.append(",PRIMARY KEY("); - // if (ids.size() > 1) { - // str.append('('); - // } + if (partitionedIds.size() > 1) { + str.append('('); + } - for (String id : ids) { + for (String id : partitionedIds) { if (str.charAt(str.length() - 1) != '(') { str.append(','); } str.append(id); } - // if (ids.size() > 1) { - // str.append(')'); - // } + if (partitionedIds.size() > 1) { + str.append(')'); + } - for (String id : idColumns) { + for (String id : clusteredIds) { str.append(','); str.append(id); } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentPropertyIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentPropertyIntegrationTests.java index dcc25c126..0dd7ad2f3 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentPropertyIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/BasicCassandraPersistentPropertyIntegrationTests.java @@ -36,7 +36,6 @@ import org.springframework.data.cassandra.mapping.BasicCassandraPersistentProper import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; import org.springframework.data.cassandra.mapping.CassandraPersistentProperty; import org.springframework.data.cassandra.mapping.Column; -import org.springframework.data.cassandra.mapping.ColumnId; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.ClassTypeInformation; import org.springframework.util.ReflectionUtils; @@ -81,12 +80,6 @@ public class BasicCassandraPersistentPropertyIntegrationTests { assertThat(getPropertyFor(field).getColumnName(), is("time")); } - @Test - public void checksColumnIdProperty() { - CassandraPersistentProperty property = getPropertyFor(ReflectionUtils.findField(Timeline.class, "time")); - assertThat(property.isColumnId(), is(true)); - } - @After public void clearCassandra() { EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); @@ -106,7 +99,6 @@ public class BasicCassandraPersistentPropertyIntegrationTests { @Id String id; - @ColumnId Date time; @Column("message") diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Book.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Book.java index b5e07e29f..bc0659205 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Book.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Book.java @@ -15,7 +15,7 @@ */ package org.springframework.data.cassandra.test.integration.table; -import org.springframework.data.cassandra.mapping.RowId; +import org.springframework.data.cassandra.mapping.Id; import org.springframework.data.cassandra.mapping.Table; /** @@ -27,7 +27,7 @@ import org.springframework.data.cassandra.mapping.Table; @Table(name = "book") public class Book { - @RowId + @Id private String isbn; private String title; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Comment.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Comment.java index ff0fd3f6b..b7d7b1632 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Comment.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Comment.java @@ -18,19 +18,15 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Date; import java.util.Set; -import org.springframework.data.annotation.Id; -import org.springframework.data.cassandra.mapping.ColumnId; +import org.springframework.data.cassandra.mapping.Id; import org.springframework.data.cassandra.mapping.Qualify; import org.springframework.data.cassandra.mapping.Table; import com.datastax.driver.core.DataType; /** - * This is an example of dynamic table that creates each time new column with Post timestamp annotated by @ColumnId. - * - * It is possible to use a static table for posts and identify them by PostId(UUID), but in this case we need to use - * MapReduce for Big Data to find posts for particular user, so it is better to have index (userId) -> index (post time) - * architecture. It helps a lot to build eventually a search index for the particular user. + * This is an example of dynamic table (wide row). PartitionKey (former RowId) is pk.author. ClusteredColumn (former + * Column Id) is pk.time * * @author Alex Shvid */ @@ -38,17 +34,10 @@ import com.datastax.driver.core.DataType; public class Comment { /* - * Primary Row ID + * Primary Key */ @Id - private String author; - - /* - * Column ID - */ - @ColumnId - @Qualify(type = DataType.Name.TIMESTAMP) - private Date time; + private CommentPK pk; private String text; @@ -61,20 +50,12 @@ public class Comment { private String postAuthor; private Date postTime; - public String getAuthor() { - return author; + public CommentPK getPk() { + return pk; } - public void setAuthor(String author) { - this.author = author; - } - - public Date getTime() { - return time; - } - - public void setTime(Date time) { - this.time = time; + public void setPk(CommentPK pk) { + this.pk = pk; } public String getText() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/CommentPK.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/CommentPK.java new file mode 100644 index 000000000..626481e44 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/CommentPK.java @@ -0,0 +1,63 @@ +package org.springframework.data.cassandra.test.integration.table; + +/* + * Copyright 2010-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. + */ +import java.util.Date; + +import org.springframework.data.cassandra.mapping.CompositePrimaryKey; +import org.springframework.data.cassandra.mapping.Partitioned; +import org.springframework.data.cassandra.mapping.Qualify; + +import com.datastax.driver.core.DataType; + +/** + * This is an example of dynamic table (wide row) that creates each time new column with timestamp. + * + * @author Alex Shvid + */ + +@CompositePrimaryKey +public class CommentPK { + + /* + * Row ID + */ + @Partitioned + private String author; + + /* + * Clustered Column + */ + @Qualify(type = DataType.Name.TIMESTAMP) + private Date time; + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/LogEntry.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/LogEntry.java index 5797dec9f..e845fa5a1 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/LogEntry.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/LogEntry.java @@ -17,17 +17,12 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Date; -import org.springframework.data.annotation.Id; -import org.springframework.data.cassandra.mapping.Column; -import org.springframework.data.cassandra.mapping.RowId; +import org.springframework.data.cassandra.mapping.Id; import org.springframework.data.cassandra.mapping.Table; /** - * This is an example of the Users statis table, where all fields are columns in Cassandra row. Some fields can be - * Set,List,Map like emails. + * This is an example of the LogEntry static table, where all fields are columns in Cassandra row. * - * User contains base information related for separate user, like names, additional information, emails, following - * users, friends. * * @author Alex Shvid */ @@ -35,9 +30,9 @@ import org.springframework.data.cassandra.mapping.Table; public class LogEntry { /* - * Primary Row ID + * Primary Key */ - @RowId + @Id private Date logDate; private String hostname; diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Notification.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Notification.java index 6bde2543d..5b6ed07d7 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Notification.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Notification.java @@ -18,13 +18,11 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Date; import org.springframework.data.annotation.Id; -import org.springframework.data.cassandra.mapping.ColumnId; -import org.springframework.data.cassandra.mapping.Index; +import org.springframework.data.cassandra.mapping.Indexed; import org.springframework.data.cassandra.mapping.Table; /** - * This is an example of dynamic table that creates each time new column with Notification timestamp annotated by - * @ColumnId. + * This is an example of dynamic table that creates each time new column with Notification timestamp. * * By default it is active Notification until user deactivate it. This table uses index on the field active to access in * WHERE cause only for active notifications. @@ -35,18 +33,12 @@ import org.springframework.data.cassandra.mapping.Table; public class Notification { /* - * Primary Row ID + * Primary Key */ @Id - private String username; + private NotificationPK pk; - /* - * Column ID - */ - @ColumnId - private Date time; - - @Index + @Indexed private boolean active; /* @@ -57,20 +49,12 @@ public class Notification { private String refAuthor; private Date refTime; - public String getUsername() { - return username; + public NotificationPK getPk() { + return pk; } - public void setUsername(String username) { - this.username = username; - } - - public Date getTime() { - return time; - } - - public void setTime(Date time) { - this.time = time; + public void setPk(NotificationPK pk) { + this.pk = pk; } public boolean isActive() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/NotificationPK.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/NotificationPK.java new file mode 100644 index 000000000..22e892e3e --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/NotificationPK.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010-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.data.cassandra.test.integration.table; + +import java.util.Date; + +import org.springframework.data.cassandra.mapping.CompositePrimaryKey; +import org.springframework.data.cassandra.mapping.Partitioned; +import org.springframework.data.cassandra.mapping.Qualify; + +import com.datastax.driver.core.DataType; + +/** + * This is an example of dynamic table that creates each time new column with Notification timestamp. + * + * By default it is active Notification until user deactivate it. This table uses index on the field active to access in + * WHERE cause only for active notifications. + * + * @author Alex Shvid + */ +@CompositePrimaryKey +public class NotificationPK { + + /* + * Row ID + */ + @Partitioned + private String username; + + /* + * Clustered Column + */ + @Qualify(type = DataType.Name.TIMESTAMP) + private Date time; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Post.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Post.java index ea3de9f3d..c4d9317ff 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Post.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Post.java @@ -20,11 +20,10 @@ import java.util.Map; import java.util.Set; import org.springframework.data.annotation.Id; -import org.springframework.data.cassandra.mapping.ColumnId; import org.springframework.data.cassandra.mapping.Table; /** - * This is an example of dynamic table that creates each time new column with Post timestamp annotated by @ColumnId. + * This is an example of dynamic table that creates each time new column with Post timestamp. * * It is possible to use a static table for posts and identify them by PostId(UUID), but in this case we need to use * MapReduce for Big Data to find posts for particular user, so it is better to have index (userId) -> index (post time) @@ -36,16 +35,10 @@ import org.springframework.data.cassandra.mapping.Table; public class Post { /* - * Primary Row ID + * Primary Key */ @Id - private String author; - - /* - * Column ID - */ - @ColumnId - private Date time; + private PostPK pk; private String type; // status, share @@ -55,20 +48,12 @@ public class Post { private Set likes; private Set followers; - public String getAuthor() { - return author; + public PostPK getPk() { + return pk; } - public void setAuthor(String author) { - this.author = author; - } - - public Date getTime() { - return time; - } - - public void setTime(Date time) { - this.time = time; + public void setPk(PostPK pk) { + this.pk = pk; } public String getType() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/PostPK.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/PostPK.java new file mode 100644 index 000000000..80b19d0fc --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/PostPK.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010-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.data.cassandra.test.integration.table; + +import java.util.Date; + +import org.springframework.data.cassandra.mapping.CompositePrimaryKey; +import org.springframework.data.cassandra.mapping.Partitioned; + +/** + * This is an example of dynamic table that creates each time new column with Post timestamp. + * + * It is possible to use a static table for posts and identify them by PostId(UUID), but in this case we need to use + * MapReduce for Big Data to find posts for particular user, so it is better to have index (userId) -> index (post time) + * architecture. It helps a lot to build eventually a search index for the particular user. + * + * @author Alex Shvid + */ + +@CompositePrimaryKey +public class PostPK { + + /* + * Row ID + */ + @Partitioned + private String author; + + /* + * Clustered Column + */ + private Date time; + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Timeline.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Timeline.java index ce670b0c1..813f6a444 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Timeline.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/Timeline.java @@ -18,7 +18,6 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Date; import org.springframework.data.annotation.Id; -import org.springframework.data.cassandra.mapping.ColumnId; import org.springframework.data.cassandra.mapping.Table; /** @@ -34,16 +33,10 @@ import org.springframework.data.cassandra.mapping.Table; public class Timeline { /* - * Primary Row ID + * Row ID */ @Id - private String username; - - /* - * Column ID - */ - @ColumnId - private Date time; + private TimelinePK pk; /* * Reference to the post by author and postUID @@ -51,20 +44,12 @@ public class Timeline { private String author; private Date postTime; - public String getUsername() { - return username; + public TimelinePK getPk() { + return pk; } - public void setUsername(String username) { - this.username = username; - } - - public Date getTime() { - return time; - } - - public void setTime(Date time) { - this.time = time; + public void setPk(TimelinePK pk) { + this.pk = pk; } public String getAuthor() { diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/TimelinePK.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/TimelinePK.java new file mode 100644 index 000000000..ab6fad8e7 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/TimelinePK.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010-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.data.cassandra.test.integration.table; + +import java.util.Date; + +import org.springframework.data.cassandra.mapping.CompositePrimaryKey; +import org.springframework.data.cassandra.mapping.Partitioned; + +/** + * This is an example of the users timeline dynamic table, where all columns are dynamically created by @ColumnId field + * value. The rest fields are places in Cassandra value. + * + * Timeline entity is used to store user's status updates that it follows in the site. Timeline always ordered by @ColumnId + * field and we can retrieve last top status updates by using limits. + * + * @author Alex Shvid + */ + +@CompositePrimaryKey +public class TimelinePK { + + /* + * Row ID + */ + @Partitioned + private String username; + + /* + * Clustered Column + */ + private Date time; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + +} diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/User.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/User.java index 2586d0273..3bb91aeff 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/User.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/User.java @@ -18,7 +18,7 @@ package org.springframework.data.cassandra.test.integration.table; import java.util.Set; import org.springframework.data.annotation.Id; -import org.springframework.data.cassandra.mapping.Index; +import org.springframework.data.cassandra.mapping.Indexed; import org.springframework.data.cassandra.mapping.Table; /** @@ -49,7 +49,7 @@ public class User { * Secondary index, used only on fields with common information, * not effective on email, username */ - @Index + @Indexed private String place; /* diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/UserAlter.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/UserAlter.java deleted file mode 100644 index 7baad7368..000000000 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/table/UserAlter.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2010-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.data.cassandra.test.integration.table; - -import java.util.Set; - -import org.springframework.data.annotation.Id; -import org.springframework.data.cassandra.mapping.Index; -import org.springframework.data.cassandra.mapping.Table; - -/** - * This is an example of the Users statis table, where all fields are columns in Cassandra row. Some fields can be - * Set,List,Map like emails. - * - * User contains base information related for separate user, like names, additional information, emails, following - * users, friends. - * - * @author Alex Shvid - */ -@Table(name = "users") -public class UserAlter { - - /* - * Primary Row ID - */ - @Id - private String username; - - /* - * Public information - */ - private String firstName; - private String lastName; - - /* - * Secondary index, used only on fields with common information, - * not effective on email, username - */ - @Index - private String place; - - private String nickName; - - /* - * Password - */ - private String password; - - /* - * Age - */ - private int age; - - /* - * Following other users in userline - */ - private Set following; - - /* - * Friends of the user - */ - private Set friends; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getPlace() { - return place; - } - - public void setPlace(String place) { - this.place = place; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public Set getFollowing() { - return following; - } - - public void setFollowing(Set following) { - this.following = following; - } - - public Set getFriends() { - return friends; - } - - public void setFriends(Set friends) { - this.friends = friends; - } - - /** - * @return Returns the age. - */ - public int getAge() { - return age; - } - - /** - * @param age The age to set. - */ - public void setAge(int age) { - this.age = age; - } - - /** - * @return Returns the nickName. - */ - public String getNickName() { - return nickName; - } - - /** - * @param nickName The nickName to set. - */ - public void setNickName(String nickName) { - this.nickName = nickName; - } - -}