/*
* Copyright (C) 2012-2015 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.driver.core;
import com.datastax.driver.core.exceptions.InvalidTypeException;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.utils.CassandraVersion;
import com.datastax.driver.core.utils.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.TypeToken;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.nio.ByteBuffer;
import java.util.*;
import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Validates that nested collections are properly encoded,
* even if some inner type requires a custom codec.
*/
@CassandraVersion("2.1.0")
public class TypeCodecNestedCollectionsIntegrationTest extends CCMTestsSupport {
private final String insertQuery = "INSERT INTO \"myTable\" (pk, v) VALUES (?, ?)";
private final String selectQuery = "SELECT pk, v FROM \"myTable\" WHERE pk = ?";
private BuiltStatement insertStmt;
private BuiltStatement selectStmt;
private int pk = 42;
private List<Set<Map<MyInt, String>>> v;
// @formatter:off
private TypeToken<List<Set<Map<MyInt, String>>>> listType = new TypeToken<List<Set<Map<MyInt, String>>>>() {};
private TypeToken<Set<Map<MyInt, String>>> elementsType = new TypeToken<Set<Map<MyInt, String>>>() {};
// @formatter:on
@Override
public void onTestContextInitialized() {
execute(
"CREATE TABLE IF NOT EXISTS \"myTable\" ("
+ "pk int PRIMARY KEY, "
+ "v frozen<list<frozen<set<frozen<map<int,text>>>>>>"
+ ")"
);
}
public Cluster.Builder createClusterBuilder() {
return Cluster.builder().withCodecRegistry(
new CodecRegistry().register(new MyIntCodec()) // global User <-> varchar codec
);
}
@BeforeClass(groups = "short")
public void setupData() {
Map<MyInt, String> map = ImmutableMap.of(new MyInt(42), "foo", new MyInt(43), "bar");
Set<Map<MyInt, String>> set = new HashSet<Map<MyInt, String>>();
set.add(map);
v = new ArrayList<Set<Map<MyInt, String>>>();
v.add(set);
}
@BeforeMethod(groups = "short")
public void createBuiltStatements() throws Exception {
insertStmt = insertInto("\"myTable\"")
.value("pk", bindMarker())
.value("v", bindMarker());
selectStmt = select("pk", "v")
.from("\"myTable\"")
.where(eq("pk", bindMarker()));
}
@Test(groups = "short")
public void should_work_with_simple_statements() {
session().execute(insertQuery, pk, v);
ResultSet rows = session().execute(selectQuery, pk);
Row row = rows.one();
assertRow(row);
}
@Test(groups = "short")
public void should_work_with_prepared_statements_1() {
session().execute(session().prepare(insertQuery).bind(pk, v));
PreparedStatement ps = session().prepare(selectQuery);
ResultSet rows = session().execute(ps.bind(pk));
Row row = rows.one();
assertRow(row);
}
@Test(groups = "short")
public void should_work_with_prepared_statements_2() {
session().execute(session().prepare(insertQuery).bind()
.setInt(0, pk)
.setList(1, v, elementsType) // variant with element type explicitly set
);
PreparedStatement ps = session().prepare(selectQuery);
ResultSet rows = session().execute(ps.bind()
.setInt(0, pk)
);
Row row = rows.one();
assertRow(row);
}
@Test(groups = "short")
public void should_work_with_prepared_statements_3() {
session().execute(session().prepare(insertQuery).bind()
.setInt(0, pk)
.set(1, v, listType)
);
PreparedStatement ps = session().prepare(selectQuery);
ResultSet rows = session().execute(ps.bind()
.setInt(0, pk)
);
Row row = rows.one();
assertRow(row);
}
@Test(groups = "short")
public void should_work_with_built_statements() {
session().execute(session().prepare(insertStmt).bind()
.setInt(0, pk)
.set(1, v, listType)
);
PreparedStatement ps = session().prepare(selectStmt);
ResultSet rows = session().execute(ps.bind()
.setInt(0, pk)
);
Row row = rows.one();
assertRow(row);
}
private void assertRow(Row row) {
assertThat(row.getList(1, elementsType)).isEqualTo(v);
assertThat(row.get(1, listType)).isEqualTo(v);
}
private class MyInt {
private final int i;
private MyInt(int i) {
this.i = i;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
MyInt myInt = (MyInt) o;
return MoreObjects.equal(i, myInt.i);
}
@Override
public int hashCode() {
return MoreObjects.hashCode(i);
}
}
private class MyIntCodec extends TypeCodec<MyInt> {
MyIntCodec() {
super(DataType.cint(), MyInt.class);
}
@Override
public ByteBuffer serialize(MyInt value, ProtocolVersion protocolVersion) throws InvalidTypeException {
return TypeCodec.cint().serialize(value.i, protocolVersion);
}
@Override
public MyInt deserialize(ByteBuffer bytes, ProtocolVersion protocolVersion) throws InvalidTypeException {
return new MyInt(TypeCodec.cint().deserialize(bytes, protocolVersion));
}
@Override
public MyInt parse(String value) throws InvalidTypeException {
return null; // not tested
}
@Override
public String format(MyInt value) throws InvalidTypeException {
return null; // not tested
}
}
}