#203 - Revise Cassandra Examples.
Simplify examples by adopting Spring Boot 1.4 improvements. Upgrade Cassandra Java driver to 3.0.3. Add examples for Ingalls (Query derivation, projection, Java 8 feature support). Cassandra example setup is now self-contained by requiring just a running Cassandra instance. Keyspace and tables are created during the tests. Examples also check if Cassandra is running and some examples additionally check the required version. Test execution is skipped if conditions are not met. Cassandra (2.x) is started with TravisCI.
This commit is contained in:
@@ -5,6 +5,7 @@ jdk:
|
||||
|
||||
services:
|
||||
- redis-server
|
||||
- cassandra
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@@ -14,4 +15,4 @@ sudo: false
|
||||
|
||||
install: true
|
||||
|
||||
script: "mvn clean dependency:list test -Dsort"
|
||||
script: "mvn clean dependency:list test -Dsort"
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
Before we can start we have to install Cassandra, e.g. via brew on Max OS.
|
||||
```
|
||||
brew install cassandra
|
||||
pip install cassandra-driver
|
||||
brew install cassandra-driver
|
||||
|
||||
More details can be found here: https://wiki.apache.org/cassandra/GettingStarted
|
||||
```
|
||||
@@ -17,26 +15,5 @@ More details can be found here: https://wiki.apache.org/cassandra/GettingStarted
|
||||
/usr/local/bin/cassandra -f
|
||||
```
|
||||
|
||||
### Start a Cassandra shell cqlsh
|
||||
```
|
||||
/usr/local/bin/cqlsh
|
||||
```
|
||||
|
||||
### Setup Keyspace and Tables
|
||||
|
||||
```
|
||||
CREATE KEYSPACE example
|
||||
WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };
|
||||
|
||||
USE example;
|
||||
|
||||
CREATE TABLE users (
|
||||
user_id int PRIMARY KEY,
|
||||
uname text,
|
||||
fname text,
|
||||
lname text
|
||||
);
|
||||
```
|
||||
|
||||
That should be enough to get you started.
|
||||
Now you can simply type ```mvn clean install``` to run the example.
|
||||
Now you can simply type ```mvn clean install``` to run the example.
|
||||
|
||||
@@ -12,6 +12,22 @@
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Cassandra - Example</name>
|
||||
<description>Small sample project showing the usage of Spring Data Cassandra.</description>
|
||||
|
||||
<description>Basic sample project showing the usage of Spring Data Cassandra.</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-data-cassandra-example-utils</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -13,37 +13,51 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package example.springdata.cassandra;
|
||||
package example.springdata.cassandra.basic;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cassandra.config.java.AbstractCqlTemplateConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.cassandra.config.SchemaAction;
|
||||
import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration;
|
||||
import org.springframework.data.cassandra.core.CassandraTemplate;
|
||||
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
/**
|
||||
* Basic {@link Configuration} to create the necessary schema for the {@link User} table.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
class SimpleConfiguration {
|
||||
class BasicConfiguration {
|
||||
|
||||
@Configuration
|
||||
@EnableCassandraRepositories
|
||||
static class CassandraConfig extends AbstractCqlTemplateConfiguration {
|
||||
static class CassandraConfig extends AbstractCassandraConfiguration {
|
||||
|
||||
@Override
|
||||
public String getKeyspaceName() {
|
||||
return "example";
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public CassandraTemplate cassandraTemplate(Session session) {
|
||||
return new CassandraTemplate(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getEntityBasePackages() {
|
||||
return new String[] { User.class.getPackage().getName() };
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchemaAction getSchemaAction() {
|
||||
return SchemaAction.RECREATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2013-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 example.springdata.cassandra.basic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.cassandra.repository.Query;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* Simple repository interface for {@link User} instances. The interface is used to declare so called query methods,
|
||||
* methods to retrieve single entities or collections of them.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public interface BasicUserRepository extends CrudRepository<User, Long> {
|
||||
|
||||
/**
|
||||
* Sample method annotated with {@link Query}. This method executes the CQL from the {@link Query} value.
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@Query("SELECT * from users where user_id in(?0)")
|
||||
User findUserByIdIn(long id);
|
||||
|
||||
/**
|
||||
* Derived query method. This query corresponds with {@code SELECT * FROM users WHERE uname = ?0}.
|
||||
* {@link User#username} is not part of the primary so it requires a secondary index.
|
||||
*
|
||||
* @param username
|
||||
* @return
|
||||
*/
|
||||
User findUserByUsername(String username);
|
||||
|
||||
/**
|
||||
* Derived query method using SASI (SSTable Attached Secondary Index) features through the {@code LIKE} keyword. This
|
||||
* query corresponds with {@code SELECT * FROM users WHERE uname LIKE '?0%'}. {@link User#username} is not part of the
|
||||
* primary so it requires a secondary index.
|
||||
*
|
||||
* @param lastnamePrefix
|
||||
* @return
|
||||
*/
|
||||
List<User> findUsersByLastnameStartsWith(String lastnamePrefix);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package example.springdata.cassandra;
|
||||
package example.springdata.cassandra.basic;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Package showing a simple repository interface to use basic query method execution functionality.
|
||||
*/
|
||||
package example.springdata.cassandra;
|
||||
package example.springdata.cassandra.basic;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,14 +13,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package example.springdata.cassandra;
|
||||
package example.springdata.cassandra.convert;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.cassandra.mapping.Table;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Simple repository interface for {@link User} instances. The interface is used to declare so called query methods,
|
||||
* methods to retrieve single entities or collections of them.
|
||||
* Sample Addressbook class.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface SimpleUserRepository extends CrudRepository<User, Long> {}
|
||||
@Data
|
||||
@Table
|
||||
public class Addressbook {
|
||||
|
||||
@Id String id;
|
||||
|
||||
Contact me;
|
||||
List<Contact> friends;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.convert;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Sample Contact class.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Contact {
|
||||
|
||||
String firstname;
|
||||
String lastname;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.convert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.cassandra.config.SchemaAction;
|
||||
import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration;
|
||||
import org.springframework.data.cassandra.convert.CustomConversions;
|
||||
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* {@link Configuration} class to register custom converters.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCassandraRepositories
|
||||
class ConverterConfiguration extends AbstractCassandraConfiguration {
|
||||
|
||||
@Override
|
||||
public String getKeyspaceName() {
|
||||
return "example";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getEntityBasePackages() {
|
||||
return new String[] { Addressbook.class.getPackage().getName() };
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchemaAction getSchemaAction() {
|
||||
return SchemaAction.RECREATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomConversions customConversions() {
|
||||
|
||||
List<Converter<?, ?>> converters = new ArrayList<>();
|
||||
converters.add(new PersonWriteConverter());
|
||||
converters.add(new PersonReadConverter());
|
||||
converters.add(new CustomAddressbookReadConverter());
|
||||
|
||||
return new CustomConversions(converters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a {@link Contact} into its {@link String} representation.
|
||||
*/
|
||||
static class PersonWriteConverter implements Converter<Contact, String> {
|
||||
|
||||
public String convert(Contact source) {
|
||||
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(source);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a {@link Contact} from its {@link String} representation.
|
||||
*/
|
||||
static class PersonReadConverter implements Converter<String, Contact> {
|
||||
|
||||
public Contact convert(String source) {
|
||||
|
||||
if (StringUtils.hasText(source)) {
|
||||
try {
|
||||
return new ObjectMapper().readValue(source, Contact.class);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform custom mapping by reading a {@link Row} into a custom class.
|
||||
*/
|
||||
static class CustomAddressbookReadConverter implements Converter<Row, CustomAddressbook> {
|
||||
|
||||
public CustomAddressbook convert(Row source) {
|
||||
|
||||
CustomAddressbook result = new CustomAddressbook();
|
||||
|
||||
result.setTheId(source.getString("id"));
|
||||
result.setMyDetailsAsJson(source.getString("me"));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.convert;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Data
|
||||
public class CustomAddressbook {
|
||||
|
||||
String theId;
|
||||
String myDetailsAsJson;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Package showing conversion features.
|
||||
*/
|
||||
package example.springdata.cassandra.convert;
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.projection;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.cassandra.mapping.Table;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Value
|
||||
@Table
|
||||
class Customer {
|
||||
|
||||
@Id String id;
|
||||
String firstname, lastname;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.projection;
|
||||
|
||||
/**
|
||||
* An example projection interface containing only the firstname.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
interface CustomerProjection {
|
||||
|
||||
String getFirstname();
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.projection;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* Sample repository managing customers to show projecting functionality of Spring Data Cassandra.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
interface CustomerRepository extends CrudRepository<Customer, String> {
|
||||
|
||||
/**
|
||||
* Uses a projection interface to indicate the fields to be returned. As the projection doesn't use any dynamic
|
||||
* fields, the query execution will be restricted to only the fields needed by the projection.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Collection<CustomerProjection> findAllProjectedBy();
|
||||
|
||||
/**
|
||||
* When a projection is used that contains dynamic properties (i.e. SpEL expressions in an {@link Value} annotation),
|
||||
* the normal target entity will be loaded but dynamically projected so that the target can be referred to in the
|
||||
* expression.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Collection<CustomerSummary> findAllSummarizedBy();
|
||||
|
||||
/**
|
||||
* Passes in the projection type dynamically.
|
||||
*
|
||||
* @param id
|
||||
* @param projection
|
||||
* @return
|
||||
*/
|
||||
<T> Collection<T> findById(String id, Class<T> projection);
|
||||
|
||||
/**
|
||||
* Projection for a single entity.
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
CustomerProjection findProjectedById(String id);
|
||||
|
||||
/**
|
||||
* Dynamic projection for a single entity.
|
||||
*
|
||||
* @param id
|
||||
* @param projection
|
||||
* @return
|
||||
*/
|
||||
<T> T findProjectedById(String id, Class<T> projection);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.projection;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
/**
|
||||
* An example of using SpEL with projections.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
interface CustomerSummary {
|
||||
|
||||
@Value("#{target.firstname + ' ' + target.lastname}")
|
||||
String getFullName();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.projection;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.cassandra.config.SchemaAction;
|
||||
import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration;
|
||||
import org.springframework.data.cassandra.core.CassandraTemplate;
|
||||
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
import example.springdata.cassandra.basic.User;
|
||||
|
||||
/**
|
||||
* Basic {@link Configuration} to create the necessary schema for the {@link Customer} table.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
class ProjectionConfiguration {
|
||||
|
||||
@Configuration
|
||||
@EnableCassandraRepositories
|
||||
static class CassandraConfig extends AbstractCassandraConfiguration {
|
||||
|
||||
@Override
|
||||
public String getKeyspaceName() {
|
||||
return "example";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getEntityBasePackages() {
|
||||
return new String[] { Customer.class.getPackage().getName() };
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchemaAction getSchemaAction() {
|
||||
return SchemaAction.RECREATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Package showing projection features.
|
||||
*/
|
||||
package example.springdata.cassandra.projection;
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import example.springdata.cassandra.SimpleConfiguration;
|
||||
import example.springdata.cassandra.SimpleUserRepository;
|
||||
import example.springdata.cassandra.User;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* Integration test showing the basic usage of {@link SimpleUserRepository}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Ignore
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = SimpleConfiguration.class)
|
||||
public class SimpleUserRepositoryTests {
|
||||
|
||||
@Autowired SimpleUserRepository repository;
|
||||
User user;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
user = new User();
|
||||
user.setId(42L);
|
||||
user.setUsername("foobar");
|
||||
user.setFirstname("firstname");
|
||||
user.setLastname("lastname");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSavedUserById() {
|
||||
|
||||
user = repository.save(user);
|
||||
|
||||
assertThat(repository.findOne(user.getId()), is(user));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.basic;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.util.Version;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
import example.springdata.cassandra.util.CassandraVersion;
|
||||
import example.springdata.cassandra.util.RequiresCassandraKeyspace;
|
||||
|
||||
/**
|
||||
* Integration test showing the basic usage of {@link BasicUserRepository}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = BasicConfiguration.class)
|
||||
public class BasicUserRepositoryTests {
|
||||
|
||||
public final static Version CASSANDRA_3_4 = Version.parse("3.4");
|
||||
|
||||
@ClassRule public final static RequiresCassandraKeyspace CASSANDRA_KEYSPACE = RequiresCassandraKeyspace.onLocalhost();
|
||||
|
||||
@Autowired BasicUserRepository repository;
|
||||
@Autowired Session session;
|
||||
User user;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
user = new User();
|
||||
user.setId(42L);
|
||||
user.setUsername("foobar");
|
||||
user.setFirstname("firstname");
|
||||
user.setLastname("lastname");
|
||||
}
|
||||
|
||||
/**
|
||||
* Saving an object using the Cassandra Repository will create a persistent representation of the object in Cassandra.
|
||||
*/
|
||||
@Test
|
||||
public void findSavedUserById() {
|
||||
|
||||
user = repository.save(user);
|
||||
|
||||
assertThat(repository.findOne(user.getId()), is(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cassandra can be queries by using query methods annotated with {@link @Query}.
|
||||
*/
|
||||
@Test
|
||||
public void findByAnnotatedQueryMethod() {
|
||||
|
||||
repository.save(user);
|
||||
|
||||
assertThat(repository.findUserByIdIn(1000), is(nullValue()));
|
||||
assertThat(repository.findUserByIdIn(42), is(equalTo(user)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring Data Cassandra supports query derivation so annotating query methods with
|
||||
* {@link org.springframework.data.cassandra.repository.Query} is optional. Querying columns other than the primary
|
||||
* key requires a secondary index.
|
||||
*/
|
||||
@Test
|
||||
public void findByDerivedQueryMethod() throws InterruptedException {
|
||||
|
||||
session.execute("CREATE INDEX IF NOT EXISTS user_username ON users (uname);");
|
||||
/*
|
||||
Cassandra secondary indexes are created in the background without the possibility to check
|
||||
whether they are available or not. So we are forced to just wait. *sigh*
|
||||
*/
|
||||
Thread.sleep(1000);
|
||||
|
||||
repository.save(user);
|
||||
|
||||
assertThat(repository.findUserByUsername(user.getUsername()), is(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring Data Cassandra supports {@code LIKE} and {@code CONTAINS} query keywords to for SASI indexes.
|
||||
*/
|
||||
@Test
|
||||
public void findByDerivedQueryMethodWithSASI() throws InterruptedException {
|
||||
|
||||
assumeTrue(CassandraVersion.getReleaseVersion(session).isGreaterThanOrEqualTo(CASSANDRA_3_4));
|
||||
|
||||
session.execute("CREATE CUSTOM INDEX ON users (lname) USING 'org.apache.cassandra.index.sasi.SASIIndex';");
|
||||
/*
|
||||
Cassandra secondary indexes are created in the background without the possibility to check
|
||||
whether they are available or not. So we are forced to just wait. *sigh*
|
||||
*/
|
||||
Thread.sleep(1000);
|
||||
|
||||
repository.save(user);
|
||||
|
||||
assertThat(repository.findUsersByLastnameStartsWith("last"), hasItem(user));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.basic;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.cassandra.core.CassandraOperations;
|
||||
import org.springframework.data.cassandra.core.CassandraTemplate;
|
||||
import org.springframework.data.cassandra.core.WriteListener;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
|
||||
import example.springdata.cassandra.util.RequiresCassandraKeyspace;
|
||||
|
||||
/**
|
||||
* Integration test showing the basic usage of {@link CassandraTemplate}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = BasicConfiguration.CassandraConfig.class)
|
||||
public class CassandraOperationsIntegrationTests {
|
||||
|
||||
@ClassRule public final static RequiresCassandraKeyspace CASSANDRA_KEYSPACE = RequiresCassandraKeyspace.onLocalhost();
|
||||
|
||||
@Autowired CassandraOperations template;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
template.truncate("users");
|
||||
}
|
||||
|
||||
/**
|
||||
* Cassandra {@link com.datastax.driver.core.Statement}s can be used together with {@link CassandraTemplate} and the
|
||||
* mapping layer.
|
||||
*/
|
||||
@Test
|
||||
public void insertAndSelect() {
|
||||
|
||||
Insert insert = QueryBuilder.insertInto("users").value("user_id", 42L) //
|
||||
.value("uname", "heisenberg") //
|
||||
.value("fname", "Walter") //
|
||||
.value("lname", "White") //
|
||||
.ifNotExists(); //
|
||||
|
||||
template.execute(insert);
|
||||
|
||||
User user = template.selectOneById(User.class, 42L);
|
||||
assertThat(user.getUsername(), is(equalTo("heisenberg")));
|
||||
|
||||
List<User> users = template.select(QueryBuilder.select().from("users"), User.class);
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(equalTo(user)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Objects can be inserted and updated using {@link CassandraTemplate}. What you {@code update} is what you
|
||||
* {@code select}.
|
||||
*/
|
||||
@Test
|
||||
public void insertAndUpdate() {
|
||||
|
||||
User user = new User();
|
||||
user.setId(42L);
|
||||
user.setUsername("heisenberg");
|
||||
user.setFirstname("Walter");
|
||||
user.setLastname("White");
|
||||
|
||||
template.insert(user);
|
||||
|
||||
user.setFirstname(null);
|
||||
template.update(user);
|
||||
|
||||
User loaded = template.selectOneById(User.class, 42L);
|
||||
assertThat(loaded.getUsername(), is(equalTo("heisenberg")));
|
||||
assertThat(loaded.getFirstname(), is(nullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous query execution using callbacks.
|
||||
*/
|
||||
@Test
|
||||
public void insertAsynchronously() throws InterruptedException {
|
||||
|
||||
User user = new User();
|
||||
user.setId(42L);
|
||||
user.setUsername("heisenberg");
|
||||
user.setFirstname("Walter");
|
||||
user.setLastname("White");
|
||||
|
||||
final CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
|
||||
template.insertAsynchronously(user, new WriteListener<User>() {
|
||||
|
||||
@Override
|
||||
public void onWriteComplete(Collection<User> entities) {
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception x) {}
|
||||
});
|
||||
|
||||
countDownLatch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
User loaded = template.selectOneById(User.class, user.getId());
|
||||
assertThat(loaded, is(equalTo(user)));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link CassandraTemplate} allows selection of projections on template-level. All basic data types including
|
||||
* {@link Row} can be selected.
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void selectProjections() {
|
||||
|
||||
User user = new User();
|
||||
user.setId(42L);
|
||||
user.setUsername("heisenberg");
|
||||
user.setFirstname("Walter");
|
||||
user.setLastname("White");
|
||||
|
||||
template.insert(user);
|
||||
|
||||
Long id = template.selectOne(QueryBuilder.select("user_id").from("users"), Long.class);
|
||||
assertThat(id, is(user.getId()));
|
||||
|
||||
Row row = template.selectOne(QueryBuilder.select("user_id").from("users"), Row.class);
|
||||
assertThat(row.getLong(0), is(user.getId()));
|
||||
|
||||
Map<String, Object> map = template.selectOne(QueryBuilder.select().from("users"), Map.class);
|
||||
assertThat(map, hasEntry("user_id", user.getId()));
|
||||
assertThat(map, hasEntry("fname", "Walter"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.convert;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.cassandra.core.CassandraOperations;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
|
||||
import example.springdata.cassandra.util.RequiresCassandraKeyspace;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = ConverterConfiguration.class)
|
||||
public class ConversionIntegrationTests {
|
||||
|
||||
@ClassRule public final static RequiresCassandraKeyspace CASSANDRA_KEYSPACE = RequiresCassandraKeyspace.onLocalhost();
|
||||
|
||||
@Autowired CassandraOperations operations;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
operations.truncate("addressbook");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and stores a new {@link Addressbook} inside of Cassandra. {@link Contact} classes are converted using the
|
||||
* custom {@link example.springdata.cassandra.convert.ConverterConfiguration.PersonWriteConverter}.
|
||||
*/
|
||||
@Test
|
||||
public void shouldCreateAddressbook() {
|
||||
|
||||
Addressbook addressbook = new Addressbook();
|
||||
addressbook.setId("private");
|
||||
|
||||
addressbook.setMe(new Contact("Walter", "White"));
|
||||
addressbook.setFriends(Arrays.asList(new Contact("Jesse", "Pinkman"), new Contact("Saul", "Goodman")));
|
||||
|
||||
operations.insert(addressbook);
|
||||
|
||||
Row row = operations.selectOne(QueryBuilder.select().from("addressbook"), Row.class);
|
||||
|
||||
assertThat(row, is(notNullValue()));
|
||||
|
||||
assertThat(row.getString("id"), is(equalTo("private")));
|
||||
assertThat(row.getString("me"), containsString("\"firstname\":\"Walter\""));
|
||||
assertThat(row.getList("friends", String.class), hasSize(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and loads a new {@link Addressbook} inside of Cassandra. {@link Contact} classes are converted using the
|
||||
* custom {@link example.springdata.cassandra.convert.ConverterConfiguration.PersonReadConverter}.
|
||||
*/
|
||||
@Test
|
||||
public void shouldReadAddressbook() {
|
||||
|
||||
Addressbook addressbook = new Addressbook();
|
||||
addressbook.setId("private");
|
||||
|
||||
addressbook.setMe(new Contact("Walter", "White"));
|
||||
addressbook.setFriends(Arrays.asList(new Contact("Jesse", "Pinkman"), new Contact("Saul", "Goodman")));
|
||||
|
||||
operations.insert(addressbook);
|
||||
|
||||
Addressbook loaded = operations.selectOne(QueryBuilder.select().from("addressbook"), Addressbook.class);
|
||||
|
||||
assertThat(loaded.getMe(), is(equalTo(addressbook.getMe())));
|
||||
assertThat(loaded.getFriends(), is(equalTo(addressbook.getFriends())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and stores a new {@link Addressbook} inside of Cassandra. The {@link Addressbook} is read back to a
|
||||
* {@link CustomAddressbook} class using the
|
||||
* {@link example.springdata.cassandra.convert.ConverterConfiguration.CustomAddressbookReadConverter}.
|
||||
*/
|
||||
@Test
|
||||
public void shouldReadCustomAddressbook() {
|
||||
|
||||
Addressbook addressbook = new Addressbook();
|
||||
addressbook.setId("private");
|
||||
|
||||
addressbook.setMe(new Contact("Walter", "White"));
|
||||
|
||||
operations.insert(addressbook);
|
||||
|
||||
CustomAddressbook loaded = operations.selectOne(QueryBuilder.select().from("addressbook"), CustomAddressbook.class);
|
||||
|
||||
assertThat(loaded.getTheId(), is(equalTo(addressbook.getId())));
|
||||
assertThat(loaded.getMyDetailsAsJson(), containsString("\"firstname\":\"Walter\""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.projection;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.projection.TargetAware;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import example.springdata.cassandra.util.RequiresCassandraKeyspace;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link CustomerRepository} to show projection capabilities.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = ProjectionConfiguration.class)
|
||||
public class CustomerRepositoryIntegrationTest {
|
||||
|
||||
@ClassRule public final static RequiresCassandraKeyspace CASSANDRA_KEYSPACE = RequiresCassandraKeyspace.onLocalhost();
|
||||
|
||||
@Autowired CustomerRepository customers;
|
||||
|
||||
Customer dave, carter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
customers.deleteAll();
|
||||
|
||||
this.dave = customers.save(new Customer("d", "Dave", "Matthews"));
|
||||
this.carter = customers.save(new Customer("c", "Carter", "Beauford"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void projectsEntityIntoInterface() {
|
||||
|
||||
Collection<CustomerProjection> result = customers.findAllProjectedBy();
|
||||
|
||||
assertThat(result, hasSize(2));
|
||||
assertThat(result.iterator().next().getFirstname(), is("Carter"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void projectsDynamically() {
|
||||
|
||||
Collection<CustomerProjection> result = customers.findById("d", CustomerProjection.class);
|
||||
|
||||
assertThat(result, hasSize(1));
|
||||
assertThat(result.iterator().next().getFirstname(), is("Dave"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void projectsIndividualDynamically() {
|
||||
|
||||
CustomerSummary result = customers.findProjectedById(dave.getId(), CustomerSummary.class);
|
||||
|
||||
assertThat(result, is(notNullValue()));
|
||||
assertThat(result.getFullName(), is("Dave Matthews"));
|
||||
|
||||
// Proxy backed by original instance as the projection uses dynamic elements
|
||||
assertThat(((TargetAware) result).getTarget(), is(instanceOf(Customer.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void projectIndividualInstance() {
|
||||
|
||||
CustomerProjection result = customers.findProjectedById(dave.getId());
|
||||
|
||||
assertThat(result, is(notNullValue()));
|
||||
assertThat(result.getFirstname(), is("Dave"));
|
||||
assertThat(((TargetAware) result).getTarget(), is(instanceOf(Customer.class)));
|
||||
}
|
||||
|
||||
}
|
||||
36
cassandra/java8/README.md
Normal file
36
cassandra/java8/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Spring Data Cassandra - Java 8 examples
|
||||
|
||||
This project contains samples of Java 8 specific features of Spring Data (Cassandra).
|
||||
|
||||
## Support for JDK 8's `Stream` for repository methods
|
||||
|
||||
Repository methods can use a Java 8 `Stream` as a return type which will cause the reading of the results and the to-object-conversion of rows to happen while iterating over the stream.
|
||||
|
||||
```java
|
||||
public interface PersonRepository extends CrudRepository<Person, String> {
|
||||
|
||||
@Override
|
||||
List<Person> findAll();
|
||||
|
||||
//Custom Query method returning a Java 8 Stream
|
||||
@Query("SELECT * FROM person")
|
||||
Stream<Person> findAllByCustomQueryWithStream();
|
||||
}
|
||||
```
|
||||
|
||||
The test cases in `PersonRepositoryIntegrationTest` oppose a plain `List` based query method with one that uses a `Stream` and shows how the former pulls all data into memory first and the iteration is done over the pre-populated list. The execution of the `Stream`-based method in contrast shows that the individual elements are read and converted while iterating the stream.
|
||||
|
||||
## Preparation
|
||||
|
||||
### Install Cassandra
|
||||
Before we can start we have to install Cassandra, e.g. via brew on Max OS.
|
||||
|
||||
More details can be found here: https://wiki.apache.org/cassandra/GettingStarted
|
||||
|
||||
### Start Cassandra
|
||||
```
|
||||
/usr/local/bin/cassandra -f
|
||||
```
|
||||
|
||||
That should be enough to get you started.
|
||||
Now you can simply type ```mvn clean install``` to run the example.
|
||||
26
cassandra/java8/pom.xml
Normal file
26
cassandra/java8/pom.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.examples</groupId>
|
||||
<artifactId>spring-data-cassandra-examples</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-data-cassandra-java8</artifactId>
|
||||
<name>Spring Data Cassandra - Java 8 specific features</name>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-data-cassandra-example-utils</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.java8;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.cassandra.config.SchemaAction;
|
||||
import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration;
|
||||
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
class CassandraConfiguration {
|
||||
|
||||
@Configuration
|
||||
@EnableCassandraRepositories
|
||||
static class CassandraConfig extends AbstractCassandraConfiguration {
|
||||
|
||||
@Override
|
||||
public String getKeyspaceName() {
|
||||
return "example";
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchemaAction getSchemaAction() {
|
||||
return SchemaAction.RECREATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.java8;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.cassandra.mapping.Table;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Table("pizza_orders")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Order {
|
||||
|
||||
@Id String id;
|
||||
LocalDate orderDate;
|
||||
ZoneId zoneId;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.java8;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
|
||||
import org.springframework.data.cassandra.mapping.CassandraType;
|
||||
import org.springframework.data.cassandra.repository.Query;
|
||||
import org.springframework.data.repository.Repository;
|
||||
|
||||
/**
|
||||
* Repository to manage {@link Order} instances.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface OrderRepository extends Repository<Order, String> {
|
||||
|
||||
/**
|
||||
* Method parameters are converted according the registered Converters into Cassandra types.
|
||||
*/
|
||||
@Query("SELECT * from pizza_orders WHERE orderdate = ?0 and zoneid = ?1 ALLOW FILTERING")
|
||||
Order findOrderByOrderDateAndZoneId(LocalDate orderDate, ZoneId zoneId);
|
||||
|
||||
/**
|
||||
* Parameter conversion can be overridden by using the {@link CassandraType} annotation.
|
||||
*/
|
||||
@Query("SELECT * from pizza_orders WHERE orderdate = ?0 and zoneid = ?1 ALLOW FILTERING")
|
||||
Order findOrderByDate(com.datastax.driver.core.LocalDate orderDate, String zoneId);
|
||||
|
||||
void deleteAll();
|
||||
|
||||
Order save(Order order);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.java8;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.cassandra.mapping.Table;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Table
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Person {
|
||||
|
||||
@Id String id;
|
||||
String firstname, lastname;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.java8;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.data.cassandra.repository.Query;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.Repository;
|
||||
|
||||
/**
|
||||
* Repository to manage {@link Person} instances.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface PersonRepository extends Repository<Person, String> {
|
||||
|
||||
/**
|
||||
* Special customization of {@link CrudRepository#findOne(java.io.Serializable)} to return a JDK 8 {@link Optional}.
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
Optional<Person> findOne(String id);
|
||||
|
||||
@Query("select * from person")
|
||||
Stream<Person> streamAllPeople();
|
||||
|
||||
/**
|
||||
* Sample method to derive a query from using JDK 8's {@link Optional} as return type.
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@Query("select * from person where id = ?0")
|
||||
Optional<Person> findById(String id);
|
||||
|
||||
/**
|
||||
* Sample default method to show JDK 8 feature support.
|
||||
*
|
||||
* @param person
|
||||
* @return
|
||||
*/
|
||||
default Optional<Person> findByPerson(Person person) {
|
||||
return findById(person == null ? null : person.id);
|
||||
}
|
||||
|
||||
void deleteAll();
|
||||
|
||||
Person save(Person person);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Package showing Java 8 features.
|
||||
*/
|
||||
package example.springdata.cassandra.java8;
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.java8;
|
||||
|
||||
import example.springdata.cassandra.util.RequiresCassandraKeyspace;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.util.Version;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Integration test to show the usage of Java 8 features with Spring Data Cassandra.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = CassandraConfiguration.class)
|
||||
public class Java8IntegrationTests {
|
||||
|
||||
@ClassRule
|
||||
public final static RequiresCassandraKeyspace CASSANDRA_KEYSPACE = RequiresCassandraKeyspace.onLocalhost().atLeast(Version.parse("3.0"));
|
||||
|
||||
@Autowired PersonRepository repository;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
repository.deleteAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providesFindOneWithOptional() {
|
||||
|
||||
Person homer = repository.save(new Person("1", "Homer", "Simpson"));
|
||||
|
||||
assertThat(repository.findOne(homer.id).isPresent(), is(true));
|
||||
assertThat(repository.findOne(homer.id + 1), is(Optional.<Person> empty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokesDefaultMethod() {
|
||||
|
||||
Person homer = repository.save(new Person("1", "Homer", "Simpson"));
|
||||
Optional<Person> result = repository.findByPerson(homer);
|
||||
|
||||
assertThat(result.isPresent(), is(true));
|
||||
assertThat(result.get(), is(homer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Streaming data from the store by using a repository method that returns a {@link Stream}. Note, that since the
|
||||
* resulting {@link Stream} contains state it needs to be closed explicitly after use!
|
||||
*/
|
||||
@Test
|
||||
public void useJava8StreamsWithCustomQuery() {
|
||||
|
||||
Person homer = repository.save(new Person("1", "Homer", "Simpson"));
|
||||
Person bart = repository.save(new Person("2", "Bart", "Simpson"));
|
||||
|
||||
try (Stream<Person> stream = repository.streamAllPeople()) {
|
||||
assertThat(stream.collect(Collectors.toList()), hasItems(homer, bart));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.java8;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.util.Version;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import example.springdata.cassandra.util.RequiresCassandraKeyspace;
|
||||
|
||||
/**
|
||||
* Integration test to show the usage of JSR-310 date/time types with Spring Data Cassandra.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = CassandraConfiguration.class)
|
||||
public class Jsr310IntegrationTests {
|
||||
|
||||
@ClassRule public final static RequiresCassandraKeyspace CASSANDRA_KEYSPACE = RequiresCassandraKeyspace.onLocalhost()
|
||||
.atLeast(Version.parse("3.0"));
|
||||
|
||||
@Autowired OrderRepository repository;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
repository.deleteAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneByJsr310Types() {
|
||||
|
||||
Order order = new Order("42", LocalDate.now(), ZoneId.systemDefault());
|
||||
|
||||
repository.save(order);
|
||||
|
||||
assertThat(repository.findOrderByOrderDateAndZoneId(order.getOrderDate(), order.getZoneId()), is(equalTo(order)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneByConvertedTypes() {
|
||||
|
||||
Order order = new Order("42", LocalDate.of(2010, 1, 2), ZoneId.systemDefault());
|
||||
|
||||
repository.save(order);
|
||||
|
||||
com.datastax.driver.core.LocalDate date = com.datastax.driver.core.LocalDate.fromYearMonthDay(2010, 1, 2);
|
||||
String zoneId = order.getZoneId().getId();
|
||||
|
||||
assertThat(repository.findOrderByDate(date, zoneId), is(equalTo(order)));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-data-cassandra-examples</artifactId>
|
||||
@@ -17,7 +17,9 @@
|
||||
<inceptionYear>2014</inceptionYear>
|
||||
|
||||
<modules>
|
||||
<module>util</module>
|
||||
<module>example</module>
|
||||
<module>java8</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
@@ -27,9 +29,14 @@
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-cassandra</artifactId>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-cassandra</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.datastax.cassandra</groupId>
|
||||
<artifactId>cassandra-driver-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
22
cassandra/util/pom.xml
Normal file
22
cassandra/util/pom.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.examples</groupId>
|
||||
<artifactId>spring-data-cassandra-examples</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-data-cassandra-example-utils</artifactId>
|
||||
<name>Spring Data Cassandra - Example Utilities</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.util;
|
||||
|
||||
import org.springframework.data.util.Version;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
/**
|
||||
* Utility to retrieve the Cassandra release version.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@UtilityClass
|
||||
public class CassandraVersion {
|
||||
|
||||
/**
|
||||
* Retrieve the Cassandra release version.
|
||||
*
|
||||
* @param session must not be {@literal null}.
|
||||
* @return the release {@link Version}.
|
||||
*/
|
||||
public static Version getReleaseVersion(Session session) {
|
||||
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
|
||||
ResultSet resultSet = session.execute("SELECT release_version FROM system.local;");
|
||||
Row row = resultSet.one();
|
||||
|
||||
return Version.parse(row.getString(0));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 example.springdata.cassandra.util;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.AssumptionViolatedException;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.springframework.data.util.Version;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.NettyOptions;
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
|
||||
/**
|
||||
* Implementation of an {@link ExternalResource} to verify Apache Cassandra is running and listening on the given
|
||||
* contact point. This rule also creates a keyspace if it not exists.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class RequiresCassandraKeyspace extends ExternalResource {
|
||||
|
||||
private final int timeout = 30;
|
||||
private final String host;
|
||||
private final int port;
|
||||
private final String keyspaceName;
|
||||
private Version requiresVersion;
|
||||
|
||||
private RequiresCassandraKeyspace(String host, int port, String keyspaceName) {
|
||||
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.keyspaceName = keyspaceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require a running Cassandra instance on {@code localhost:9042}.
|
||||
*
|
||||
* @return the {@link RequiresCassandraKeyspace} rule
|
||||
*/
|
||||
public static RequiresCassandraKeyspace onLocalhost() {
|
||||
return new RequiresCassandraKeyspace("localhost", 9042, "example");
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a version requirement.
|
||||
*
|
||||
* @param version must not be {@literal null}.
|
||||
* @return the {@link RequiresCassandraKeyspace} rule
|
||||
*/
|
||||
public RequiresCassandraKeyspace atLeast(Version version) {
|
||||
|
||||
Assert.notNull(version, "Required version must not be null!");
|
||||
|
||||
this.requiresVersion = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.junit.rules.ExternalResource#before()
|
||||
*/
|
||||
@Override
|
||||
protected void before() throws Throwable {
|
||||
|
||||
try (Socket socket = new Socket()) {
|
||||
socket.setTcpNoDelay(true);
|
||||
socket.setSoLinger(true, 0);
|
||||
socket.connect(new InetSocketAddress(host, port), timeout);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new AssumptionViolatedException(String.format("Seems as Cassandra is not running at %s:%s.", host, port),
|
||||
e);
|
||||
}
|
||||
|
||||
Cluster cluster = Cluster.builder().addContactPoint(host).withPort(port).withNettyOptions(new NettyOptions() {
|
||||
@Override
|
||||
public void onClusterClose(EventLoopGroup eventLoopGroup) {
|
||||
eventLoopGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS).syncUninterruptibly();
|
||||
}
|
||||
}).build();
|
||||
|
||||
Session session = cluster.newSession();
|
||||
|
||||
try {
|
||||
|
||||
if (requiresVersion != null) {
|
||||
|
||||
Version cassandraReleaseVersion = CassandraVersion.getReleaseVersion(session);
|
||||
|
||||
if (cassandraReleaseVersion.isLessThan(requiresVersion)) {
|
||||
throw new AssumptionViolatedException(
|
||||
String.format("Cassandra at %s:%s runs in Version %s but we require at least %s", host, port,
|
||||
cassandraReleaseVersion, requiresVersion));
|
||||
}
|
||||
}
|
||||
|
||||
session.execute(String.format("CREATE KEYSPACE IF NOT EXISTS %s \n"
|
||||
+ "WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };", keyspaceName));
|
||||
} finally {
|
||||
session.close();
|
||||
cluster.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user