Skip to content

Commit 22da2a0

Browse files
committed
Implemented ofy().load().kind(...)
1 parent f5e3ba7 commit 22da2a0

6 files changed

Lines changed: 70 additions & 17 deletions

File tree

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,20 @@ public interface Loader extends SimpleQuery<Object>
5353
*/
5454
<E> LoadType<E> type(Class<E> type);
5555

56+
/**
57+
* <p>Restricts the find operation to entities of a particular kind. This is similar to type()
58+
* but lets you specify any arbitrary kind string. You'll typically only use this if you are
59+
* also working with the low level api directly.</p>
60+
*
61+
* <p><b>All command objects are immutable; this method returns a new object instead of modifying the
62+
* current command object.</b></p>
63+
*
64+
* @param kind is the kind of entity (or entities) to retrieve
65+
* @return the next step in the immutable command chain, which allows you to start a query or define
66+
* keys for a batch get.
67+
*/
68+
<E> LoadType<E> kind(String kind);
69+
5670
/**
5771
* <p>Load a single entity ref. This starts an asynchronous fetch operation.</p>
5872
*

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

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import com.googlecode.objectify.util.DatastoreUtils;
1010
import com.googlecode.objectify.util.ResultCache;
1111
import com.googlecode.objectify.util.ResultProxy;
12-
1312
import java.util.Arrays;
1413
import java.util.LinkedHashMap;
1514
import java.util.Map;
@@ -23,21 +22,25 @@
2322
class LoadTypeImpl<T> extends Queryable<T> implements LoadType<T>
2423
{
2524
/** */
26-
Class<T> type;
25+
private final String kind;
26+
27+
/** Might be null; perhaps we specified a raw kind only */
28+
private final Class<T> type;
2729

2830
/** Possible parent */
29-
Key<T> parent;
31+
private final Key<T> parent;
3032

