/* * 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.mapping; import com.datastax.driver.core.CCMTestsSupport; import com.datastax.driver.core.Row; import com.datastax.driver.core.TypeCodec; import com.datastax.driver.core.utils.CassandraVersion; import com.datastax.driver.mapping.annotations.*; import org.testng.annotations.Test; import java.util.concurrent.atomic.AtomicInteger; import static org.assertj.core.api.Assertions.assertThat; @CassandraVersion(value = "2.1.0") public class MappingConfigurationNamingStrategyTest extends CCMTestsSupport { private static AtomicInteger counter = new AtomicInteger(0); @Override public void onTestContextInitialized() { execute("CREATE TABLE lowerlisp (\"primary-key\" int primary key, \"my-value\" int)", "CREATE TABLE uppersnake (\"PRIMARY_KEY\" int primary key, \"MY_VALUE\" int)", "CREATE TYPE \"ADDRESS\" (\"ZIP_CODE\" int, \"CITY_AND_STATE\" text)", "CREATE TABLE user (\"NAME\" text primary key, \"ADDRESS\" frozen<\"ADDRESS\">)"); } @Table(name = "lowerlisp") static class UpperSnake { @PartitionKey int PRIMARY_KEY; int MY_VALUE; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UpperSnake that = (UpperSnake) o; return PRIMARY_KEY == that.PRIMARY_KEY && MY_VALUE == that.MY_VALUE; } @Override public int hashCode() { int result = PRIMARY_KEY; result = 31 * result + MY_VALUE; return result; } } @Test(groups = "short") public void should_use_naming_strategy_fields() { // given a configuration with a java naming convention of upper snake case (i.e. HELLO_WORLD) and a // cassandra naming convention of lower lisp case (i.e. hello-world) with and access strategy of fields MappingConfiguration conf = MappingConfiguration.builder() .withPropertyMapper(new DefaultPropertyMapper() .setNamingStrategy(new DefaultNamingStrategy( NamingConventions.UPPER_SNAKE_CASE, NamingConventions.LOWER_LISP_CASE)) .setPropertyAccessStrategy(PropertyAccessStrategy.FIELDS)) .build(); MappingManager mappingManager = new MappingManager(session(), conf); // when creating a mapper // should succeed since fields match the upper snake case strategy and they are appropriately converted // to lower lisp format (PRIMARY_KEY -> primary-key, MY_VALUE -> my-value) Mapper<UpperSnake> mapper = mappingManager.mapper(UpperSnake.class); // should be able to insert and retrieve data UpperSnake in = new UpperSnake(); in.PRIMARY_KEY = counter.incrementAndGet(); in.MY_VALUE = counter.incrementAndGet(); mapper.save(in); UpperSnake out = mapper.get(in.PRIMARY_KEY); assertThat(out).isEqualTo(in); } @Table(name = "lowerlisp") static class NamingStrategyOverrideField { // Override what would be mapped to key to primary-key @PartitionKey @Column(name = "primary-key") int key; int MY_VALUE; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; NamingStrategyOverrideField that = (NamingStrategyOverrideField) o; return key == that.key && MY_VALUE == that.MY_VALUE; } @Override public int hashCode() { int result = key; result = 31 * result + MY_VALUE; return result; } } @Test(groups = "short") public void should_override_naming_strategy_with_column_annotation_name_fields() { // given a configuration with a java naming convention of upper snake case (i.e. HELLO_WORLD) and a // cassandra naming convention of lower lisp case (i.e. hello-world) with an access strategy of fields MappingConfiguration conf = MappingConfiguration.builder() .withPropertyMapper(new DefaultPropertyMapper() .setNamingStrategy(new DefaultNamingStrategy( NamingConventions.UPPER_SNAKE_CASE, NamingConventions.LOWER_LISP_CASE)) .setPropertyAccessStrategy(PropertyAccessStrategy.FIELDS)) .build(); // when creating a mapper // should succeed since fields match the upper snake case strategy and they are appropriately converted // to lower lisp format (MY_VALUE -> my-value) and since there is a @Column-annotated name override (key field // has override to 'primary-key' MappingManager mappingManager = new MappingManager(session(), conf); Mapper<NamingStrategyOverrideField> mapper = mappingManager.mapper(NamingStrategyOverrideField.class); // should be able to insert and retrieve data NamingStrategyOverrideField in = new NamingStrategyOverrideField(); in.key = counter.incrementAndGet(); in.MY_VALUE = counter.incrementAndGet(); mapper.save(in); NamingStrategyOverrideField out = mapper.get(in.key); assertThat(out).isEqualTo(in); } @Table(name = "uppersnake") @SuppressWarnings({"unused", "WeakerAccess"}) static class LowerSnake { private int _primaryKey; private int _myValue; @PartitionKey public int getprimary_key() { return _primaryKey; } public void setprimary_key(int k) { this._primaryKey = k; } public int getmy_value() { return _myValue; } public void setmy_value(int v) { this._myValue = v; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; LowerSnake that = (LowerSnake) o; return _primaryKey == that._primaryKey && _myValue == that._myValue; } @Override public int hashCode() { int result = _primaryKey; result = 31 * result + _myValue; return result; } } @Test(groups = "short") public void should_use_naming_strategy_getters_and_setters() { // given a configuration with a java naming convention of lower snake case (i.e. hello_world) and a // cassandra naming convention of upper snake case (i.e. HELLO_WORLD) with an access strategy of // getters and setters MappingConfiguration conf = MappingConfiguration.builder() .withPropertyMapper(new DefaultPropertyMapper() .setNamingStrategy(new DefaultNamingStrategy( NamingConventions.LOWER_SNAKE_CASE, NamingConventions.UPPER_SNAKE_CASE)) .setPropertyAccessStrategy(PropertyAccessStrategy.GETTERS_AND_SETTERS)) .build(); // when creating a mapper // should succeed since getters match the lower snake case strategy and they are appropriately converted // to upper snake case format (getprimary_key -> PRIMARY_KEY, getmy_value -> MY_VALUE) MappingManager mappingManager = new MappingManager(session(), conf); Mapper<LowerSnake> mapper = mappingManager.mapper(LowerSnake.class); // should be able to insert and retrieve data LowerSnake in = new LowerSnake(); in.setprimary_key(counter.incrementAndGet()); in.setmy_value(counter.incrementAndGet()); mapper.save(in); LowerSnake out = mapper.get(in.getprimary_key()); assertThat(out).isEqualTo(in); } @Table(name = "uppersnake") @SuppressWarnings({"unused", "WeakerAccess"}) static class NamingStrategyOverrideGetter { private int _primaryKey; private int _myValue; // Override column name from what would be mapped to KEY to PRIMARY_KEY @PartitionKey @Column(name = "PRIMARY_KEY", caseSensitive = true) public int getKey() { return _primaryKey; } public void setKey(int k) { this._primaryKey = k; } public int getmy_value() { return _myValue; } public void setmy_value(int v) { this._myValue = v; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; NamingStrategyOverrideGetter that = (NamingStrategyOverrideGetter) o; return _primaryKey == that._primaryKey && _myValue == that._myValue; } @Override public int hashCode() { int result = _primaryKey; result = 31 * result + _myValue; return result; } } @Test(groups = "short") public void should_override_naming_strategy_with_column_annotation_name_getters() { // given a configuration with a java naming convention of lower snake case (i.e. hello_world) and a // cassandra naming convention of upper snake case (i.e. HELLO_WORLD) with an access strategy for // getters and setters MappingConfiguration conf = MappingConfiguration.builder() .withPropertyMapper(new DefaultPropertyMapper() .setNamingStrategy(new DefaultNamingStrategy( NamingConventions.LOWER_SNAKE_CASE, NamingConventions.UPPER_SNAKE_CASE)) .setPropertyAccessStrategy(PropertyAccessStrategy.GETTERS_AND_SETTERS)) .build(); // when creating a mapper // should succeed since getters match the lower snake case strategy and they are appropriately converted // to upper snake case format (getmy_value -> MY_VALUE) and @Column-annotated name override on getKey is // PRIMARY_KEY. MappingManager mappingManager = new MappingManager(session(), conf); Mapper<NamingStrategyOverrideGetter> mapper = mappingManager.mapper(NamingStrategyOverrideGetter.class); // should be able to insert and retrieve data NamingStrategyOverrideGetter in = new NamingStrategyOverrideGetter(); in.setKey(counter.incrementAndGet()); in.setmy_value(counter.incrementAndGet()); mapper.save(in); NamingStrategyOverrideGetter out = mapper.get(in.getKey()); assertThat(out).isEqualTo(in); } @Accessor interface NamingStrategyAccessor { @Query("SELECT * from uppersnake where \"PRIMARY_KEY\" = ?") Result<NamingStrategyOverrideGetter> getValue(int key); } @Test(groups = "short") public void should_apply_naming_strategy_when_mapping_from_accessor_result() { // given a configuration with a java naming convention of lower snake case (i.e. hello_world) and a // cassandra naming convention of upper snake case (i.e. HELLO_WORLD) with an access strategy for // getters and setters MappingConfiguration conf = MappingConfiguration.builder() .withPropertyMapper(new DefaultPropertyMapper() .setNamingStrategy(new DefaultNamingStrategy( NamingConventions.LOWER_SNAKE_CASE, NamingConventions.UPPER_SNAKE_CASE)) .setPropertyAccessStrategy(PropertyAccessStrategy.GETTERS_AND_SETTERS)) .build(); MappingManager mappingManager = new MappingManager(session(), conf); Mapper<NamingStrategyOverrideGetter> mapper = mappingManager.mapper(NamingStrategyOverrideGetter.class); NamingStrategyAccessor acc = mappingManager.createAccessor(NamingStrategyAccessor.class); NamingStrategyOverrideGetter in = new NamingStrategyOverrideGetter(); in.setKey(counter.incrementAndGet()); in.setmy_value(counter.incrementAndGet()); mapper.save(in); Result<NamingStrategyOverrideGetter> out = acc.getValue(in.getKey()); assertThat(out.one()).isEqualTo(in); } @UDT(name = "ADDRESS", caseSensitiveType = true) static class Address { int zip_code; @Field(name = "CITY_AND_STATE", caseSensitive = true) String cityAndState; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Address address = (Address) o; return zip_code == address.zip_code && (cityAndState != null ? cityAndState.equals(address.cityAndState) : address.cityAndState == null); } @Override public int hashCode() { int result = zip_code; result = 31 * result + (cityAndState != null ? cityAndState.hashCode() : 0); return result; } } @Table(name = "user") static class User { @PartitionKey String name; Address address; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return (name != null ? name.equals(user.name) : user.name == null) && (address != null ? address.equals(user.address) : user.address == null); } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (address != null ? address.hashCode() : 0); return result; } } @Test(groups = "short") public void should_apply_naming_strategy_to_udts() { // given a configuration with a java naming convention of lower snake case (i.e. hello_world) and a // cassandra naming convention of upper snake case (i.e. HELLO_WORLD) with an access strategy for // fields MappingConfiguration conf = MappingConfiguration.builder() .withPropertyMapper(new DefaultPropertyMapper() .setNamingStrategy(new DefaultNamingStrategy( NamingConventions.LOWER_SNAKE_CASE, NamingConventions.UPPER_SNAKE_CASE)) .setPropertyAccessStrategy(PropertyAccessStrategy.FIELDS)) .build(); MappingManager mappingManager = new MappingManager(session(), conf); // when creating a mapper // should succeed since fields match the lower snake case strategy and they are appropriately converted for // both the table (User) and the underlying UDT (Address) Mapper<User> mapper = mappingManager.mapper(User.class); // insert user w/ address Address address = new Address(); address.zip_code = 90210; address.cityAndState = "Beverly Hills, CA"; User user = new User(); user.name = "John Doe"; user.address = address; mapper.save(user); // retrieve user w/ address and ensure it matches the input. User out = mapper.get(user.name); assertThat(out).isEqualTo(user); // should be able to use udtCodec to get a codec back that is capable of converting a retrieved // udt column value into an Address object and it should match the input. TypeCodec<Address> addressCodec = mappingManager.udtCodec(Address.class); Row row = session().execute("select \"ADDRESS\" from user where \"NAME\" = 'John Doe'").one(); Address outAddress = row.get(0, addressCodec); assertThat(outAddress).isEqualTo(address); } }