BAEL-4971 - Object mapping with Cassandra (#13427)
* BAEL-4971 - Object mapping with Cassandra * BAEL-4971 - Object mapping with Cassandra * BAEL-4971 - Object mapping with Cassandra - changing test name * BAEL-4971 - Object mapping with Cassandra - code formatting * BAEL-4971 - Object mapping with Cassandra - review incorporation
This commit is contained in:
parent
8f2e92dacb
commit
639de9687e
|
@ -60,8 +60,32 @@
|
||||||
<version>${system.stubs.version}</version>
|
<version>${system.stubs.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.datastax.oss</groupId>
|
||||||
|
<artifactId>java-driver-mapper-runtime</artifactId>
|
||||||
|
<version>4.15.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<configuration>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>com.datastax.oss</groupId>
|
||||||
|
<artifactId>java-driver-mapper-processor</artifactId>
|
||||||
|
<version>4.15.0</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>11</java.version>
|
<java.version>11</java.version>
|
||||||
<org.springframework.data.version>3.1.11</org.springframework.data.version>
|
<org.springframework.data.version>3.1.11</org.springframework.data.version>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.baeldung.objectmapper;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class CassandraMapperApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(CassandraMapperApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package org.baeldung.objectmapper;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.DaoFactory;
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.DaoKeyspace;
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.Mapper;
|
||||||
|
import org.baeldung.objectmapper.dao.CounterDao;
|
||||||
|
import org.baeldung.objectmapper.dao.UserDao;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface DaoMapper {
|
||||||
|
|
||||||
|
@DaoFactory
|
||||||
|
UserDao getUserDao(@DaoKeyspace CqlIdentifier keyspace);
|
||||||
|
|
||||||
|
@DaoFactory
|
||||||
|
CounterDao getUserCounterDao(@DaoKeyspace CqlIdentifier keyspace);
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.baeldung.objectmapper.dao;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.Dao;
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.Increment;
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.Select;
|
||||||
|
import org.baeldung.objectmapper.entity.Counter;
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
public interface CounterDao {
|
||||||
|
|
||||||
|
@Increment(entityClass = Counter.class)
|
||||||
|
void incrementCounter(String id, long count);
|
||||||
|
|
||||||
|
@Select
|
||||||
|
Counter getCounterById(String id);
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package org.baeldung.objectmapper.dao;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.core.PagingIterable;
|
||||||
|
import com.datastax.oss.driver.api.core.cql.BoundStatement;
|
||||||
|
import com.datastax.oss.driver.api.core.cql.Row;
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.*;
|
||||||
|
import org.baeldung.objectmapper.entity.User;
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
public interface UserDao {
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
void insertUser(User user);
|
||||||
|
|
||||||
|
@Select
|
||||||
|
User getUserById(int id);
|
||||||
|
|
||||||
|
@Select
|
||||||
|
PagingIterable<User> getAllUsers();
|
||||||
|
|
||||||
|
@Update
|
||||||
|
void updateUser(User user);
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
void deleteUser(User user);
|
||||||
|
|
||||||
|
@GetEntity
|
||||||
|
User getUser(Row row);
|
||||||
|
|
||||||
|
@SetEntity
|
||||||
|
BoundStatement setUser(BoundStatement udtValue, User user);
|
||||||
|
|
||||||
|
@Query(value = "select * from user_profile where user_age > :userAge ALLOW FILTERING")
|
||||||
|
PagingIterable<User> getUsersOlderThanAge(int userAge);
|
||||||
|
|
||||||
|
@QueryProvider(providerClass = UserQueryProvider.class, entityHelpers = User.class, providerMethod = "getUsersOlderThanAge")
|
||||||
|
PagingIterable<User> getUsersOlderThan(String age);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.baeldung.objectmapper.dao;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.core.CqlSession;
|
||||||
|
import com.datastax.oss.driver.api.core.PagingIterable;
|
||||||
|
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||||
|
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||||
|
import com.datastax.oss.driver.api.mapper.MapperContext;
|
||||||
|
import com.datastax.oss.driver.api.mapper.entity.EntityHelper;
|
||||||
|
import com.datastax.oss.driver.api.querybuilder.QueryBuilder;
|
||||||
|
import org.baeldung.objectmapper.entity.User;
|
||||||
|
|
||||||
|
public class UserQueryProvider {
|
||||||
|
|
||||||
|
private final CqlSession session;
|
||||||
|
private final EntityHelper<User> userHelper;
|
||||||
|
|
||||||
|
public UserQueryProvider(MapperContext context, EntityHelper<User> userHelper) {
|
||||||
|
this.session = context.getSession();
|
||||||
|
this.userHelper = userHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PagingIterable<User> getUsersOlderThanAge(String age) {
|
||||||
|
SimpleStatement statement = QueryBuilder.selectFrom("user_profile")
|
||||||
|
.all()
|
||||||
|
.whereColumn("user_age")
|
||||||
|
.isGreaterThan(QueryBuilder
|
||||||
|
.bindMarker(age))
|
||||||
|
.build();
|
||||||
|
PreparedStatement preparedSelectUser = session.prepare(statement);
|
||||||
|
return session
|
||||||
|
.execute(preparedSelectUser.getQuery())
|
||||||
|
.map(result -> userHelper.get(result, true));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.baeldung.objectmapper.entity;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.CqlName;
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.Entity;
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.HierarchyScanStrategy;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@CqlName("admin_profile")
|
||||||
|
@HierarchyScanStrategy(highestAncestor = User.class, includeHighestAncestor = true)
|
||||||
|
public class Admin extends User {
|
||||||
|
private String role;
|
||||||
|
private String department;
|
||||||
|
|
||||||
|
public String getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(String role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDepartment() {
|
||||||
|
return department;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDepartment(String department) {
|
||||||
|
this.department = department;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.baeldung.objectmapper.entity;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.Entity;
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.PartitionKey;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Counter {
|
||||||
|
|
||||||
|
@PartitionKey
|
||||||
|
private String id;
|
||||||
|
private long count;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCount(long count) {
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package org.baeldung.objectmapper.entity;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.mapper.annotations.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@CqlName("user_profile")
|
||||||
|
public class User {
|
||||||
|
@PartitionKey
|
||||||
|
private int id;
|
||||||
|
@CqlName("username")
|
||||||
|
private String userName;
|
||||||
|
@ClusteringColumn
|
||||||
|
private int userAge;
|
||||||
|
|
||||||
|
@Computed("writetime(userName)")
|
||||||
|
private long writetime;
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(int id, String userName, int userAge) {
|
||||||
|
this.id = id;
|
||||||
|
this.userName = userName;
|
||||||
|
this.userAge = userAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserName(String userName) {
|
||||||
|
this.userName = userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUserAge() {
|
||||||
|
return userAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserAge(int userAge) {
|
||||||
|
this.userAge = userAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getWritetime() {
|
||||||
|
return writetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWritetime(long writetime) {
|
||||||
|
this.writetime = writetime;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
package org.baeldung.objectmapper;
|
||||||
|
|
||||||
|
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||||
|
import com.datastax.oss.driver.api.core.CqlSession;
|
||||||
|
import org.baeldung.objectmapper.dao.CounterDao;
|
||||||
|
import org.baeldung.objectmapper.dao.UserDao;
|
||||||
|
import org.baeldung.objectmapper.entity.Counter;
|
||||||
|
import org.baeldung.objectmapper.entity.User;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Testcontainers
|
||||||
|
@SpringBootTest
|
||||||
|
public class MapperLiveTest {
|
||||||
|
|
||||||
|
private static final String KEYSPACE_NAME = "baeldung";
|
||||||
|
|
||||||
|
@Container
|
||||||
|
private static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2")
|
||||||
|
.withExposedPorts(9042);
|
||||||
|
|
||||||
|
static void setupCassandraConnectionProperties() {
|
||||||
|
System.setProperty("spring.data.cassandra.keyspace-name", KEYSPACE_NAME);
|
||||||
|
System.setProperty("spring.data.cassandra.contact-points", cassandra.getContainerIpAddress());
|
||||||
|
System.setProperty("spring.data.cassandra.port", String.valueOf(cassandra.getMappedPort(9042)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static UserDao userDao;
|
||||||
|
static CounterDao counterDao;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void setup() {
|
||||||
|
setupCassandraConnectionProperties();
|
||||||
|
CqlSession session = CqlSession.builder().build();
|
||||||
|
|
||||||
|
String createKeyspace = "CREATE KEYSPACE IF NOT EXISTS baeldung " +
|
||||||
|
"WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};";
|
||||||
|
String useKeyspace = "USE baeldung;";
|
||||||
|
String createUserTable = "CREATE TABLE IF NOT EXISTS user_profile " +
|
||||||
|
"(id int, username text, user_age int, writetime bigint, PRIMARY KEY (id, user_age)) " +
|
||||||
|
"WITH CLUSTERING ORDER BY (user_age DESC);";
|
||||||
|
String createAdminTable = "CREATE TABLE IF NOT EXISTS admin_profile " +
|
||||||
|
"(id int, username text, user_age int, role text, writetime bigint, department text, " +
|
||||||
|
"PRIMARY KEY (id, user_age)) " +
|
||||||
|
"WITH CLUSTERING ORDER BY (user_age DESC);";
|
||||||
|
String createCounter = "CREATE TABLE IF NOT EXISTS counter " +
|
||||||
|
"(id text, count counter, PRIMARY KEY (id));";
|
||||||
|
|
||||||
|
session.execute(createKeyspace);
|
||||||
|
session.execute(useKeyspace);
|
||||||
|
session.execute(createUserTable);
|
||||||
|
session.execute(createAdminTable);
|
||||||
|
session.execute(createCounter);
|
||||||
|
|
||||||
|
DaoMapper mapper = new DaoMapperBuilder(session).build();
|
||||||
|
userDao = mapper.getUserDao(CqlIdentifier.fromCql("baeldung"));
|
||||||
|
counterDao = mapper.getUserCounterDao(CqlIdentifier.fromCql("baeldung"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenUser_whenInsert_thenRetrievedDuringGet() {
|
||||||
|
User user = new User(1, "JohnDoe", 31);
|
||||||
|
userDao.insertUser(user);
|
||||||
|
User retrievedUser = userDao.getUserById(1);
|
||||||
|
Assertions.assertEquals(retrievedUser.getUserName(), user.getUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenCounter_whenIncrement_thenIncremented() {
|
||||||
|
Counter users = counterDao.getCounterById("users");
|
||||||
|
long initialCount = users != null ? users.getCount(): 0;
|
||||||
|
|
||||||
|
counterDao.incrementCounter("users", 1);
|
||||||
|
|
||||||
|
users = counterDao.getCounterById("users");
|
||||||
|
long finalCount = users != null ? users.getCount(): 0;
|
||||||
|
|
||||||
|
Assertions.assertEquals(finalCount - initialCount, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenUser_whenGetUsersOlderThan_thenRetrieved() {
|
||||||
|
User user = new User(2, "JaneDoe", 20);
|
||||||
|
userDao.insertUser(user);
|
||||||
|
List<User> retrievedUsers = userDao.getUsersOlderThanAge(30).all();
|
||||||
|
Assertions.assertEquals(retrievedUsers.size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue