implement UDTSet test and operations

This commit is contained in:
Albert Shift 2015-04-20 21:50:15 -07:00
parent f59bf9ec2f
commit ec36db0b5f
10 changed files with 260 additions and 76 deletions

View file

@ -44,6 +44,8 @@ public abstract class AbstractSessionOperations {
abstract public Executor getExecutor();
abstract public SessionRepository getSessionRepository();
abstract public ColumnValueProvider getValueProvider();
abstract public ColumnValuePreparer getValuePreparer();

View file

@ -100,7 +100,12 @@ public final class CasserSession extends AbstractSessionOperations implements Cl
public Executor getExecutor() {
return executor;
}
@Override
public SessionRepository getSessionRepository() {
return sessionRepository;
}
@Override
public ColumnValueProvider getValueProvider() {
return valueProvider;
@ -117,7 +122,7 @@ public final class CasserSession extends AbstractSessionOperations implements Cl
ColumnValueProvider valueProvider = getValueProvider();
CasserEntity entity = Casser.entity(entityClass);
return new SelectOperation<E>(this, entity, getValueProvider(), (r) -> {
return new SelectOperation<E>(this, entity, (r) -> {
Map<String, Object> map = new ValueProviderMap(r, valueProvider, entity);
return (E) Casser.map(entityClass, map);
@ -126,25 +131,25 @@ public final class CasserSession extends AbstractSessionOperations implements Cl
}
public SelectOperation<Fun.ArrayTuple> select() {
return new SelectOperation<Fun.ArrayTuple>(this, getValueProvider());
return new SelectOperation<Fun.ArrayTuple>(this);
}
public SelectOperation<Row> selectAll(Class<?> entityClass) {
Objects.requireNonNull(entityClass, "entityClass is empty");
return new SelectOperation<Row>(this, Casser.entity(entityClass), getValueProvider());
return new SelectOperation<Row>(this, Casser.entity(entityClass));
}
public <E> SelectOperation<E> selectAll(Class<E> entityClass, Function<Row, E> rowMapper) {
Objects.requireNonNull(entityClass, "entityClass is empty");
Objects.requireNonNull(rowMapper, "rowMapper is empty");
return new SelectOperation<E>(this, Casser.entity(entityClass), getValueProvider(), rowMapper);
return new SelectOperation<E>(this, Casser.entity(entityClass), rowMapper);
}
public <V1> SelectOperation<Fun.Tuple1<V1>> select(Getter<V1> getter1) {
Objects.requireNonNull(getter1, "field 1 is empty");
CasserPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
return new SelectOperation<Tuple1<V1>>(this, getValueProvider(), new Mappers.Mapper1<V1>(getValueProvider(), p1), p1);
return new SelectOperation<Tuple1<V1>>(this, new Mappers.Mapper1<V1>(getValueProvider(), p1), p1);
}
public <V1, V2> SelectOperation<Tuple2<V1, V2>> select(Getter<V1> getter1, Getter<V2> getter2) {
@ -153,7 +158,7 @@ public final class CasserSession extends AbstractSessionOperations implements Cl
CasserPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
CasserPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
return new SelectOperation<Fun.Tuple2<V1, V2>>(this, getValueProvider(), new Mappers.Mapper2<V1, V2>(getValueProvider(), p1, p2), p1, p2);
return new SelectOperation<Fun.Tuple2<V1, V2>>(this, new Mappers.Mapper2<V1, V2>(getValueProvider(), p1, p2), p1, p2);
}
public <V1, V2, V3> SelectOperation<Fun.Tuple3<V1, V2, V3>> select(Getter<V1> getter1, Getter<V2> getter2, Getter<V3> getter3) {
@ -164,7 +169,7 @@ public final class CasserSession extends AbstractSessionOperations implements Cl
CasserPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
CasserPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
CasserPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
return new SelectOperation<Fun.Tuple3<V1, V2, V3>>(this, getValueProvider(), new Mappers.Mapper3<V1, V2, V3>(getValueProvider(), p1, p2, p3), p1, p2, p3);
return new SelectOperation<Fun.Tuple3<V1, V2, V3>>(this, new Mappers.Mapper3<V1, V2, V3>(getValueProvider(), p1, p2, p3), p1, p2, p3);
}
public <V1, V2, V3, V4> SelectOperation<Fun.Tuple4<V1, V2, V3, V4>> select(
@ -178,7 +183,7 @@ public final class CasserSession extends AbstractSessionOperations implements Cl
CasserPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
CasserPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
CasserPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
return new SelectOperation<Fun.Tuple4<V1, V2, V3, V4>>(this, getValueProvider(), new Mappers.Mapper4<V1, V2, V3, V4>(getValueProvider(), p1, p2, p3, p4), p1, p2, p3, p4);
return new SelectOperation<Fun.Tuple4<V1, V2, V3, V4>>(this, new Mappers.Mapper4<V1, V2, V3, V4>(getValueProvider(), p1, p2, p3, p4), p1, p2, p3, p4);
}
public <V1, V2, V3, V4, V5> SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>> select(
@ -194,7 +199,7 @@ public final class CasserSession extends AbstractSessionOperations implements Cl
CasserPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
CasserPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
CasserPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
return new SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>>(this, getValueProvider(),
return new SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>>(this,
new Mappers.Mapper5<V1, V2, V3, V4, V5>(getValueProvider(), p1, p2, p3, p4, p5),
p1, p2, p3, p4, p5);
}
@ -215,7 +220,7 @@ public final class CasserSession extends AbstractSessionOperations implements Cl
CasserPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
CasserPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
CasserPropertyNode p6 = MappingUtil.resolveMappingProperty(getter6);
return new SelectOperation<Tuple6<V1, V2, V3, V4, V5, V6>>(this, getValueProvider(),
return new SelectOperation<Tuple6<V1, V2, V3, V4, V5, V6>>(this,
new Mappers.Mapper6<V1, V2, V3, V4, V5, V6>(getValueProvider(), p1, p2, p3, p4, p5, p6),
p1, p2, p3, p4, p5, p6);
}
@ -240,7 +245,6 @@ public final class CasserSession extends AbstractSessionOperations implements Cl
CasserPropertyNode p6 = MappingUtil.resolveMappingProperty(getter6);
CasserPropertyNode p7 = MappingUtil.resolveMappingProperty(getter7);
return new SelectOperation<Fun.Tuple7<V1, V2, V3, V4, V5, V6, V7>>(this,
getValueProvider(),
new Mappers.Mapper7<V1, V2, V3, V4, V5, V6, V7>(
getValueProvider(),
p1, p2, p3, p4, p5, p6, p7),

View file

@ -72,15 +72,20 @@ public final class SessionInitializer extends AbstractSessionOperations {
public Executor getExecutor() {
return executor;
}
@Override
public SessionRepository getSessionRepository() {
throw new CasserException("not expected to call");
}
@Override
public ColumnValueProvider getValueProvider() {
throw new CasserException("not expected call");
throw new CasserException("not expected to call");
}
@Override
public ColumnValuePreparer getValuePreparer() {
throw new CasserException("not expected call");
throw new CasserException("not expected to call");
}
public SessionInitializer showCql() {

View file

@ -52,7 +52,6 @@ import com.noorq.casser.support.Fun.ArrayTuple;
public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, SelectOperation<E>> {
protected final ColumnValueProvider valueProvider;
protected Function<Row, E> rowMapper = null;
protected final List<CasserPropertyNode> props = new ArrayList<CasserPropertyNode>();
@ -60,15 +59,15 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
protected Integer limit = null;
protected boolean allowFiltering = false;
public SelectOperation(AbstractSessionOperations sessionOperations,
ColumnValueProvider valueProvider) {
public SelectOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations);
this.valueProvider = valueProvider;
this.rowMapper = new Function<Row, E>() {
@Override
public E apply(Row source) {
ColumnValueProvider valueProvider = sessionOps.getValueProvider();
Object[] arr = new Object[props.size()];
int i = 0;
@ -84,11 +83,9 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
}
public SelectOperation(AbstractSessionOperations sessionOperations,
CasserEntity entity,
ColumnValueProvider valueProvider) {
CasserEntity entity) {
super(sessionOperations);
this.valueProvider = valueProvider;
entity.getOrderedProperties()
.stream()
@ -99,11 +96,9 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
public SelectOperation(AbstractSessionOperations sessionOperations,
CasserEntity entity,
ColumnValueProvider valueProvider,
Function<Row, E> rowMapper) {
super(sessionOperations);
this.valueProvider = valueProvider;
this.rowMapper = rowMapper;
entity.getOrderedProperties()
@ -114,12 +109,10 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
}
public SelectOperation(AbstractSessionOperations sessionOperations,
ColumnValueProvider valueProvider,
Function<Row, E> rowMapper,
CasserPropertyNode... props) {
super(sessionOperations);
this.valueProvider = valueProvider;
this.rowMapper = rowMapper;
Collections.addAll(this.props, props);
}
@ -144,17 +137,13 @@ public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, S
Objects.requireNonNull(entityClass, "entityClass is null");
if (this.valueProvider == null) {
throw new CasserMappingException("mapTo operator is not available in current configuration");
}
CasserEntity entity = Casser.entity(entityClass);
this.rowMapper = null;
return new SelectTransformingOperation<R, E>(this, (r) -> {
Map<String, Object> map = new ValueProviderMap(r, valueProvider, entity);
Map<String, Object> map = new ValueProviderMap(r, sessionOps.getValueProvider(), entity);
return (R) Casser.map(entityClass, map);
});

View file

@ -19,19 +19,29 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.UDTValue;
import com.datastax.driver.core.UserType;
import com.datastax.driver.core.querybuilder.Assignment;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Update;
import com.google.common.collect.ImmutableSet;
import com.noorq.casser.core.AbstractSessionOperations;
import com.noorq.casser.core.Filter;
import com.noorq.casser.core.Getter;
import com.noorq.casser.core.SessionRepository;
import com.noorq.casser.core.reflect.CasserPropertyNode;
import com.noorq.casser.mapping.CasserEntity;
import com.noorq.casser.mapping.CasserProperty;
import com.noorq.casser.mapping.MappingUtil;
import com.noorq.casser.mapping.convert.EntityToUDTValueConverter;
import com.noorq.casser.mapping.type.AbstractDataType;
import com.noorq.casser.mapping.type.UDTSetDataType;
import com.noorq.casser.support.CasserMappingException;
@ -243,12 +253,19 @@ public final class UpdateOperation extends AbstractFilterOperation<ResultSet, Up
Objects.requireNonNull(value, "value is empty");
CasserPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
//Object valueObj = sessionOps.getValuePreparer().prepareColumnValue(value, p.getProperty());
CasserProperty prop = p.getProperty();
assignments.add(QueryBuilder.add(p.getColumnName(), value));
Object valueObj = value;
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
Set convertedSet = (Set) converter.get().apply(ImmutableSet.builder().add(value).build());
valueObj = convertedSet.iterator().next();
}
assignments.add(QueryBuilder.add(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
@ -258,12 +275,18 @@ public final class UpdateOperation extends AbstractFilterOperation<ResultSet, Up
Objects.requireNonNull(value, "value is empty");
CasserPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
//Object valueObj = sessionOps.getValuePreparer().prepareColumnValue(value, p.getProperty());
CasserProperty prop = p.getProperty();
assignments.add(QueryBuilder.addAll(p.getColumnName(), value));
Set valueObj = value;
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
valueObj = (Set) converter.get().apply(value);
}
assignments.add(QueryBuilder.addAll(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
@ -273,12 +296,19 @@ public final class UpdateOperation extends AbstractFilterOperation<ResultSet, Up
Objects.requireNonNull(value, "value is empty");
CasserPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
//Object valueObj = sessionOps.getValuePreparer().prepareColumnValue(value, p.getProperty());
CasserProperty prop = p.getProperty();
assignments.add(QueryBuilder.remove(p.getColumnName(), value));
Object valueObj = value;
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
Set convertedSet = (Set) converter.get().apply(ImmutableSet.builder().add(value).build());
valueObj = convertedSet.iterator().next();
}
assignments.add(QueryBuilder.remove(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}
@ -288,12 +318,18 @@ public final class UpdateOperation extends AbstractFilterOperation<ResultSet, Up
Objects.requireNonNull(value, "value is empty");
CasserPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
//Object valueObj = sessionOps.getValuePreparer().prepareColumnValue(value, p.getProperty());
CasserProperty prop = p.getProperty();
assignments.add(QueryBuilder.removeAll(p.getColumnName(), value));
Set valueObj = value;
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
valueObj = (Set) converter.get().apply(value);
}
assignments.add(QueryBuilder.removeAll(p.getColumnName(), valueObj));
addPropertyNode(p);
return this;
}

View file

@ -85,15 +85,29 @@ public class DslInvocationHandler<E> implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("toString".equals(method.getName())) {
String methodName = method.getName();
if ("equals".equals(methodName) && method.getParameterCount() == 1) {
return this == args[0];
}
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new CasserException("invalid getter method " + method);
}
if ("hashCode".equals(methodName)) {
return hashCode();
}
if ("toString".equals(methodName)) {
return entity.toString();
}
if (DslExportable.GET_ENTITY_METHOD.equals(method.getName())) {
if (DslExportable.GET_ENTITY_METHOD.equals(methodName)) {
return entity;
}
if (DslExportable.GET_PARENT_METHOD.equals(method.getName())) {
if (DslExportable.GET_PARENT_METHOD.equals(methodName)) {
return parent.get();
}

View file

@ -35,13 +35,21 @@ public class MapperInvocationHandler<E> implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if ("equals".equals(methodName) && method.getParameterCount() == 1) {
return this == args[0];
}
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new CasserException("invalid getter method " + method);
}
String methodName = method.getName();
if ("hashCode".equals(methodName)) {
return hashCode();
}
if ("toString".equals(methodName)) {
return iface.getSimpleName() + ": " + src.toString();
}

View file

@ -15,25 +15,16 @@
*/
package com.noorq.casser.mapping.convert;
import java.nio.ByteBuffer;
import java.util.function.Function;
import com.datastax.driver.core.UDTValue;
import com.datastax.driver.core.UserType;
import com.noorq.casser.core.SessionRepository;
import com.noorq.casser.mapping.CasserProperty;
import com.noorq.casser.mapping.value.UDTColumnValuePreparer;
public final class EntityToUDTValueConverter extends AbstractEntityValueWriter<UDTValue> implements Function<Object, UDTValue> {
public final class EntityToUDTValueConverter extends AbstractUDTValueWriter implements Function<Object, UDTValue> {
private final UserType userType;
private final UDTColumnValuePreparer valuePreparer;
public EntityToUDTValueConverter(Class<?> iface, UserType userType, SessionRepository repository) {
super(iface);
this.userType = userType;
this.valuePreparer = new UDTColumnValuePreparer(userType, repository);
super(iface, userType, repository);
}
@Override
@ -46,15 +37,4 @@ public final class EntityToUDTValueConverter extends AbstractEntityValueWriter<U
return outValue;
}
@Override
void writeColumn(UDTValue udtValue, Object value,
CasserProperty prop) {
ByteBuffer bytes = (ByteBuffer) valuePreparer.prepareColumnValue(value, prop);
if (bytes != null) {
udtValue.setBytesUnsafe(prop.getColumnName().getName(), bytes);
}
}
}

View file

@ -28,7 +28,7 @@ import java.util.Set;
import java.util.UUID;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.noorq.casser.core.Casser;
@ -37,12 +37,12 @@ import com.noorq.casser.test.integration.build.AbstractEmbeddedCassandraTest;
public class CollectionTest extends AbstractEmbeddedCassandraTest {
Customer customer = Casser.dsl(Customer.class);
static Customer customer = Casser.dsl(Customer.class);
CasserSession session;
static CasserSession session;
@Before
public void beforeTest() {
@BeforeClass
public static void beforeTest() {
session = Casser.init(getSession()).showCql().add(customer).autoCreateDrop().get();
}

View file

@ -15,9 +15,12 @@
*/
package com.noorq.casser.test.integration.core.udtcollection;
import static com.noorq.casser.core.Query.eq;
import java.util.HashSet;
import java.util.Set;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
@ -57,10 +60,84 @@ public class UDTCollectionTest extends AbstractEmbeddedCassandraTest {
.value(book::reviewers, reviewers)
.sync();
// READ
Book actual = session.select(Book.class).where(book::id, eq(id)).sync().findFirst().get();
Assert.assertEquals(id, actual.id());
assertEqualSets(reviewers, actual.reviewers());
// UPDATE
Set<Author> expected = new HashSet<Author>();
expected.add(new AuthorImpl("Craig", "Los Altos"));
session.update().set(book::reviewers, expected).where(book::id, eq(id)).sync();
Set<Author> actualSet = session.select(book::reviewers).where(book::id, eq(id)).sync().findFirst().get()._1;
assertEqualSets(expected, actualSet);
// add operation
expected.add(new AuthorImpl("Add", "AddCity"));
session.update().add(book::reviewers, new AuthorImpl("Add", "AddCity"))
.where(book::id, eq(id)).sync();
actualSet = session.select(book::reviewers).where(book::id, eq(id)).sync().findFirst().get()._1;
assertEqualSets(expected, actualSet);
// addAll operation
expected.addAll(reviewers);
session.update().addAll(book::reviewers, reviewers).where(book::id, eq(id)).sync();
actualSet = session.select(book::reviewers).where(book::id, eq(id)).sync().findFirst().get()._1;
assertEqualSets(expected, actualSet);
// DELETE
// remove single value
Author a = expected.stream().filter(p -> p.name().equals("Add")).findFirst().get();
expected.remove(a);
session.update().remove(book::reviewers, a).where(book::id, eq(id)).sync();
actualSet = session.select(book::reviewers).where(book::id, eq(id)).sync().findFirst().get()._1;
assertEqualSets(expected, actualSet);
// remove values
expected.remove(expected.stream().filter(p -> p.name().equals("Alex")).findFirst().get());
expected.remove(expected.stream().filter(p -> p.name().equals("Bob")).findFirst().get());
session.update().removeAll(book::reviewers, reviewers).where(book::id, eq(id)).sync();
actualSet = session.select(book::reviewers).where(book::id, eq(id)).sync().findFirst().get()._1;
assertEqualSets(expected, actualSet);
// remove full list
session.update().set(book::reviewers, null).where(book::id, eq(id)).sync();
actualSet = session.select(book::reviewers).where(book::id, eq(id)).sync().findFirst().get()._1;
Assert.assertNull(actualSet);
// remove object
session.delete().where(book::id, eq(id)).sync();
Long cnt = session.count().where(book::id, eq(id)).sync();
Assert.assertEquals(Long.valueOf(0), cnt);
}
private void assertEqualSets(Set<Author> expected, Set<Author> actual) {
Assert.assertEquals(expected.size(), actual.size());
for (Author e : expected) {
Author a = actual.stream().filter(p -> p.name().equals(e.name())).findFirst().get();
Assert.assertEquals(e.city(), a.city());
}
}
private static final class AuthorImpl implements Author {
@ -81,6 +158,42 @@ public class UDTCollectionTest extends AbstractEmbeddedCassandraTest {
public String city() {
return city;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((city == null) ? 0 : city.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AuthorImpl other = (AuthorImpl) obj;
if (city == null) {
if (other.city != null)
return false;
} else if (!city.equals(other.city))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "AuthorImpl [name=" + name + ", city=" + city + "]";
}
}
@ -103,6 +216,39 @@ public class UDTCollectionTest extends AbstractEmbeddedCassandraTest {
public int page() {
return page;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + page;
result = prime * result + ((title == null) ? 0 : title.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SectionImpl other = (SectionImpl) obj;
if (page != other.page)
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
@Override
public String toString() {
return "SectionImpl [title=" + title + ", page=" + page + "]";
}
}