blob: 6bcbde6ffff05f7194b8eb8df7888ccdeda8273d [file]
/*
* Copyright DataStax, Inc.
*
* 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 com.datastax.oss.driver.mapper;
import static org.assertj.core.api.Assertions.assertThat;
import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import com.datastax.oss.driver.api.core.data.GettableByName;
import com.datastax.oss.driver.api.mapper.annotations.Dao;
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.Entity;
import com.datastax.oss.driver.api.mapper.annotations.GetEntity;
import com.datastax.oss.driver.api.mapper.annotations.Insert;
import com.datastax.oss.driver.api.mapper.annotations.Mapper;
import com.datastax.oss.driver.api.mapper.annotations.PartitionKey;
import com.datastax.oss.driver.api.mapper.annotations.Select;
import com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy;
import com.datastax.oss.driver.api.testinfra.CassandraRequirement;
import com.datastax.oss.driver.api.testinfra.ccm.CcmRule;
import com.datastax.oss.driver.api.testinfra.session.SessionRule;
import com.datastax.oss.driver.categories.ParallelizableTests;
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList;
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
/** Tests that entities with UDTs nested at various levels are properly mapped. */
@Category(ParallelizableTests.class)
@CassandraRequirement(min = "2.2", description = "support for unset values")
public class NestedUdtIT {
private static final CcmRule CCM_RULE = CcmRule.getInstance();
private static final SessionRule<CqlSession> SESSION_RULE = SessionRule.builder(CCM_RULE).build();
@ClassRule
public static final TestRule CHAIN = RuleChain.outerRule(CCM_RULE).around(SESSION_RULE);
private static UUID CONTAINER_ID = UUID.randomUUID();
private static final Container SAMPLE_CONTAINER =
new Container(
CONTAINER_ID,
ImmutableList.of(new Type1("a"), new Type1("b")),
ImmutableMap.of(
"cd",
ImmutableList.of(new Type1("c"), new Type1("d")),
"ef",
ImmutableList.of(new Type1("e"), new Type1("f"))),
ImmutableMap.of(
new Type1("12"),
ImmutableSet.of(ImmutableList.of(new Type2(1)), ImmutableList.of(new Type2(2)))),
ImmutableMap.of(
new Type1("12"), ImmutableMap.of("12", ImmutableSet.of(new Type2(1), new Type2(2)))));
private static final Container SAMPLE_CONTAINER_NULL_LIST =
new Container(
CONTAINER_ID,
null,
ImmutableMap.of(
"cd",
ImmutableList.of(new Type1("c"), new Type1("d")),
"ef",
ImmutableList.of(new Type1("e"), new Type1("f"))),
ImmutableMap.of(
new Type1("12"),
ImmutableSet.of(ImmutableList.of(new Type2(1)), ImmutableList.of(new Type2(2)))),
ImmutableMap.of(
new Type1("12"), ImmutableMap.of("12", ImmutableSet.of(new Type2(1), new Type2(2)))));
private static ContainerDao containerDao;
@BeforeClass
public static void setup() {
CqlSession session = SESSION_RULE.session();
for (String query :
ImmutableList.of(
"CREATE TYPE type1(s text)",
"CREATE TYPE type2(i int)",
"CREATE TABLE container(id uuid PRIMARY KEY, "
+ "list frozen<list<type1>>, "
+ "map1 frozen<map<text, list<type1>>>, "
+ "map2 frozen<map<type1, set<list<type2>>>>,"
+ "map3 frozen<map<type1, map<text, set<type2>>>>"
+ ")")) {
session.execute(
SimpleStatement.builder(query).setExecutionProfile(SESSION_RULE.slowProfile()).build());
}
UdtsMapper udtsMapper = new NestedUdtIT_UdtsMapperBuilder(session).build();
containerDao = udtsMapper.containerDao(SESSION_RULE.keyspace());
}
@Before
public void clearContainerData() {
CqlSession session = SESSION_RULE.session();
session.execute(
SimpleStatement.builder("TRUNCATE container")
.setExecutionProfile(SESSION_RULE.slowProfile())
.build());
}
@Test
public void should_insert_and_retrieve_entity_with_nested_udts() {
// When
containerDao.save(SAMPLE_CONTAINER);
Container retrievedEntity = containerDao.loadByPk(SAMPLE_CONTAINER.getId());
// Then
assertThat(retrievedEntity).isEqualTo(SAMPLE_CONTAINER);
}
@Test
public void should_insert_do_not_set_to_null_udts() {
// Given
containerDao.save(SAMPLE_CONTAINER);
Container retrievedEntity = containerDao.loadByPk(SAMPLE_CONTAINER.getId());
assertThat(retrievedEntity.list).isNotNull();
// When
containerDao.saveDoNotSetNull(SAMPLE_CONTAINER_NULL_LIST);
Container retrievedEntitySecond = containerDao.loadByPk(SAMPLE_CONTAINER.getId());
assertThat(retrievedEntitySecond.list).isNotNull();
}
@Test
public void should_insert_set_to_null_udts() {
// Given
containerDao.save(SAMPLE_CONTAINER);
Container retrievedEntity = containerDao.loadByPk(SAMPLE_CONTAINER.getId());
assertThat(retrievedEntity.list).isNotNull();
// When
containerDao.saveSetToNull(SAMPLE_CONTAINER_NULL_LIST);
Container retrievedEntitySecond = containerDao.loadByPk(SAMPLE_CONTAINER.getId());
assertThat(retrievedEntitySecond.list).isEmpty();
}
@Mapper
public interface UdtsMapper {
@DaoFactory
ContainerDao containerDao(@DaoKeyspace CqlIdentifier keyspace);
}
@Dao
public interface ContainerDao {
@Select
Container loadByPk(UUID id);
@Insert
void save(Container container);
@Insert(nullSavingStrategy = NullSavingStrategy.DO_NOT_SET)
void saveDoNotSetNull(Container container);
@Insert(nullSavingStrategy = NullSavingStrategy.SET_TO_NULL)
void saveSetToNull(Container container);
@GetEntity
Container get(GettableByName source);
}
@Entity
public static class Container {
@PartitionKey private UUID id;
private List<Type1> list;
private Map<String, List<Type1>> map1;
private Map<Type1, Set<List<Type2>>> map2;
private Map<Type1, Map<String, Set<Type2>>> map3;
public Container() {}
public Container(
UUID id,
List<Type1> list,
Map<String, List<Type1>> map1,
Map<Type1, Set<List<Type2>>> map2,
Map<Type1, Map<String, Set<Type2>>> map3) {
this.id = id;
this.list = list;
this.map1 = map1;
this.map2 = map2;
this.map3 = map3;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public List<Type1> getList() {
return list;
}
public void setList(List<Type1> list) {
this.list = list;
}
public Map<String, List<Type1>> getMap1() {
return map1;
}
public void setMap1(Map<String, List<Type1>> map1) {
this.map1 = map1;
}
public Map<Type1, Set<List<Type2>>> getMap2() {
return map2;
}
public void setMap2(Map<Type1, Set<List<Type2>>> map2) {
this.map2 = map2;
}
public Map<Type1, Map<String, Set<Type2>>> getMap3() {
return map3;
}
public void setMap3(Map<Type1, Map<String, Set<Type2>>> map3) {
this.map3 = map3;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other instanceof Container) {
Container that = (Container) other;
return Objects.equals(this.id, that.id)
&& Objects.equals(this.list, that.list)
&& Objects.equals(this.map1, that.map1)
&& Objects.equals(this.map2, that.map2)
&& Objects.equals(this.map3, that.map3);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hash(id, list, map1, map2, map3);
}
}
@Entity
public static class Type1 {
private String s;
public Type1() {}
public Type1(String s) {
this.s = s;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other instanceof Type1) {
Type1 that = (Type1) other;
return Objects.equals(this.s, that.s);
} else {
return false;
}
}
@Override
public int hashCode() {
return s == null ? 0 : s.hashCode();
}
}
@Entity
public static class Type2 {
private int i;
public Type2() {}
public Type2(int i) {
this.i = i;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other instanceof Type2) {
Type2 that = (Type2) other;
return this.i == that.i;
} else {
return false;
}
}
@Override
public int hashCode() {
return i;
}
}
}