composite primary key support

This commit is contained in:
Alex Shvid
2013-12-02 21:08:51 -08:00
parent 9ae9984102
commit d9dd7d1605
26 changed files with 405 additions and 387 deletions

View File

@@ -35,7 +35,6 @@ 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;
import org.springframework.data.cassandra.mapping.CompoundKey;
import org.springframework.data.cassandra.mapping.Table;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.ClassUtils;

View File

@@ -83,7 +83,7 @@ public class CassandraAdminTemplate implements CassandraAdminOperations {
execute(new SessionCallback<Object>() {
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;

View File

@@ -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<SpringDataKeysp
private void createNewTable(Session session, String useTableName, CassandraPersistentEntity<?> 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)) {

View File

@@ -104,14 +104,6 @@ public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T,
*/
public int compare(CassandraPersistentProperty o1, CassandraPersistentProperty o2) {
if (o1.isColumnId()) {
return 1;
}
if (o2.isColumnId()) {
return -1;
}
return o1.getColumnName().compareTo(o2.getColumnName());
}

View File

@@ -51,7 +51,7 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
}
/**
* Also considers fields that has a RowId annotation.
* Also considers fields that has an Id annotation.
*
*/
@Override
@@ -61,16 +61,18 @@ public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentP
return true;
}
return getField().isAnnotationPresent(PrimaryKey.class);
return getField().isAnnotationPresent(Id.class);
}
/**
* For dynamic tables returns true if property value is used as column name.
* Returns the true if the field composite primary key.
*
* @return
*/
public boolean isColumnId() {
return getField().isAnnotationPresent(ColumnId.class);
@Override
public boolean isCompositePrimaryKey() {
Class<?> 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);
}
/*

View File

@@ -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;
}
}

View File

@@ -27,11 +27,11 @@ import com.datastax.driver.core.DataType;
public interface CassandraPersistentProperty extends PersistentProperty<CassandraPersistentProperty> {
/**
* 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<Cassandr
*/
boolean isIndexed();
/**
* Returns true if the property has Partitioned annotation.
*
* @return
*/
boolean isPartitioned();
}

View File

@@ -22,16 +22,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Identifies compound keys class in the Cassandra table that contains several fields. Same as
* Defines composite primary key class in the Cassandra table that contains several fields. Example:
*
* @org.springframework.data.annotation.Id
*
* Example:
*
* @CompoundKey class AccountPK { String account; String region; }
* @CompositePrimaryKey class AccountPK { String account; String region; }
*
* @Table class Account {
* @PrimaryKey AccountPK pk; }
* @Id AccountPK pk; }
*
*
* @author Alex Shvid
@@ -40,6 +36,6 @@ import java.lang.annotation.Target;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface CompoundKey {
public @interface CompositePrimaryKey {
}

View File

@@ -21,13 +21,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Uses in dynamic tables where column names are values of this field. Usually it is a Date/Time field or UUIDTime
* field.
* Identifies primary key or ID in the Cassandra table. Same as @org.springframework.data.annotation.Id
*
* @author Alex Shvid
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
public @interface ColumnId {
@org.springframework.data.annotation.Id
public @interface Id {
}

View File

@@ -30,6 +30,6 @@ import java.lang.annotation.Target;
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
public @interface Index {
public @interface Indexed {
}

View File

@@ -1,32 +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.mapping;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Identifies partition key in the Cassandra compound key class.
*
* @author Alex Shvid
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
public @interface PartitionKey {
}

View File

@@ -20,15 +20,14 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.data.annotation.Id;
/**
* Identifies row ID in the Cassandra table. Same as @org.springframework.data.annotation.Id
* Identifies partition key in the Cassandra composite primary key class. Annotated column is the part of the Cassandra
* Partition Key (former Row Id).
*
* @author Alex Shvid
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Id
public @interface PrimaryKey {
public @interface Partitioned {
}

View File

@@ -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<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext) {
final StringBuilder str = new StringBuilder();
str.append("CREATE TABLE ");
str.append(tableName);
str.append('(');
final List<String> ids = new ArrayList<String>();
final List<String> idColumns = new ArrayList<String>();
final List<String> clusteredIds = new ArrayList<String>();
final List<String> partitionedIds = new ArrayList<String>();
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
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<CassandraPersistentProperty>() {
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);
}

View File

@@ -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")

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.cassandra.test.integration.table;
import org.springframework.data.cassandra.mapping.PrimaryKey;
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 {
@PrimaryKey
@Id
private String isbn;
private String title;

View File

@@ -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() {

View File

@@ -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;
}
}

View File

@@ -17,15 +17,12 @@ package org.springframework.data.cassandra.test.integration.table;
import java.util.Date;
import org.springframework.data.cassandra.mapping.PrimaryKey;
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
*/
@@ -33,9 +30,9 @@ import org.springframework.data.cassandra.mapping.Table;
public class LogEntry {
/*
* Primary Row ID
* Primary Key
*/
@PrimaryKey
@Id
private Date logDate;
private String hostname;

View File

@@ -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() {

View File

@@ -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;
}
}

View File

@@ -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<String> likes;
private Set<String> 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() {

View File

@@ -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;
}
}

View File

@@ -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() {

View File

@@ -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;
}
}

View File

@@ -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;
/*

View File

@@ -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<String> following;
/*
* Friends of the user
*/
private Set<String> 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<String> getFollowing() {
return following;
}
public void setFollowing(Set<String> following) {
this.following = following;
}
public Set<String> getFriends() {
return friends;
}
public void setFriends(Set<String> 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;
}
}