diff --git a/querydsl-core/src/main/java/com/mysema/query/group/AbstractGroupColumnDefinition.java b/querydsl-core/src/main/java/com/mysema/query/group/AbstractGroupColumnDefinition.java deleted file mode 100644 index 8f384d3f8..000000000 --- a/querydsl-core/src/main/java/com/mysema/query/group/AbstractGroupColumnDefinition.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2011 Mysema Ltd. - * All rights reserved. - * - */ -package com.mysema.query.group; - -import com.mysema.query.types.Expression; - -/** - * A base class for GroupColumnDefinitions - * @author sasa - * - * @param - * @param - */ -public abstract class AbstractGroupColumnDefinition implements GroupColumnDefinition { - - private final Expression expr; - - public AbstractGroupColumnDefinition(Expression expr) { - this.expr = expr; - } - - @Override - public Expression getExpression() { - return expr; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "(" + expr + ")"; - } -} \ No newline at end of file diff --git a/querydsl-core/src/main/java/com/mysema/query/group/Group.java b/querydsl-core/src/main/java/com/mysema/query/group/Group.java index 7999f2780..6a6406cd1 100644 --- a/querydsl-core/src/main/java/com/mysema/query/group/Group.java +++ b/querydsl-core/src/main/java/com/mysema/query/group/Group.java @@ -7,26 +7,81 @@ package com.mysema.query.group; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; import com.mysema.query.types.Expression; /** + * A group of rows. Group is build according to GroupDefinitions. + * * @author sasa * */ public interface Group { + /** + * @return Groups elements as an array + */ Object[] toArray(); - R getGroup(GroupColumnDefinition coldef); + /** + * Returns the value of the given group. + * + * @param Type of element in a single ResultSet row, i.e. type of Expression<T> + * @param Target type of this group, e.g. List<T> + * @param coldef + * @throws NoSuchElementException if group is undefined. + * @throws ClassCastException if group is of different type + * @return Value of given group definition in this group + */ + R getGroup(GroupDefinition coldef); + /** + * Returns the value of the given single valued expression. This is the + * first value of given column within this group of the ResultSet. + * + * @param Value type + * @param expr Grouped expression + * @throws NoSuchElementException if group is undefined. + * @throws ClassCastException if group is of different type (e.g. Set) + * @return Value of given expression in this group + */ T getOne(Expression expr); + /** + * Returns a Set of values in this group. + * + * @param Value type of Set + * @param expr Grouped expression + * @throws NoSuchElementException if group is undefined. + * @throws ClassCastException if group is of different type (e.g. List) + * @return Set of values in this group + */ Set getSet(Expression expr); + /** + * Returns a List of values in this group. + * + * @param Value type of List + * @param expr Grouped expression + * @throws NoSuchElementException if group is undefined. + * @throws ClassCastException if group is of different type (e.g. Set) + * @return List of values in this group + */ List getList(Expression expr); + /** + * Returns a Map of values in this group + * + * @param Key type of result Map + * @param Value type of result Map + * @param key Key expression + * @param value Value expression + * @throws NoSuchElementException if group is undefined. + * @throws ClassCastException if group is of different type (e.g. List) + * @return Map of values in this group + */ Map getMap(Expression key, Expression value); } \ No newline at end of file diff --git a/querydsl-core/src/main/java/com/mysema/query/group/GroupBy.java b/querydsl-core/src/main/java/com/mysema/query/group/GroupBy.java index 43041ff84..48424bea7 100644 --- a/querydsl-core/src/main/java/com/mysema/query/group/GroupBy.java +++ b/querydsl-core/src/main/java/com/mysema/query/group/GroupBy.java @@ -32,19 +32,24 @@ import com.mysema.query.types.Expression; *
  • Group of null is handled correctly * * + * Results can be analyzed, filtered and transformed using GroupProcessor for stateless processors + * and GroupProcessorFactory for stateful processors. + * + * There exists + * * @author sasa */ public class GroupBy implements ResultTransformer> { - private static class GList extends AbstractGroupColumnDefinition>{ + private static class GList extends AbstractGroupDefinition>{ public GList(Expression expr) { super(expr); } @Override - public GroupColumn> createGroupColumn() { - return new GroupColumn>() { + public GroupCollector> createGroupCollector() { + return new GroupCollector>() { private final List list = new ArrayList(); @@ -63,15 +68,15 @@ public class GroupBy implements ResultTransformer> { } } - private static class GMap extends AbstractGroupColumnDefinition, Map>{ + private static class GMap extends AbstractGroupDefinition, Map>{ public GMap(QPair qpair) { super(qpair); } @Override - public GroupColumn> createGroupColumn() { - return new GroupColumn>() { + public GroupCollector> createGroupCollector() { + return new GroupCollector>() { private final Map set = new LinkedHashMap(); @@ -91,15 +96,15 @@ public class GroupBy implements ResultTransformer> { } } - private static class GOne extends AbstractGroupColumnDefinition{ + private static class GOne extends AbstractGroupDefinition{ public GOne(Expression expr) { super(expr); } @Override - public GroupColumn createGroupColumn() { - return new GroupColumn() { + public GroupCollector createGroupCollector() { + return new GroupCollector() { private boolean first = true; private T val; @@ -123,26 +128,26 @@ public class GroupBy implements ResultTransformer> { private class GroupImpl implements Group { - private final Map, GroupColumn> groupColumns = new LinkedHashMap, GroupColumn>(); + private final Map, GroupCollector> groupCollectors = new LinkedHashMap, GroupCollector>(); public GroupImpl() { for (int i=0; i < columnDefinitions.size(); i++) { - GroupColumnDefinition coldef = columnDefinitions.get(i); - groupColumns.put(coldef.getExpression(), coldef.createGroupColumn()); + GroupDefinition coldef = columnDefinitions.get(i); + groupCollectors.put(coldef.getExpression(), coldef.createGroupCollector()); } } void add(Object[] row) { int i=0; - for (GroupColumn groupColumn : groupColumns.values()) { - groupColumn.add(row[i]); + for (GroupCollector groupCollector : groupCollectors.values()) { + groupCollector.add(row[i]); i++; } } @SuppressWarnings("unchecked") private R get(Expression expr) { - GroupColumn col = (GroupColumn) groupColumns.get(expr); + GroupCollector col = (GroupCollector) groupCollectors.get(expr); if (col != null) { return col.get(); } @@ -151,12 +156,12 @@ public class GroupBy implements ResultTransformer> { @Override @SuppressWarnings("unchecked") - public R getGroup(GroupColumnDefinition definition) { - Iterator> iter = groupColumns.values().iterator(); - for (GroupColumnDefinition def : columnDefinitions) { - GroupColumn groupColumn = iter.next(); + public R getGroup(GroupDefinition definition) { + Iterator> iter = groupCollectors.values().iterator(); + for (GroupDefinition def : columnDefinitions) { + GroupCollector groupCollector = iter.next(); if (def.equals(definition)) { - return (R) groupColumn.get(); + return (R) groupCollector.get(); } } throw new NoSuchElementException(definition.toString()); @@ -171,7 +176,7 @@ public class GroupBy implements ResultTransformer> { public Map getMap(Expression key, Expression value) { for (QPair pair : maps) { if (pair.equals(key, value)) { - return (Map) groupColumns.get(pair).get(); + return (Map) groupCollectors.get(pair).get(); } } throw new NoSuchElementException("GMap(" + key + ", " + value + ")"); @@ -189,8 +194,8 @@ public class GroupBy implements ResultTransformer> { @Override public Object[] toArray() { - List arr = new ArrayList(groupColumns.size()); - for (GroupColumn col : groupColumns.values()) { + List arr = new ArrayList(groupCollectors.size()); + for (GroupCollector col : groupCollectors.values()) { arr.add(col.get()); } return arr.toArray(); @@ -198,7 +203,7 @@ public class GroupBy implements ResultTransformer> { } - private static class GSet extends AbstractGroupColumnDefinition>{ + private static class GSet extends AbstractGroupDefinition>{ public GSet(Expression expr) { super(expr); @@ -206,8 +211,8 @@ public class GroupBy implements ResultTransformer> { @Override @SuppressWarnings("unchecked") - public GroupColumn> createGroupColumn() { - return new GroupColumn>() { + public GroupCollector> createGroupCollector() { + return new GroupCollector>() { private final Set set = new LinkedHashSet(); @@ -233,7 +238,7 @@ public class GroupBy implements ResultTransformer> { return new GroupBy(expr, first, rest); } - protected final List> columnDefinitions; + protected final List> columnDefinitions; private final GroupProcessor> defaultProcessor = new GroupProcessor>() { @@ -248,13 +253,25 @@ public class GroupBy implements ResultTransformer> { } }; - private final List> maps; + protected final List> maps; + /** + * Group ResultSet rows by the value of given expression. + * + * @param groupBy + */ public GroupBy(Expression groupBy) { - this(new ArrayList>(), new ArrayList>()); + this(new ArrayList>(), new ArrayList>()); withGroup(new GOne(groupBy)); } + /** + * Group ResultSet rows by the value of given expression. + * + * @param groupBy + * @param first One-valued expression + * @param rest More one-valued expressions + */ public GroupBy(Expression groupBy, Expression first, Expression... rest) { this(groupBy); withOne(first); @@ -263,20 +280,33 @@ public class GroupBy implements ResultTransformer> { } } - public GroupBy(Expression groupBy, GroupColumnDefinition group, GroupColumnDefinition... groups) { + /** + * Group ResultSet rows by the value of given expression. + * + * @param groupBy + * @param group + * @param groups + */ + public GroupBy(Expression groupBy, GroupDefinition group, GroupDefinition... groups) { this(groupBy); withGroup(group); - for (GroupColumnDefinition g : groups) { + for (GroupDefinition g : groups) { withGroup(g); } } - protected GroupBy(List> columnDefinitions, List> maps) { + /** + * A constructor that allows cloning in sub classes. + * + * @param columnDefinitions + * @param maps + */ + protected GroupBy(List> columnDefinitions, List> maps) { this.columnDefinitions = columnDefinitions; this.maps = maps; } - public List> getColumnDefinitions() { + public List> getColumnDefinitions() { return Collections.unmodifiableList(columnDefinitions); } @@ -323,37 +353,96 @@ public class GroupBy implements ResultTransformer> { return process(projectable, defaultProcessor); } - public GroupBy withGroup(GroupColumnDefinition g) { - columnDefinitions.add(g); + /** + * A way to project custom group types. + * + * @param groupDefinition Custom group definition + * @return + */ + public GroupBy withGroup(GroupDefinition groupDefinition) { + Assert.notNull(groupDefinition, "groupDefinition"); + + columnDefinitions.add(groupDefinition); return this; } + /** + * Values of given expression in all rows belonging to this group as List. + * + * @param + * @param expr + * @return + */ public GroupBy withList(Expression expr) { return withGroup(new GList(expr)); } + /** + * Map of given expressions in all rows belonging to this group as Map. + * + * @param + * @param + * @param key + * @param value + * @return + */ public GroupBy withMap(Expression key, Expression value) { QPair qpair = new QPair(key, value); maps.add(qpair); return withGroup(new GMap(qpair)); } + /** + * Value of given expression in the first row belonging to this group. + * + * @param + * @param expr + * @return + */ public GroupBy withOne(Expression expr) { return withGroup(new GOne(expr)); } + /** + * Process results with a stateful processor created by given processorFactory. + * + * @param + * @param processorFactory + * @return + */ public ProcessorGroupBy withProcessor(GroupProcessorFactory processorFactory) { return ProcessorGroupBy.create(this, processorFactory); } + /** + * Process results with the given stateless processor. + * + * @param + * @param processor + * @return + */ public ProcessorGroupBy withProcessor(GroupProcessor processor) { return ProcessorGroupBy.create(this, processor); } + /** + * Values of given expression in all rows belonging to this group as Set. + * + * @param + * @param expr + * @return + */ public GroupBy withSet(Expression expr) { return withGroup(new GSet(expr)); } + /** + * Transforms results using given transformer. + * + * @param + * @param transformer Stateless Map transformer + * @return + */ public ProcessorGroupBy withTransformer(final Transformer, W> transformer) { return withProcessor(new GroupProcessor() { @@ -370,6 +459,13 @@ public class GroupBy implements ResultTransformer> { }); } + /** + * Transforms Map values with given transformer. + * + * @param + * @param transformer Stateless Group transformer + * @return + */ public ProcessorGroupBy> withValueTransformer(final Transformer transformer) { return withTransformer(new Transformer, Map>() { diff --git a/querydsl-core/src/main/java/com/mysema/query/group/GroupColumn.java b/querydsl-core/src/main/java/com/mysema/query/group/GroupColumn.java deleted file mode 100644 index c6db27fd6..000000000 --- a/querydsl-core/src/main/java/com/mysema/query/group/GroupColumn.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2011 Mysema Ltd. - * All rights reserved. - * - */ -package com.mysema.query.group; - -/** - * - * @author sasa - * @param - */ -public interface GroupColumn { - - void add(Object o); - - R get(); - -} \ No newline at end of file diff --git a/querydsl-core/src/main/java/com/mysema/query/group/GroupColumnDefinition.java b/querydsl-core/src/main/java/com/mysema/query/group/GroupColumnDefinition.java deleted file mode 100644 index be4dface1..000000000 --- a/querydsl-core/src/main/java/com/mysema/query/group/GroupColumnDefinition.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2011 Mysema Ltd. - * All rights reserved. - * - */ -package com.mysema.query.group; - -import com.mysema.query.types.Expression; - -/** - * Defines the way results of a given expression are grouped. - * - * @author sasa - * - * @param Expression type - * @param Target type (e.g. T, Set<T> or List<T>) - */ -public interface GroupColumnDefinition { - - Expression getExpression(); - - GroupColumn createGroupColumn(); - -} \ No newline at end of file diff --git a/querydsl-core/src/main/java/com/mysema/query/group/GroupProcessor.java b/querydsl-core/src/main/java/com/mysema/query/group/GroupProcessor.java index 7c8af5512..37c21ebe8 100644 --- a/querydsl-core/src/main/java/com/mysema/query/group/GroupProcessor.java +++ b/querydsl-core/src/main/java/com/mysema/query/group/GroupProcessor.java @@ -21,6 +21,12 @@ import org.apache.commons.collections15.Transformer; */ public interface GroupProcessor extends Transformer, O> { + /** + * Analyze the given row. + * + * @param row + * @return true if row is accepted, false if rejected + */ boolean accept(Object[] row); } diff --git a/querydsl-core/src/main/java/com/mysema/query/group/GroupProcessorFactory.java b/querydsl-core/src/main/java/com/mysema/query/group/GroupProcessorFactory.java index 3a938ce48..461bad037 100644 --- a/querydsl-core/src/main/java/com/mysema/query/group/GroupProcessorFactory.java +++ b/querydsl-core/src/main/java/com/mysema/query/group/GroupProcessorFactory.java @@ -18,6 +18,6 @@ import java.util.List; */ public interface GroupProcessorFactory { - public GroupProcessor createProcessor(List> columnDefinitions); + public GroupProcessor createProcessor(List> columnDefinitions); } diff --git a/querydsl-core/src/main/java/com/mysema/query/group/ProcessorGroupBy.java b/querydsl-core/src/main/java/com/mysema/query/group/ProcessorGroupBy.java index 00991993d..5675da484 100644 --- a/querydsl-core/src/main/java/com/mysema/query/group/ProcessorGroupBy.java +++ b/querydsl-core/src/main/java/com/mysema/query/group/ProcessorGroupBy.java @@ -7,6 +7,7 @@ package com.mysema.query.group; import java.util.List; +import com.mysema.commons.lang.Assert; import com.mysema.query.Projectable; import com.mysema.query.ResultTransformer; @@ -36,7 +37,7 @@ public class ProcessorGroupBy implements ResultTransformer { this(groupBy, new GroupProcessorFactory() { @Override - public GroupProcessor createProcessor(List> columnDefinitions) { + public GroupProcessor createProcessor(List> columnDefinitions) { return processor; } @@ -44,6 +45,9 @@ public class ProcessorGroupBy implements ResultTransformer { } public ProcessorGroupBy(GroupBy groupBy, GroupProcessorFactory processorFactory) { + Assert.notNull(groupBy, "groupBy"); + Assert.notNull(processorFactory, "processorFactory"); + this.groupBy = groupBy; this.processorFactory = processorFactory; } diff --git a/querydsl-core/src/main/java/com/mysema/query/group/QPair.java b/querydsl-core/src/main/java/com/mysema/query/group/QPair.java index f4b9be377..a44c30a98 100644 --- a/querydsl-core/src/main/java/com/mysema/query/group/QPair.java +++ b/querydsl-core/src/main/java/com/mysema/query/group/QPair.java @@ -8,6 +8,7 @@ package com.mysema.query.group; import java.util.Arrays; import java.util.List; +import com.mysema.commons.lang.Assert; import com.mysema.commons.lang.Pair; import com.mysema.query.types.Expression; import com.mysema.query.types.ExpressionBase; @@ -36,6 +37,10 @@ public final class QPair extends ExpressionBase> implements Fac @SuppressWarnings({ "rawtypes", "unchecked" }) public QPair(Expression key, Expression value) { super((Class) Pair.class); + + Assert.notNull(key, "key"); + Assert.notNull(value, "value"); + this.key = key; this.value = value; } diff --git a/querydsl-core/src/main/java/com/mysema/query/group/ValueTransformerMap.java b/querydsl-core/src/main/java/com/mysema/query/group/ValueTransformerMap.java index 1f56373ff..7081cc24b 100644 --- a/querydsl-core/src/main/java/com/mysema/query/group/ValueTransformerMap.java +++ b/querydsl-core/src/main/java/com/mysema/query/group/ValueTransformerMap.java @@ -14,6 +14,8 @@ import org.apache.commons.collections15.Transformer; import org.apache.commons.collections15.collection.TransformedCollection; import org.apache.commons.collections15.set.TransformedSet; +import com.mysema.commons.lang.Assert; + /** * A read-only view of underlying map with values transformed by a given Transformer. * @@ -34,6 +36,9 @@ public class ValueTransformerMap extends AbstractMap { } public ValueTransformerMap(Map map, Transformer transformer) { + Assert.notNull(map, "map"); + Assert.notNull(transformer, "transformer"); + this.map = map; this.transformer = transformer; } diff --git a/querydsl-core/src/test/java/com/mysema/query/group/GroupByTest.java b/querydsl-core/src/test/java/com/mysema/query/group/GroupByTest.java index ff015b58c..a5a17fe52 100644 --- a/querydsl-core/src/test/java/com/mysema/query/group/GroupByTest.java +++ b/querydsl-core/src/test/java/com/mysema/query/group/GroupByTest.java @@ -10,6 +10,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; import org.apache.commons.collections15.Transformer; @@ -40,11 +41,11 @@ public class GroupByTest { private static final StringExpression commentText = new StringPath("commentText"); - private static final GroupColumnDefinition constant = new AbstractGroupColumnDefinition(commentId) { + private static final GroupDefinition constant = new AbstractGroupDefinition(commentId) { @Override - public GroupColumn createGroupColumn() { - return new GroupColumn() { + public GroupCollector createGroupCollector() { + return new GroupCollector() { @Override public void add(Object o) { @@ -213,6 +214,26 @@ public class GroupByTest { assertEquals("constant", group.getGroup(constant)); } + @Test(expected=NoSuchElementException.class) + public void NoSuchElementException() { + Map results = + GroupBy.create(postId).withOne(postName).withSet(commentId).withList(commentText) + .transform(BASIC_RESULTS); + + Group group = results.get(1); + group.getSet(qComment); + } + + @Test(expected=ClassCastException.class) + public void ClassCastException() { + Map results = + GroupBy.create(postId).withOne(postName).withSet(commentId).withList(commentText) + .transform(BASIC_RESULTS); + + Group group = results.get(1); + group.getList(commentId); + } + @Test public void Map() { Map results =