Skip to content

Commit 1f9f46c

Browse files
committed
Add reverse() method to Query
1 parent fe7638f commit 1f9f46c

7 files changed

Lines changed: 86 additions & 56 deletions

File tree

src/main/java/com/googlecode/objectify/cmd/Query.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,10 @@ public interface Query<T> extends SimpleQuery<T>
110110
*/
111111
@Override
112112
public Query<T> hybrid(boolean force);
113+
114+
/* (non-Javadoc)
115+
* @see com.googlecode.objectify.cmd.SimpleQuery#reverse()
116+
*/
117+
@Override
118+
public Query<T> reverse();
113119
}

src/main/java/com/googlecode/objectify/cmd/SimpleQuery.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ public interface SimpleQuery<T> extends QueryExecute<T>
9898
* Determines whether this is a SELECT DISTINCT query.
9999
*/
100100
public SimpleQuery<T> distinct(boolean value);
101+
102+
/**
103+
* Reverse the query, as described in the <a href="https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/Query#reverse()">GAE docs</a>.
104+
*/
105+
public SimpleQuery<T> reverse();
101106

102107
/**
103108
* <p>This method forces Objectify to (or not to) hybridize the query into a keys-only fetch plus batch get.</p>

src/main/java/com/googlecode/objectify/impl/QueryImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ void setDistinct(boolean value) {
269269
this.actual.setDistinct(value);
270270
}
271271

272+
/** Modifies the instance, switching directions */
273+
void toggleReverse() {
274+
this.actual = this.actual.reverse();
275+
}
276+
272277
/* (non-Javadoc)
273278
* @see java.lang.Object#toString()
274279
*/

src/main/java/com/googlecode/objectify/impl/SimpleQueryImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,14 @@ public QueryKeys<T> keys()
158158
q.setKeysOnly();
159159
return new QueryKeysImpl<T>(q);
160160
}
161+
162+
/* (non-Javadoc)
163+
* @see com.googlecode.objectify.cmd.SimpleQuery#reverse()
164+
*/
165+
@Override
166+
public QueryImpl<T> reverse() {
167+
QueryImpl<T> q = createQuery();
168+
q.toggleReverse();
169+
return q;
170+
}
161171
}

src/main/java/com/googlecode/objectify/util/cmd/SimpleQueryWrapper.java

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,147 +21,134 @@ public class SimpleQueryWrapper<H extends SimpleQueryWrapper<H, T>, T> implement
2121
SimpleQuery<T> base;
2222

