From 6ace0bf0d8723f267453a000bab4c2cb24c282e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Westk=C3=A4mper?= Date: Tue, 19 May 2009 18:21:44 +0000 Subject: [PATCH] --- .../query/collections/AbstractColQuery.java | 56 +++++++++++++++--- .../iterators/LimitingIterator.java | 59 +++++++++++++++++++ .../collections/support/CustomQueryable.java | 4 +- .../mysema/query/collections/PagingTest.java | 55 +++++++++++++++++ .../iterators/LimitingIteratorTest.java | 28 +++++++++ 5 files changed, 193 insertions(+), 9 deletions(-) create mode 100644 querydsl-collections/src/main/java/com/mysema/query/collections/iterators/LimitingIterator.java create mode 100644 querydsl-collections/src/test/java/com/mysema/query/collections/PagingTest.java create mode 100644 querydsl-collections/src/test/java/com/mysema/query/collections/iterators/LimitingIteratorTest.java diff --git a/querydsl-collections/src/main/java/com/mysema/query/collections/AbstractColQuery.java b/querydsl-collections/src/main/java/com/mysema/query/collections/AbstractColQuery.java index c2f58de98..dc51ec7c4 100644 --- a/querydsl-collections/src/main/java/com/mysema/query/collections/AbstractColQuery.java +++ b/querydsl-collections/src/main/java/com/mysema/query/collections/AbstractColQuery.java @@ -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> extends QueryBaseWithProjection 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> extends return new DefaultIndexSupport(new SimpleIteratorSource(exprToIt), ops, sources); } + private Iterator createPagedIterator(Expr projection) throws Exception{ + Iterator iterator = createIterator(projection); + return LimitingIterator.transform(iterator, getMetadata().getModifiers()); + } + private Iterator createIterator(Expr projection) throws Exception { checkClosed(); List> sources = new ArrayList>(); @@ -318,7 +332,6 @@ public class AbstractColQuery> extends return it; } - @SuppressWarnings("unchecked") protected Iterator handleSelect(Iterator it, List> sources, Expr projection) throws Exception { Iterator rv = transform(ops, it, sources, projection); if (getMetadata().isDistinct()){ @@ -335,7 +348,7 @@ public class AbstractColQuery> 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> extends public CloseableIterator iterate(Expr 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> extends } } + // TODO : optimize + public SearchResults listResults(Expr projection) { + QueryModifiers modifiers = getMetadata().getModifiers(); + List 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(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(Collections.emptyList(), modifiers, list.size()); + } + } + if (modifiers.getLimit() != null){ + end = (int)Math.min(start + modifiers.getLimit(), list.size()); + } + return new SearchResults(list.subList(start, end), modifiers, list.size()); + } + } } diff --git a/querydsl-collections/src/main/java/com/mysema/query/collections/iterators/LimitingIterator.java b/querydsl-collections/src/main/java/com/mysema/query/collections/iterators/LimitingIterator.java new file mode 100644 index 000000000..4f57bfbdd --- /dev/null +++ b/querydsl-collections/src/main/java/com/mysema/query/collections/iterators/LimitingIterator.java @@ -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 implements Iterator { + + public static Iterator transform(Iterator 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(iterator, modifiers.getLimit()); + } + } + return iterator; + } + + private final Iterator original; + + private final long limit; + + private long counter; + + public LimitingIterator(Iterator 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() { + + } + +} diff --git a/querydsl-collections/src/main/java/com/mysema/query/collections/support/CustomQueryable.java b/querydsl-collections/src/main/java/com/mysema/query/collections/support/CustomQueryable.java index 1806d6bb8..bf8fda019 100644 --- a/querydsl-collections/src/main/java/com/mysema/query/collections/support/CustomQueryable.java +++ b/querydsl-collections/src/main/java/com/mysema/query/collections/support/CustomQueryable.java @@ -53,8 +53,8 @@ public class CustomQueryable> extends P } - protected ColQuery getInnerQuery(){ - return innerQuery; + protected QueryMetadata getMetadata(){ + return innerQuery.getMetadata(); } diff --git a/querydsl-collections/src/test/java/com/mysema/query/collections/PagingTest.java b/querydsl-collections/src/test/java/com/mysema/query/collections/PagingTest.java new file mode 100644 index 000000000..705842a18 --- /dev/null +++ b/querydsl-collections/src/test/java/com/mysema/query/collections/PagingTest.java @@ -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 ints = Arrays.asList(1,2,3,4,5,6,7,8,9); + + private PNumber 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; + } +} diff --git a/querydsl-collections/src/test/java/com/mysema/query/collections/iterators/LimitingIteratorTest.java b/querydsl-collections/src/test/java/com/mysema/query/collections/iterators/LimitingIteratorTest.java new file mode 100644 index 000000000..6f31e553a --- /dev/null +++ b/querydsl-collections/src/test/java/com/mysema/query/collections/iterators/LimitingIteratorTest.java @@ -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 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 transform(List ints, Long limit, Long offset) { + QueryModifiers modifiers = new QueryModifiers(limit, offset); + return IteratorUtils.toList(LimitingIterator.transform(ints.iterator(), modifiers)); + } + +}