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>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.datastax.oss</groupId>
|
||||
<artifactId>java-driver-mapper-runtime</artifactId>
|
||||
<version>4.15.0</version>
|
||||
</dependency>
|
||||
</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>
|
||||
<java.version>11</java.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