This commit is contained in:
Timo Westkämper 2009-05-19 18:21:44 +00:00
parent 9cb530a664
commit 6ace0bf0d8
5 changed files with 193 additions and 9 deletions

View File

@ -11,7 +11,15 @@ import static com.mysema.query.collections.utils.QueryIteratorUtils.transform;
import java.io.Closeable;
import java.io.IOException;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections15.IteratorUtils;
import org.apache.commons.collections15.Predicate;
@ -23,8 +31,11 @@ import com.mysema.query.JoinExpression;
import com.mysema.query.Projectable;
import com.mysema.query.QueryBaseWithProjection;
import com.mysema.query.QueryMetadata;
import com.mysema.query.QueryModifiers;
import com.mysema.query.SearchResults;
import com.mysema.query.collections.eval.Evaluator;
import com.mysema.query.collections.iterators.FilteringMultiIterator;
import com.mysema.query.collections.iterators.LimitingIterator;
import com.mysema.query.collections.iterators.MultiIterator;
import com.mysema.query.collections.support.DefaultIndexSupport;
import com.mysema.query.collections.support.DefaultSourceSortingSupport;
@ -57,11 +68,9 @@ import com.mysema.query.util.CloseableIterator;
*/
// TODO : implement leftJoin, rightJoin and fullJoin
// TODO : implement groupBy and having
// TODO : remove close handling
public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> extends QueryBaseWithProjection<Object, SubType> implements Closeable, Projectable{
@SuppressWarnings("unchecked")
private final SubType _this = (SubType) this;
private boolean arrayProjection = false;
private boolean closed = false;
@ -188,6 +197,11 @@ public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> extends
return new DefaultIndexSupport(new SimpleIteratorSource(exprToIt), ops, sources);
}
private <RT> Iterator<RT> createPagedIterator(Expr<RT> projection) throws Exception{
Iterator<RT> iterator = createIterator(projection);
return LimitingIterator.transform(iterator, getMetadata().getModifiers());
}
private <RT> Iterator<RT> createIterator(Expr<RT> projection) throws Exception {
checkClosed();
List<Expr<?>> sources = new ArrayList<Expr<?>>();
@ -318,7 +332,6 @@ public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> extends
return it;
}
@SuppressWarnings("unchecked")
protected <RT> Iterator<RT> handleSelect(Iterator<?> it, List<Expr<?>> sources, Expr<RT> projection) throws Exception {
Iterator<RT> rv = transform(ops, it, sources, projection);
if (getMetadata().isDistinct()){
@ -335,7 +348,7 @@ public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> extends
addToProjection(projection);
try {
return asCloseableIterator(createIterator(projection));
return asCloseableIterator(createPagedIterator(projection));
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
@ -344,7 +357,7 @@ public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> extends
public <RT> CloseableIterator<RT> iterate(Expr<RT> projection) {
addToProjection(projection);
try {
return asCloseableIterator(createIterator(projection));
return asCloseableIterator(createPagedIterator(projection));
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
@ -402,4 +415,33 @@ public class AbstractColQuery<SubType extends AbstractColQuery<SubType>> extends
}
}
// TODO : optimize
public <RT> SearchResults<RT> listResults(Expr<RT> projection) {
QueryModifiers modifiers = getMetadata().getModifiers();
List<RT> list;
try {
list = IteratorUtils.toList(createIterator(projection));
}catch(Exception e){
throw new RuntimeException(e.getMessage(), e);
}
if (list.isEmpty()){
return SearchResults.emptyResults();
}else if (!modifiers.isRestricting()){
return new SearchResults<RT>(list, modifiers, list.size());
}else{
int start = 0;
int end = list.size();
if (modifiers.getOffset() != null){
if (modifiers.getOffset() < list.size()){
start = modifiers.getOffset().intValue();
}else{
return new SearchResults<RT>(Collections.<RT>emptyList(), modifiers, list.size());
}
}
if (modifiers.getLimit() != null){
end = (int)Math.min(start + modifiers.getLimit(), list.size());
}
return new SearchResults<RT>(list.subList(start, end), modifiers, list.size());
}
}
}

View File

@ -0,0 +1,59 @@
package com.mysema.query.collections.iterators;
import java.util.Iterator;
import com.mysema.commons.lang.Assert;
import com.mysema.query.QueryModifiers;
/**
* PagingIterator provides
*
* @author tiwe
* @version $Id$
*/
public class LimitingIterator<E> implements Iterator<E> {
public static <T> Iterator<T> transform(Iterator<T> iterator, QueryModifiers modifiers){
if (modifiers.isRestricting()){
if (modifiers.getOffset() != null){
int counter = 0;
while (iterator.hasNext() && counter < modifiers.getOffset()){
counter++;
iterator.next();
}
}
if (modifiers.getLimit() != null){
iterator = new LimitingIterator<T>(iterator, modifiers.getLimit());
}
}
return iterator;
}
private final Iterator<E> original;
private final long limit;
private long counter;
public LimitingIterator(Iterator<E> iterator, long limit) {
this.original = Assert.notNull(iterator);
this.limit = limit;
}
@Override
public boolean hasNext() {
return original.hasNext() && counter < limit;
}
@Override
public E next() {
counter++;
return original.next();
}
@Override
public void remove() {
}
}

View File

@ -53,8 +53,8 @@ public class CustomQueryable<SubType extends CustomQueryable<SubType>> extends P
}
protected ColQuery getInnerQuery(){
return innerQuery;
protected QueryMetadata<Object> getMetadata(){
return innerQuery.getMetadata();
}

View File

@ -0,0 +1,55 @@
package com.mysema.query.collections;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.collections15.IteratorUtils;
import org.junit.Test;
import com.mysema.query.QueryModifiers;
import com.mysema.query.SearchResults;
import com.mysema.query.grammar.GrammarWithAlias;
import com.mysema.query.grammar.types.Path.PNumber;
public class PagingTest extends AbstractQueryTest{
private List<Integer> ints = Arrays.asList(1,2,3,4,5,6,7,8,9);
private PNumber<Integer> var = GrammarWithAlias.$(0);
@Test
public void test(){
assertResultSize(9, 9, null);
assertResultSize(9, 2, new QueryModifiers(2l,null));
assertResultSize(9, 2, new QueryModifiers(2l,0l));
assertResultSize(9, 2, new QueryModifiers(2l,3l));
assertResultSize(9, 9, new QueryModifiers(20l,null));
assertResultSize(9, 9, new QueryModifiers(20l,0l));
assertResultSize(9, 5, new QueryModifiers(20l,4l));
assertResultSize(9, 0, new QueryModifiers(10l,9l));
}
private void assertResultSize(int total, int size, QueryModifiers modifiers){
// via list
assertEquals(size, createQuery(modifiers).list(var).size());
// via results
SearchResults<?> results = createQuery(modifiers).listResults(var);
assertEquals(total, results.getTotal());
assertEquals(size, results.getResults().size());
// via count (ignore limit and offset)
assertEquals(total, createQuery(modifiers).count());
// via iterator
assertEquals(size, IteratorUtils.toList(createQuery(modifiers).iterate(var)).size());
}
private ColQuery createQuery(QueryModifiers modifiers){
ColQuery query = new ColQuery().from(var, ints);
if (modifiers != null) query.restrict(modifiers);
return query;
}
}

View File

@ -0,0 +1,28 @@
package com.mysema.query.collections.iterators;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.collections15.IteratorUtils;
import org.junit.Test;
import com.mysema.query.QueryModifiers;
public class LimitingIteratorTest {
@Test
public void test(){
List<Integer> ints = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
assertEquals(Arrays.asList(1,2), transform(ints, 2l, null));
assertEquals(Arrays.asList(3,4,5), transform(ints, 3l, 2l));
assertEquals(Arrays.asList(10), transform(ints, 10l, 9l));
}
private List<Integer> transform(List<Integer> ints, Long limit, Long offset) {
QueryModifiers modifiers = new QueryModifiers(limit, offset);
return IteratorUtils.toList(LimitingIterator.transform(ints.iterator(), modifiers));
}
}