/*
* Copyright 2016-2017 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 org.springframework.data.cassandra.convert;
import static org.assertj.core.api.Assertions.*;
import static org.junit.Assume.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.UUID;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.cassandra.test.integration.AbstractKeyspaceCreatingIntegrationTest;
import org.springframework.cassandra.test.integration.support.CassandraVersion;
import org.springframework.data.annotation.Id;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.cassandra.domain.AllPossibleTypes;
import org.springframework.data.cassandra.test.integration.support.SchemaTestUtils;
import org.springframework.data.util.Version;
import com.datastax.driver.core.Duration;
import com.datastax.driver.core.LocalDate;
import com.datastax.driver.core.SimpleStatement;
/**
* Integration tests for type mapping using {@link CassandraOperations}.
*
* @author Mark Paluch
* @soundtrack DJ THT meets Scarlet - Live 2 Dance (Extended Mix) (Zgin Remix)
*/
@SuppressWarnings("Since15")
public class CassandraTypeMappingIntegrationTest extends AbstractKeyspaceCreatingIntegrationTest {
static final Version VERSION_3_10 = Version.parse("3.10");
CassandraOperations operations;
Version cassandraVersion;
@Before
public void before() {
operations = new CassandraTemplate(session);
cassandraVersion = CassandraVersion.get(session);
SchemaTestUtils.potentiallyCreateTableFor(AllPossibleTypes.class, operations);
SchemaTestUtils.potentiallyCreateTableFor(TimeEntity.class, operations);
SchemaTestUtils.truncate(AllPossibleTypes.class, operations);
SchemaTestUtils.truncate(TimeEntity.class, operations);
if (cassandraVersion.isGreaterThanOrEqualTo(VERSION_3_10)) {
SchemaTestUtils.potentiallyCreateTableFor(WithDuration.class, operations);
SchemaTestUtils.truncate(WithDuration.class, operations);
}
}
@Test // DATACASS-280
public void shouldReadAndWriteInetAddress() throws Exception {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setInet(InetAddress.getByName("127.0.0.1"));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getInet()).isEqualTo(entity.getInet());
}
@Test // DATACASS-280
public void shouldReadAndWriteUUID() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setUuid(UUID.randomUUID());
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getUuid()).isEqualTo(entity.getUuid());
}
@Test // DATACASS-280
public void shouldReadAndWriteBoxedShort() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBoxedShort(Short.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBoxedShort()).isEqualTo(entity.getBoxedShort());
}
@Test // DATACASS-280
public void shouldReadAndWritePrimitiveShort() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setPrimitiveShort(Short.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getPrimitiveShort()).isEqualTo(entity.getPrimitiveShort());
}
@Test // DATACASS-271
public void shouldReadAndWriteBoxedByte() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBoxedByte(Byte.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBoxedByte()).isEqualTo(entity.getBoxedByte());
}
@Test // DATACASS-271
public void shouldReadAndWritePrimitiveByte() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setPrimitiveByte(Byte.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getPrimitiveByte()).isEqualTo(entity.getPrimitiveByte());
}
@Test // DATACASS-280
public void shouldReadAndWriteBoxedLong() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBoxedLong(Long.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBoxedLong()).isEqualTo(entity.getBoxedLong());
}
@Test // DATACASS-280
public void shouldReadAndWritePrimitiveLong() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setPrimitiveLong(Long.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getPrimitiveLong()).isEqualTo(entity.getPrimitiveLong());
}
@Test // DATACASS-280
public void shouldReadAndWriteBoxedInteger() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBoxedInteger(Integer.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBoxedInteger()).isEqualTo(entity.getBoxedInteger());
}
@Test // DATACASS-280
public void shouldReadAndWritePrimitiveInteger() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setPrimitiveInteger(Integer.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getPrimitiveInteger()).isEqualTo(entity.getPrimitiveInteger());
}
@Test // DATACASS-280
public void shouldReadAndWriteBoxedFloat() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBoxedFloat(Float.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBoxedFloat()).isEqualTo(entity.getBoxedFloat());
}
@Test // DATACASS-280
public void shouldReadAndWritePrimitiveFloat() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setPrimitiveFloat(Float.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getPrimitiveFloat()).isEqualTo(entity.getPrimitiveFloat());
}
@Test // DATACASS-280
public void shouldReadAndWriteBoxedDouble() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBoxedDouble(Double.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBoxedDouble()).isEqualTo(entity.getBoxedDouble());
}
@Test // DATACASS-280
public void shouldReadAndWritePrimitiveDouble() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setPrimitiveDouble(Double.MAX_VALUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getPrimitiveDouble()).isEqualTo(entity.getPrimitiveDouble());
}
@Test // DATACASS-280
public void shouldReadAndWriteBoxedBoolean() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBoxedBoolean(Boolean.TRUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBoxedBoolean()).isEqualTo(entity.getBoxedBoolean());
}
@Test // DATACASS-280
public void shouldReadAndWritePrimitiveBoolean() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setPrimitiveBoolean(Boolean.TRUE);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.isPrimitiveBoolean()).isEqualTo(entity.isPrimitiveBoolean());
}
@Test // DATACASS-280, DATACASS-271
public void shouldReadAndWriteTimestamp() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setTimestamp(new Date(1));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getTimestamp()).isEqualTo(entity.getTimestamp());
}
@Test // DATACASS-271
public void shouldReadAndWriteDate() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setDate(LocalDate.fromDaysSinceEpoch(1));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getDate()).isEqualTo(entity.getDate());
}
@Test // DATACASS-280
public void shouldReadAndWriteBigInteger() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBigInteger(new BigInteger("123456"));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBigInteger()).isEqualTo(entity.getBigInteger());
}
@Test // DATACASS-280
public void shouldReadAndWriteBigDecimal() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBigDecimal(new BigDecimal("123456.7890123"));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBigDecimal()).isEqualTo(entity.getBigDecimal());
}
@Test // DATACASS-280
public void shouldReadAndWriteBlob() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBlob(ByteBuffer.wrap("Hello".getBytes()));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
ByteBuffer blob = loaded.getBlob();
byte[] bytes = new byte[blob.remaining()];
blob.get(bytes);
assertThat(new String(bytes)).isEqualTo("Hello");
}
@Test // DATACASS-280
public void shouldReadAndWriteSetOfString() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setSetOfString(Collections.singleton("hello"));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getSetOfString()).isEqualTo(entity.getSetOfString());
}
@Test // DATACASS-280
public void shouldReadAndWriteEmptySetOfString() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setSetOfString(new HashSet<>());
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getSetOfString()).isNull();
}
@Test // DATACASS-280
public void shouldReadAndWriteListOfString() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setListOfString(Collections.singletonList("hello"));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getListOfString()).isEqualTo(entity.getListOfString());
}
@Test // DATACASS-280
public void shouldReadAndWriteEmptyListOfString() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setListOfString(new ArrayList<>());
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getListOfString()).isNull();
}
@Test // DATACASS-280
public void shouldReadAndWriteMapOfString() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setMapOfString(Collections.singletonMap("hello", "world"));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getMapOfString()).isEqualTo(entity.getMapOfString());
}
@Test // DATACASS-280
public void shouldReadAndWriteEmptyMapOfString() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setMapOfString(new HashMap<>());
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getMapOfString()).isNull();
}
@Test // DATACASS-280
public void shouldReadAndWriteEnum() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setAnEnum(Condition.MINT);
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
Assertions.assertThat(loaded.getAnEnum()).isEqualTo(entity.getAnEnum());
}
@Test // DATACASS-280
public void shouldReadAndWriteListOfEnum() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setListOfEnum(Collections.singletonList(Condition.MINT));
operations.insert(entity);
AllPossibleTypes loaded = operations.selectOneById(entity.getId(), AllPossibleTypes.class);
assertThat(loaded.getListOfEnum()).contains(Condition.MINT);
}
@Test // DATACASS-280
public void shouldReadAndWriteSetOfEnum() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setSetOfEnum(Collections.singleton(Condition.MINT));
operations.insert(entity);
AllPossibleTypes loaded = operations.selectOneById(entity.getId(), AllPossibleTypes.class);
assertThat(loaded.getSetOfEnum()).contains(Condition.MINT);
}
@Test // DATACASS-271
public void shouldReadAndWriteTime() {
// writing of time is not supported with Insert/Update statements as they mix up types.
// The only way to insert a time right now seems a PreparedStatement
String id = "1";
long time = 21312214L;
operations.getCqlOperations()
.execute(new SimpleStatement("INSERT INTO timeentity (id, time) values(?,?)", id, time));
TimeEntity loaded = operations.selectOneById(id, TimeEntity.class);
assertThat(loaded.getTime()).isEqualTo(time);
}
@Test // DATACASS-296
public void shouldReadAndWriteLocalDate() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setLocalDate(java.time.LocalDate.of(2010, 7, 4));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getLocalDate()).isEqualTo(entity.getLocalDate());
}
@Test // DATACASS-296
public void shouldReadAndWriteLocalDateTime() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setLocalDateTime(java.time.LocalDateTime.of(2010, 7, 4, 1, 2, 3));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getLocalDateTime()).isEqualTo(entity.getLocalDateTime());
}
@Test // DATACASS-296
public void shouldReadAndWriteLocalTime() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setLocalTime(java.time.LocalTime.of(1, 2, 3));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getLocalTime()).isEqualTo(entity.getLocalTime());
}
@Test // DATACASS-296
public void shouldReadAndWriteInstant() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setInstant(java.time.Instant.now());
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getInstant()).isEqualTo(entity.getInstant());
}
@Test // DATACASS-296
public void shouldReadAndWriteZoneId() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setZoneId(java.time.ZoneId.of("Europe/Paris"));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getZoneId()).isEqualTo(entity.getZoneId());
}
@Test // DATACASS-296
public void shouldReadAndWriteJodaLocalDate() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setJodaLocalDate(new org.joda.time.LocalDate(2010, 7, 4));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getJodaLocalDate()).isEqualTo(entity.getJodaLocalDate());
}
@Test // DATACASS-296
public void shouldReadAndWriteJodaDateTime() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setJodaDateTime(new org.joda.time.DateTime(2010, 7, 4, 1, 2, 3));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getJodaDateTime()).isEqualTo(entity.getJodaDateTime());
}
@Test // DATACASS-296
public void shouldReadAndWriteBpLocalDate() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBpLocalDate(org.threeten.bp.LocalDate.of(2010, 7, 4));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBpLocalDate()).isEqualTo(entity.getBpLocalDate());
}
@Test // DATACASS-296
public void shouldReadAndWriteBpLocalDateTime() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBpLocalDateTime(org.threeten.bp.LocalDateTime.of(2010, 7, 4, 1, 2, 3));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBpLocalDateTime()).isEqualTo(entity.getBpLocalDateTime());
}
@Test // DATACASS-296
public void shouldReadAndWriteBpLocalTime() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBpLocalTime(org.threeten.bp.LocalTime.of(1, 2, 3));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBpLocalTime()).isEqualTo(entity.getBpLocalTime());
}
@Test // DATACASS-296
public void shouldReadAndWriteBpInstant() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBpInstant(org.threeten.bp.Instant.now());
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBpZoneId()).isEqualTo(entity.getBpZoneId());
}
@Test // DATACASS-296
public void shouldReadAndWriteBpZoneId() {
AllPossibleTypes entity = new AllPossibleTypes("1");
entity.setBpZoneId(org.threeten.bp.ZoneId.of("Europe/Paris"));
operations.insert(entity);
AllPossibleTypes loaded = load(entity);
assertThat(loaded.getBpZoneId()).isEqualTo(entity.getBpZoneId());
}
@Test // DATACASS-285
@Ignore("Counter columns are not supported with Spring Data Cassandra as the value of counter columns can only be incremented/decremented, not set")
public void shouldReadAndWriteCounter() {
CounterEntity entity = new CounterEntity("1");
entity.setCount(1);
operations.update(entity);
CounterEntity loaded = operations.selectOneById(entity.getId(), CounterEntity.class);
assertThat(loaded.getCount()).isEqualTo(entity.getCount());
}
@Test // DATACASS-429
public void shouldReadAndWriteDuration() {
assumeTrue(cassandraVersion.isGreaterThanOrEqualTo(VERSION_3_10));
WithDuration withDuration = new WithDuration("foo", Duration.from("2h"));
operations.insert(withDuration);
WithDuration loaded = operations.selectOneById(withDuration.getId(), WithDuration.class);
assertThat(loaded.getDuration()).isEqualTo(withDuration.getDuration());
}
private AllPossibleTypes load(AllPossibleTypes entity) {
return operations.selectOneById(entity.getId(), AllPossibleTypes.class);
}
public enum Condition {
MINT
}
@Data
@AllArgsConstructor
static class WithDuration {
@Id String id;
Duration duration;
}
}