Skip to content

Commit 53eeeb4

Browse files
committed
Implement IN filtering
1 parent 52339db commit 53eeeb4

4 files changed

Lines changed: 63 additions & 46 deletions

File tree

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.googlecode.objectify.impl;
22

3+
import com.google.cloud.datastore.ListValue;
34
import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
45
import com.google.cloud.datastore.Value;
56
import lombok.RequiredArgsConstructor;
@@ -15,7 +16,7 @@ enum FilterOperator {
1516
GREATER_THAN_OR_EQUAL(PropertyFilter::ge),
1617
EQUAL(PropertyFilter::eq),
1718
NOT_EQUAL(PropertyFilter::neq),
18-
//IN,
19+
IN(requireList(PropertyFilter::in)),
1920
;
2021

2122
private final BiFunction<String, Value<?>, PropertyFilter> creator;
@@ -25,4 +26,19 @@ enum FilterOperator {
2526
public PropertyFilter of(final String propertyName, final Value<?> value) {
2627
return creator.apply(propertyName, value);
2728
}
29+
30+
/**
31+
* Generate a creator that makes sure that the value is a list of some sort.
32+
*/
33+
private static BiFunction<String, Value<?>, PropertyFilter> requireList(final BiFunction<String, ListValue, PropertyFilter> target) {
34+
return (property, value) -> {
35+
if (value instanceof ListValue) {
36+
return target.apply(property, (ListValue)value);
37+
} else {
38+
throw new IllegalArgumentException("Filter operation on '" + property + "' expected a list-type property");
39+
// Alternatively, convert it?
40+
//return target.apply(property, ListValue.of(value));
41+
}
42+
};
43+
}
2844
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ void addFilter(final Filter filter) {
153153
* Forgiving about the syntax; != and <> are NOT_EQUAL, = and == are EQUAL.
154154
*/
155155
protected FilterOperator translate(String operator) {
156-
operator = operator.trim();
156+
operator = operator.trim().toLowerCase();
157157

158158
if (operator.equals("=") || operator.equals("=="))
159159
return FilterOperator.EQUAL;
@@ -167,9 +167,8 @@ else if (operator.equals("<="))
167167
return FilterOperator.LESS_THAN_OR_EQUAL;
168168
else if (operator.equals("!=") || operator.equals("<>"))
169169
return FilterOperator.NOT_EQUAL;
170-
else if (operator.toLowerCase().equals("in"))
171-
//return FilterOperator.IN;
172-
throw new UnsupportedOperationException("The Cloud Datastore SDK does not currently support 'IN' filters");
170+
else if (operator.equalsIgnoreCase("in"))
171+
return FilterOperator.IN;
173172
else
174173
throw new IllegalArgumentException("Unknown operator '" + operator + "'");
175174
}

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

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -217,47 +217,6 @@ void testNotEquals() throws Exception {
217217
}
218218
}
219219

220-
/** No longer supported by the SDK */
221-
//@Test
222-
void testIN() throws Exception {
223-
final Trivial triv1 = new Trivial("foo", 3);
224-
final Trivial triv2 = new Trivial("bar", 3);
225-
ofy().save().entity(triv1).now();
226-
ofy().save().entity(triv2).now();
227-
228-
final List<String> conditions = Arrays.asList("foo", "bar", "baz");
229-
230-
final List<Trivial> result = ofy().load().type(Trivial.class).filter("someString in", conditions).list();
231-
assertThat(result).containsExactly(triv1, triv2);
232-
}
233-
234-
/** IN no longer supported by SDK */
235-
//@Test
236-
void specialKeyFilteringByIN() throws Exception {
237-
final Trivial triv1 = new Trivial("foo", 3);
238-
final Key<Trivial> key1 = ofy().save().entity(triv1).now();
239-
final Set<Key<Trivial>> singleton = Collections.singleton(key1);
240-
241-
final List<Trivial> result = ofy().load().type(Trivial.class).filter("__key__ in", singleton).list();
242-
assertThat(result).containsExactly(triv1);
243-
}
244-
245-
/** IN no longer supported by SDK */
246-
//@Test
247-
void testINfilteringWithKeyField() throws Exception {
248-
factory().register(Employee.class);
249-
250-
final Key<Employee> bobKey = Key.create(Employee.class, "bob");
251-
final Employee fred = new Employee("fred", bobKey);
252-
253-
ofy().save().entity(fred).now();
254-
255-
final Set<Key<Employee>> singleton = Collections.singleton(bobKey);
256-
257-
final List<Employee> result = ofy().load().type(Employee.class).filter("manager in", singleton).list();
258-
assertThat(result).containsExactly(fred);
259-
}
260-
261220
/** */
262221
@Test
263222
void countWorks() throws Exception {

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package com.googlecode.objectify.test;
55

66
import com.googlecode.objectify.Key;
7+
import com.googlecode.objectify.test.entity.Employee;
78
import com.googlecode.objectify.test.entity.Trivial;
89
import com.googlecode.objectify.test.util.LocalMemcacheExtension;
910
import com.googlecode.objectify.test.util.MockitoExtension;
@@ -14,8 +15,11 @@
1415
import org.junit.jupiter.api.extension.ExtendWith;
1516

1617
import java.util.ArrayList;
18+
import java.util.Arrays;
19+
import java.util.Collections;
1720
import java.util.List;
1821
import java.util.Map;
22+
import java.util.Set;
1923

2024
import static com.google.common.truth.Truth.assertThat;
2125
import static com.googlecode.objectify.ObjectifyService.factory;
@@ -61,4 +65,43 @@ void testNotEquals() throws Exception {
6165
assertThat(result).containsExactly(triv1);
6266
}
6367
}
68+
69+
@Test
70+
void testIN() throws Exception {
71+
final Trivial triv3 = new Trivial("foo3", 3);
72+
final Trivial triv4 = new Trivial("foo4", 3);
73+
ofy().save().entity(triv3).now();
74+
ofy().save().entity(triv4).now();
75+
76+
final List<String> conditions = Arrays.asList("foo3", "foo4", "baz");
77+
78+
final List<Trivial> result = ofy().load().type(Trivial.class).filter("someString in", conditions).list();
79+
assertThat(result).containsExactly(triv3, triv4);
80+
}
81+
82+
@Test
83+
void specialKeyFilteringByIN() throws Exception {
84+
final Trivial triv3 = new Trivial("foo3", 3);
85+
final Key<Trivial> key3 = ofy().save().entity(triv3).now();
86+
final Set<Key<Trivial>> singleton = Collections.singleton(key3);
87+
88+
final List<Trivial> result = ofy().load().type(Trivial.class).filter("__key__ in", singleton).list();
89+
assertThat(result).containsExactly(triv3);
90+
}
91+
92+
@Test
93+
void testINfilteringWithKeyField() throws Exception {
94+
factory().register(Employee.class);
95+
96+
final Key<Employee> bobKey = Key.create(Employee.class, "bob");
97+
final Employee fred = new Employee("fred", bobKey);
98+
99+
ofy().save().entity(fred).now();
100+
101+
final Set<Key<Employee>> singleton = Collections.singleton(bobKey);
102+
103+
final List<Employee> result = ofy().load().type(Employee.class).filter("manager in", singleton).list();
104+
assertThat(result).containsExactly(fred);
105+
}
106+
64107
}

0 commit comments

Comments
 (0)