/*
* 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.utils.CassandraVersion;
import org.testng.annotations.Test;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import static com.datastax.driver.core.Assertions.assertThat;
import static com.datastax.driver.core.DataType.cint;
import static com.datastax.driver.core.DataType.custom;
import static com.datastax.driver.core.TestUtils.serializeForCompositeType;
import static com.datastax.driver.core.TestUtils.serializeForDynamicCompositeType;
/**
* Test we "support" custom types.
*/
public class CustomTypeTest extends CCMTestsSupport {
public static final DataType CUSTOM_DYNAMIC_COMPOSITE = custom(
"org.apache.cassandra.db.marshal.DynamicCompositeType("
+ "s=>org.apache.cassandra.db.marshal.UTF8Type,"
+ "i=>org.apache.cassandra.db.marshal.Int32Type)");
public static final DataType CUSTOM_COMPOSITE = custom(
"org.apache.cassandra.db.marshal.CompositeType("
+ "org.apache.cassandra.db.marshal.UTF8Type,"
+ "org.apache.cassandra.db.marshal.Int32Type)");
@Override
public void onTestContextInitialized() {
execute(
"CREATE TABLE test ("
+ " k int,"
+ " c1 'DynamicCompositeType(s => UTF8Type, i => Int32Type)',"
+ " c2 'ReversedType(CompositeType(UTF8Type, Int32Type))'," // reversed translates to CLUSTERING ORDER BY DESC
+ " c3 'Int32Type'," // translates to int
+ " PRIMARY KEY (k, c1, c2)"
+ ") WITH COMPACT STORAGE",
"CREATE TABLE test_collection("
+ " k int PRIMARY KEY,"
+ " c1 list<'DynamicCompositeType(s => UTF8Type, i => Int32Type)'>,"
+ " c2 map<'DynamicCompositeType(s => UTF8Type, i => Int32Type)', 'DynamicCompositeType(s => UTF8Type, i => Int32Type)'>"
+ ")"
);
}
/**
* Validates that columns using custom types are properly handled by the driver in the following ways:
* <p/>
* <ol>
* <li>The column metadata appropriately represents the types as {@link DataType#custom(String)}</li>
* <li>ReversedType is appropriately detected and the clustering order of that column is marked as descending.</li>
* <li>ColumnDefinitions for a column in a {@link Row} matches the custom type and that inserted data is read back properly.</li>
* </ol>
*
* @jira_ticket JAVA-993
* @test_category metadata
*/
@Test(groups = "short")
public void should_serialize_and_deserialize_custom_types() {
TableMetadata table = cluster().getMetadata().getKeyspace(keyspace).getTable("test");
assertThat(table.getColumn("c1")).isClusteringColumn().hasType(CUSTOM_DYNAMIC_COMPOSITE);
assertThat(table.getColumn("c2")).isClusteringColumn().hasType(CUSTOM_COMPOSITE).hasClusteringOrder(ClusteringOrder.DESC);
assertThat(table.getColumn("c3")).hasType(cint());
session().execute("INSERT INTO test(k, c1, c2, c3) VALUES (0, 's@foo:i@32', 'foo:32', 1)");
session().execute("INSERT INTO test(k, c1, c2, c3) VALUES (0, 'i@42', ':42', 2)");
session().execute("INSERT INTO test(k, c1, c2, c3) VALUES (0, 'i@12:i@3', 'foo', 3)");
ResultSet rs = session().execute("SELECT * FROM test");
Row r = rs.one();
assertThat(r.getColumnDefinitions().getType("c1")).isEqualTo(CUSTOM_DYNAMIC_COMPOSITE);
assertThat(r.getColumnDefinitions().getType("c2")).isEqualTo(CUSTOM_COMPOSITE);
assertThat(r.getColumnDefinitions().getType("c3")).isEqualTo(cint());
assertThat(r.getInt("k")).isEqualTo(0);
assertThat(r.getBytesUnsafe("c1")).isEqualTo(serializeForDynamicCompositeType(12, 3));
assertThat(r.getBytesUnsafe("c2")).isEqualTo(serializeForCompositeType("foo"));
assertThat(r.getInt("c3")).isEqualTo(3);
r = rs.one();
assertThat(r.getInt("k")).isEqualTo(0);
assertThat(r.getBytesUnsafe("c1")).isEqualTo(serializeForDynamicCompositeType(42));
assertThat(r.getBytesUnsafe("c2")).isEqualTo(serializeForCompositeType("", 42));
assertThat(r.getInt("c3")).isEqualTo(2);
r = rs.one();
assertThat(r.getInt("k")).isEqualTo(0);
assertThat(r.getBytesUnsafe("c1")).isEqualTo(serializeForDynamicCompositeType("foo", 32));
assertThat(r.getBytesUnsafe("c2")).isEqualTo(serializeForCompositeType("foo", 32));
assertThat(r.getInt("c3")).isEqualTo(1);
}
/**
* Validates that columns using collections of custom types are properly handled by the driver.
*
* @jira_ticket JAVA-1034
* @test_category metadata
*/
@Test(groups = "short")
public void should_serialize_and_deserialize_collections_of_custom_types() {
TableMetadata table = cluster().getMetadata().getKeyspace(keyspace).getTable("test_collection");
assertThat(table.getColumn("c1")).hasType(DataType.list(CUSTOM_DYNAMIC_COMPOSITE));
assertThat(table.getColumn("c2")).hasType(DataType.map(CUSTOM_DYNAMIC_COMPOSITE, CUSTOM_DYNAMIC_COMPOSITE));
session().execute("INSERT INTO test_collection(k, c1, c2) VALUES (0, [ 's@foo:i@32' ], { 's@foo:i@32': 's@bar:i@42' })");
Row r = session().execute("SELECT * FROM test_collection").one();
assertThat(r.getColumnDefinitions().getType("c1")).isEqualTo(DataType.list(CUSTOM_DYNAMIC_COMPOSITE));
List<ByteBuffer> c1 = r.getList("c1", ByteBuffer.class);
assertThat(c1.get(0)).isEqualTo(serializeForDynamicCompositeType("foo", 32));
assertThat(r.getColumnDefinitions().getType("c2")).isEqualTo(DataType.map(CUSTOM_DYNAMIC_COMPOSITE, CUSTOM_DYNAMIC_COMPOSITE));
Map<ByteBuffer, ByteBuffer> c2 = r.getMap("c2", ByteBuffer.class, ByteBuffer.class);
Map.Entry<ByteBuffer, ByteBuffer> entry = c2.entrySet().iterator().next();
assertThat(entry.getKey()).isEqualTo(serializeForDynamicCompositeType("foo", 32));
assertThat(entry.getValue()).isEqualTo(serializeForDynamicCompositeType("bar", 42));
}
/**
* Validates that UDTs with fields using custom types are properly handled by the driver in the following ways:
* <p/>
* <ol>
* <li>The {@link UserType} metadata appropriately represents the types of fields with custom types as {@link DataType#custom(String)}</li>
* <li>{@link TableMetadata} with a column having a {@link UserType} is properly referenced.</li>
* <li>ColumnDefinitions for a column in a {@link Row} matches the {@link UserType} and that inserted data is read back properly.</li>
* </ol>
*
* @jira_ticket JAVA-993
* @test_category metadata
*/
@Test(groups = "short")
@CassandraVersion("2.1.0")
public void should_handle_udt_with_custom_type() {
// Given: a UDT with custom types, and a table using it.
session().execute("CREATE TYPE custom_udt (regular int, c1 'DynamicCompositeType(s => UTF8Type, i => Int32Type)', c2 'LongType')");
session().execute("CREATE TABLE custom_udt_tbl (k int primary key, v frozen<custom_udt>)");
// When: Retrieving User Type via schema metadata.
UserType custom_udt = cluster().getMetadata().getKeyspace(keyspace).getUserType("custom_udt");
assertThat(custom_udt.getFieldType("regular")).isEqualTo(cint());
// Then: The fields with custom types should be appropriately represented with their defined types.
assertThat(custom_udt.getFieldType("c1")).isEqualTo(CUSTOM_DYNAMIC_COMPOSITE);
assertThat(custom_udt.getFieldType("c2")).isEqualTo(DataType.bigint());
// When: Retrieving Table via schema metadata.
TableMetadata table = cluster().getMetadata().getKeyspace(keyspace).getTable("custom_udt_tbl");
// Then: The column with the user type should be represented and match the type previously retrieved.
assertThat(table.getColumn("v")).hasType(custom_udt);
// Given: Existing data in table with a UDT with custom types.
session().execute("INSERT INTO custom_udt_tbl (k, v) VALUES (0, {regular: 5, c1: 's@hello:i@93', c2: 400})");
// When: Data is retrieved.
Row row = session().execute("select * from custom_udt_tbl").one();
// Then: The resulting row's column definitions should match the table definition.
assertThat(row.getColumnDefinitions().getType("k")).isEqualTo(cint());
assertThat(row.getColumnDefinitions().getType("v")).isEqualTo(custom_udt);
// And: The column values should represent what was inserted.
UDTValue value = row.getUDTValue("v");
assertThat(value.getInt("regular")).isEqualTo(5);
assertThat(value.getBytes("c1")).isEqualTo(serializeForDynamicCompositeType("hello", 93));
assertThat(value.getLong("c2")).isEqualTo(400);
}
}