2323
/** */
24-
public SimpleQueryWrapper(SimpleQuery<T> base)
25-
{
24+
public SimpleQueryWrapper(SimpleQuery<T> base) {
2625
this.base = base;
2726
}
2827

2928
@Override
30-
public H filterKey(String condition, Object value)
31-
{
29+
public H filterKey(String condition, Object value) {
3230
H next = this.clone();
3331
next.base = base.filterKey(condition, value);
3432
return next;
3533
}
3634

3735
@Override
38-
public SimpleQuery<T> filterKey(Object value)
39-
{
36+
public SimpleQuery<T> filterKey(Object value) {
4037
H next = this.clone();
4138
next.base = base.filterKey(value);
4239
return next;
4340
}
4441

4542
@Override
46-
public H ancestor(Object keyOrEntity)
47-
{
43+
public H ancestor(Object keyOrEntity) {
4844
H next = this.clone();
4945
next.base = base.ancestor(keyOrEntity);
5046
return next;
5147
}
5248

5349
@Override
54-
public H limit(int value)
55-
{
50+
public H limit(int value) {
5651
H next = this.clone();
5752
next.base = base.limit(value);
5853
return next;
5954
}
6055

6156
@Override
62-
public H offset(int value)
63-
{
57+
public H offset(int value) {
6458
H next = this.clone();
6559
next.base = base.offset(value);
6660
return next;
6761
}
6862

6963
@Override
70-
public H startAt(Cursor value)
71-
{
64+
public H startAt(Cursor value) {
7265
H next = this.clone();
7366
next.base = base.startAt(value);
7467
return next;
7568
}
7669

7770
@Override
78-
public H endAt(Cursor value)
79-
{
71+
public H endAt(Cursor value) {
8072
H next = this.clone();
8173
next.base = base.endAt(value);
8274
return next;
8375
}
8476

8577
@Override
86-
public String toString()
87-
{
78+
public H reverse() {
79+
H next = this.clone();
80+
next.base = base.reverse();
81+
return next;
82+
}
83+
84+
@Override
85+
public String toString() {
8886
return base.toString();
8987
}
9088

9189
@Override
92-
public LoadResult<T> first()
93-
{
90+
public LoadResult<T> first() {
9491
return base.first();
9592
}
9693

9794
@Override
98-
public int count()
99-
{
95+
public int count() {
10096
return base.count();
10197
}
10298

10399
@Override
104-
public QueryResultIterable<T> iterable()
105-
{
100+
public QueryResultIterable<T> iterable() {
106101
return base.iterable();
107102
}
108103

109104
@Override
110-
public List<T> list()
111-
{
105+
public List<T> list() {
112106
return base.list();
113107
}
114108

115109
@Override
116-
public H chunk(int value)
117-
{
110+
public H chunk(int value) {
118111
H next = this.clone();
119112
next.base = base.chunk(value);
120113
return next;
121114
}
122115

123116
@Override
124-
public H chunkAll()
125-
{
117+
public H chunkAll() {
126118
H next = this.clone();
127119
next.base = base.chunkAll();
128120
return next;
129121
}
130122

131123
@Override
132-
public H distinct(boolean value)
133-
{
124+
public H distinct(boolean value) {
134125
H next = this.clone();
135126
next.base = base.distinct(value);
136127
return next;
137128
}
138129

139130
@Override
140-
public H hybrid(boolean force)
141-
{
131+
public H hybrid(boolean force) {
142132
H next = this.clone();
143133
next.base = base.hybrid(force);
144134
return next;
145135
}
146136

147137
@Override
148-
public QueryResultIterator<T> iterator()
149-
{
138+
public QueryResultIterator<T> iterator() {
150139
return base.iterator();
151140
}
152141

153142
@Override
154-
public QueryKeys<T> keys()
155-
{
143+
public QueryKeys<T> keys() {
156144
return base.keys();
157145
}
158146

159147
/* (non-Javadoc)
160148
* @see java.lang.Object#clone()
161149
*/
162150
@SuppressWarnings("unchecked")
163-
protected H clone()
164-
{
151+
protected H clone() {
165152
try {
166153
return (H)super.clone();
167154
} catch (CloneNotSupportedException e) {

src/test/java/com/googlecode/objectify/test/EmbedMapTests.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -85,22 +85,6 @@ public void testNullValuesWork() throws Exception {
8585
assert (fetched.primitives.equals(hml.primitives));
8686
}
8787

88-
@com.googlecode.objectify.annotation.Entity
89-
public static class MissingEmbedMapAnnotation {
90-
@Id
91-
Long id;
92-
93-
Map<String, Long> primitives = new HashMap<String, Long>();
94-
}
95-
96-
/**
97-
* We shouldn't be able to register without the @EmbedMap annotation; secures future compatiblity
98-
*/
99-
@Test(expectedExceptions=IllegalStateException.class)
100-
public void testMissingEmbedMapAnnotation() throws Exception {
101-
fact().register(MissingEmbedMapAnnotation.class);
102-
}
103-
10488
/**
10589
* We should be able to store a Key<?> as the EmbedMap key
10690
*/

src/test/java/com/googlecode/objectify/test/QueryCursorTestsSmall.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,37 @@ public void testCursorOneFetchToEnd() throws Exception {
136136
it = q.startAt(cursor).iterator();
137137
assert !it.hasNext();
138138
}
139+
140+
/** */
141+
@Test
142+
public void cursorReverses() throws Exception {
143+
Query<Trivial> q = ofy().load().type(Trivial.class).order("id");
144+
QueryResultIterator<Trivial> it = q.iterator();
145+
146+
@SuppressWarnings("unused")
147+
Cursor cursor0 = it.getCursor();
148+
final Trivial item1 = it.next();
149+
150+
Cursor cursor1 = it.getCursor();
151+
final Trivial item2 = it.next();
152+
assert !it.hasNext();
153+
154+
Cursor cursor2 = it.getCursor();
155+
Cursor cursor2Rev = it.getCursor().reverse();
156+
157+
it = q.reverse().startAt(cursor2Rev).iterator();
158+
159+
final Trivial item2Rev = it.next();
160+
161+
assert it.getCursor().equals(cursor2);
162+
assert item2Rev.getSomeString().equals(item2.getSomeString());
163+
164+
assert it.hasNext();
165+
166+
final Trivial item1Rev = it.next();
167+
168+
assert it.getCursor().equals(cursor1);
169+
assert item1Rev.getSomeString().equals(item1.getSomeString());
170+
assert !it.hasNext();
171+
}
139172
}

0 commit comments

Comments
 (0)