3133
/**
3234
*/
33-
LoadTypeImpl(LoaderImpl<?> loader, Class<T> type) {
34-
super(loader);
35-
this.type = type;
35+
LoadTypeImpl(LoaderImpl<?> loader, String kind, Class<T> type) {
36+
this(loader, kind, type, null);
3637
}
3738

3839
/** */
39-
LoadTypeImpl(LoaderImpl<?> loader, Class<T> type, Key<T> parent) {
40-
this(loader, type);
40+
LoadTypeImpl(LoaderImpl<?> loader, String kind, Class<T> type, Key<T> parent) {
41+
super(loader);
42+
this.kind = kind;
43+
this.type = type;
4144
this.parent = parent;
4245
}
4346

@@ -46,7 +49,7 @@ class LoadTypeImpl<T> extends Queryable<T> implements LoadType<T>
4649
*/
4750
@Override
4851
QueryImpl<T> createQuery() {
49-
return new QueryImpl<>(loader, type);
52+
return new QueryImpl<>(loader, kind, type);
5053
}
5154

5255
/* (non-Javadoc)
@@ -82,15 +85,15 @@ public Query<T> order(String condition) {
8285
*/
8386
@Override
8487
public LoadResult<T> id(long id) {
85-
return loader.key(Key.create(parent, type, id));
88+
return loader.key(this.<T>makeKey(id));
8689
}
8790

8891
/* (non-Javadoc)
8992
* @see com.googlecode.objectify.cmd.LoadIds#id(java.lang.String)
9093
*/
9194
@Override
9295
public LoadResult<T> id(String id) {
93-
return loader.key(Key.create(parent, type, id));
96+
return loader.key(this.<T>makeKey(id));
9497
}
9598

9699
/* (non-Javadoc)
@@ -117,7 +120,7 @@ public <S> Map<S, T> ids(Iterable<S> ids) {
117120

118121
final Map<Key<T>, S> keymap = new LinkedHashMap<>();
119122
for (S id: ids)
120-
keymap.put(DatastoreUtils.createKey(parent, type, id), id);
123+
keymap.put(this.<T>makeKey(id), id);
121124

122125
final Map<Key<T>, T> loaded = loader.keys(keymap.keySet());
123126

@@ -134,13 +137,20 @@ protected Map<S, T> nowUncached() {
134137
});
135138
}
136139

140+
/**
141+
* Make a key for the given id
142+
*/
143+
private <T> Key<T> makeKey(Object id) {
144+
return DatastoreUtils.createKey(parent, kind, id);
145+
}
146+
137147
/* (non-Javadoc)
138148
* @see com.googlecode.objectify.cmd.LoadType#parent(java.lang.Object)
139149
*/
140150
@Override
141151
public LoadIds<T> parent(Object keyOrEntity) {
142152
Key<T> parentKey = loader.ofy.factory().keys().anythingToKey(keyOrEntity);
143-
return new LoadTypeImpl<>(loader, type, parentKey);
153+
return new LoadTypeImpl<>(loader, kind, type, parentKey);
144154
}
145155

146156
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ public L group(Class<?>... groups) {
7272
*/
7373
@Override
7474
public <E> LoadType<E> type(Class<E> type) {
75-
return new LoadTypeImpl<>(this, type);
75+
return new LoadTypeImpl<>(this, Key.getKind(type), type);
76+
}
77+
78+
@Override
79+
public <E> LoadType<E> kind(String kind) {
80+
return new LoadTypeImpl<>(this, kind, null);
7681
}
7782

7883
/* (non-Javadoc)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ public class QueryImpl<T> extends SimpleQueryImpl<T> implements Query<T>, Clonea
6060
}
6161

6262
/** */
63-
QueryImpl(LoaderImpl<?> loader, Class<T> clazz) {
63+
QueryImpl(LoaderImpl<?> loader, String kind, Class<T> clazz) {
6464
super(loader);
6565

66-
this.actual = new com.google.appengine.api.datastore.Query(Key.getKind(clazz));
66+
this.actual = new com.google.appengine.api.datastore.Query(kind);
6767

6868
// If this is a polymorphic subclass, add an extra filter
6969
Subclass sub = clazz.getAnnotation(Subclass.class);
@@ -192,7 +192,7 @@ void addOrder(String condition) {
192192
condition = condition.substring(1).trim();
193193
}
194194

195-
// Check for @Id or @Parent fields. Any setting adjusts the key order. We only enforce that they are both set the same direction.
195+
// Prevent ordering by @Id or @Parent fields, which are really part of the key
196196
if (this.classRestriction != null) {
197197
KeyMetadata<?> meta = loader.ofy.factory().keys().getMetadataSafe(this.classRestriction);
198198

src/main/java/com/googlecode/objectify/util/DatastoreUtils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ else if (id instanceof Long)
6666
throw new IllegalArgumentException("id '" + id + "' must be String or Long");
6767
}
6868

69+
/**
70+
* Construct a Key<?> from a Long or String id
71+
* @param id must be either Long or String
72+
*/
73+
public static <T> Key<T> createKey(Key<?> parent, String kind, Object id) {
74+
com.google.appengine.api.datastore.Key key = createKey(parent == null ? null : parent.getRaw(), kind, id);
75+
return Key.create(key);
76+
}
77+
6978
/**
7079
* Construct a Key from a Long or String id
7180
* @param id must be either Long or String

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.google.appengine.api.datastore.FetchOptions;
88
import com.google.appengine.api.datastore.PreparedQuery;
99
import com.google.appengine.api.datastore.Query;
10+
import com.googlecode.objectify.Key;
1011
import com.googlecode.objectify.test.entity.Trivial;
1112
import com.googlecode.objectify.test.util.TestBase;
1213
import org.testng.annotations.Test;
@@ -18,6 +19,8 @@
1819
import static com.googlecode.objectify.test.util.TestObjectifyService.ds;
1920
import static com.googlecode.objectify.test.util.TestObjectifyService.fact;
2021
import static com.googlecode.objectify.test.util.TestObjectifyService.ofy;
22+
import static org.hamcrest.MatcherAssert.assertThat;
23+
import static org.hamcrest.core.Is.is;
2124

2225
/**
2326
* Tests of basic query operations
@@ -72,4 +75,16 @@ public void testChunking() throws Exception {
7275
}
7376
assert count == 100;
7477
}
78+
79+
/** */
80+
@Test
81+
public void loadByKindWorks() throws Exception {
82+
fact().register(Trivial.class);
83+
84+
Trivial triv1 = new Trivial(123L, "foo1", 12);
85+
ofy().save().entities(triv1).now();
86+
87+
Trivial fetched1 = ofy().load().<Trivial>kind(Key.getKind(Trivial.class)).id(triv1.getId()).now();
88+
assertThat(fetched1, is(triv1));
89+
}
7590
}

0 commit comments

Comments
 (0)