diff --git a/persistence-modules/spring-data-cassandra-2/pom.xml b/persistence-modules/spring-data-cassandra-2/pom.xml index 740c04d2a0..01b5ce5ed6 100644 --- a/persistence-modules/spring-data-cassandra-2/pom.xml +++ b/persistence-modules/spring-data-cassandra-2/pom.xml @@ -65,6 +65,18 @@ java-driver-mapper-runtime 4.15.0 + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + @@ -88,10 +100,10 @@ 11 - 3.1.11 - 1.15.3 + 3.4.15 + 1.19.0 1.1.0 - 5.6.2 + 5.9.3 \ No newline at end of file diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/CassandraApplication.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/CassandraApplication.java new file mode 100644 index 0000000000..ecc50cbf40 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/CassandraApplication.java @@ -0,0 +1,12 @@ +package org.baeldung.cassandra.inquery; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CassandraApplication { + + public static void main(String[] args) { + SpringApplication.run(CassandraApplication.class, args); + } +} diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/model/Product.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/model/Product.java new file mode 100644 index 0000000000..c9007e8405 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/model/Product.java @@ -0,0 +1,49 @@ +package org.baeldung.cassandra.inquery.model; + +import org.springframework.data.cassandra.core.cql.PrimaryKeyType; +import org.springframework.data.cassandra.core.mapping.Column; +import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; +import org.springframework.data.cassandra.core.mapping.Table; + +import java.util.Objects; +import java.util.UUID; + +@Table +public class Product { + + @PrimaryKeyColumn(name = "product_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED) + private UUID productId; + + @PrimaryKeyColumn(name = "product_name", ordinal = 1, type = PrimaryKeyType.CLUSTERED) + private String productName; + + @Column("description") + private String description; + + @Column("price") + private double price; + + public Product(UUID productId, String productName, String description, double price) { + this.productId = productId; + this.productName = productName; + this.description = description; + this.price = price; + } + + public String getProductName() { + return productName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Product product = (Product) o; + return productId.equals(product.productId) && productName.equals(product.productName); + } + + @Override + public int hashCode() { + return Objects.hash(productId, productName); + } +} diff --git a/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/repository/ProductRepository.java b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/repository/ProductRepository.java new file mode 100644 index 0000000000..176ca4d786 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/main/java/org/baeldung/cassandra/inquery/repository/ProductRepository.java @@ -0,0 +1,20 @@ +package org.baeldung.cassandra.inquery.repository; + +import org.baeldung.cassandra.inquery.model.Product; +import org.springframework.data.cassandra.repository.CassandraRepository; +import org.springframework.data.cassandra.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.UUID; + +@Repository +public interface ProductRepository extends CassandraRepository { + + @Query("select * from product where product_id in :productIds") + List findByProductIds(@Param("productIds") List productIds); + + @Query("select * from product where product_id = :productId and product_name in :productNames") + List findByProductIdAndNames(@Param("productId") UUID productId, @Param("productNames") List productNames); +} diff --git a/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java new file mode 100644 index 0000000000..3d2433814e --- /dev/null +++ b/persistence-modules/spring-data-cassandra-2/src/test/java/org/baeldung/cassandra/inquery/ProductRepositoryNestedLiveTest.java @@ -0,0 +1,115 @@ +package org.baeldung.cassandra.inquery; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.utils.UUIDs; +import org.baeldung.cassandra.inquery.model.Product; +import org.baeldung.cassandra.inquery.repository.ProductRepository; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.testcontainers.containers.CassandraContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + + +@Testcontainers +@SpringBootTest +class ProductRepositoryIntegrationTest { + + private static final String KEYSPACE_NAME = "mynamespace"; + + @Container + private static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2") + .withExposedPorts(9042); + + @BeforeAll + static void setupCassandraConnectionProperties() { + System.setProperty("spring.data.cassandra.keyspace-name", KEYSPACE_NAME); + System.setProperty("spring.data.cassandra.contact-points", cassandra.getHost()); + System.setProperty("spring.data.cassandra.port", String.valueOf(cassandra.getMappedPort(9042))); + createKeyspace(cassandra.getCluster()); + } + + static void createKeyspace(Cluster cluster) { + try (Session session = cluster.connect()) { + session.execute("CREATE KEYSPACE IF NOT EXISTS " + KEYSPACE_NAME + " WITH replication = \n" + + "{'class':'SimpleStrategy','replication_factor':'1'};"); + } + } + + @Nested + class ApplicationContextLiveTest { + @Test + void givenCassandraContainer_whenSpringContextIsBootstrapped_thenContainerIsRunningWithNoExceptions() { + assertThat(cassandra.isRunning()).isTrue(); + } + } + + @Nested + class ProductRepositoryLiveTest { + + @Autowired + private ProductRepository productRepository; + + @Test + void givenValidProductsIsFetched_whenFindByProductIdsIsCalled_thenProductIsReturned() { + UUID productId1 = UUIDs.timeBased(); + UUID productId2 = UUIDs.timeBased(); + UUID productId3 = UUIDs.timeBased(); + Product product1 = new Product(productId1, "Apple", "Apple v1", 12.5); + Product product2 = new Product(productId2, "Apple v2", "Apple v2", 15.5); + Product product3 = new Product(productId3, "Banana", "Banana v1", 5.5); + Product product4 = new Product(productId3, "Banana v2", "Banana v2", 15.5); + + productRepository.saveAll(List.of(product1, product2, product3, product4)); + + List existingProducts = productRepository.findByProductIds(List.of(productId1, productId2)); + assertEquals(2, existingProducts.size()); + assertTrue(existingProducts.contains(product1)); + assertTrue(existingProducts.contains(product2)); + } + + @Test + void givenExistingProducts_whenFindByIdAndNamesIsCalled_thenProductIsReturned() { + UUID productId1 = UUIDs.timeBased(); + UUID productId2 = UUIDs.timeBased(); + Product product1 = new Product(productId1, "Apple", "Apple v1", 12.5); + Product product2 = new Product(productId1, "Apple v2", "Apple v2", 15.5); + Product product3 = new Product(productId2, "Banana", "Banana v1", 5.5); + Product product4 = new Product(productId2, "Banana v2", "Banana v2", 15.5); + + productRepository.saveAll(List.of(product1, product2, product3, product4)); + + List existingProducts = productRepository.findByProductIdAndNames(productId1, + List.of(product1.getProductName(), product2.getProductName())); + assertEquals(2, existingProducts.size()); + assertTrue(existingProducts.contains(product1)); + assertTrue(existingProducts.contains(product2)); + } + + @Test + void givenNonExistingProductName_whenFindByIdAndNamesIsCalled_thenProductIsReturned() { + UUID productId1 = UUIDs.timeBased(); + UUID productId2 = UUIDs.timeBased(); + Product product1 = new Product(productId1, "Apple", "Apple v1", 12.5); + Product product2 = new Product(productId1, "Apple v2", "Apple v2", 15.5); + Product product3 = new Product(productId2, "Banana", "Banana v1", 5.5); + Product product4 = new Product(productId2, "Banana v2", "Banana v2", 15.5); + + productRepository.saveAll(List.of(product1, product2, product4)); + + List existingProducts = productRepository.findByProductIdAndNames(productId1, + List.of(product3.getProductName())); + assertEquals(0, existingProducts.size()); + } + } +}