Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / NotEqualQuerySplitter.java
blob08ed8009f540b5ff4915cad90bee16a444eda11d
1 // Copyright 2009 Google Inc. All Rights Reserved.
3 package com.google.appengine.api.datastore;
5 import static com.google.appengine.api.datastore.Query.FilterOperator.GREATER_THAN;
6 import static com.google.appengine.api.datastore.Query.FilterOperator.LESS_THAN;
7 import static com.google.appengine.api.datastore.Query.FilterOperator.NOT_EQUAL;
9 import com.google.appengine.api.datastore.Query.FilterPredicate;
10 import com.google.appengine.api.datastore.Query.SortDirection;
11 import com.google.appengine.api.datastore.Query.SortPredicate;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Iterator;
16 import java.util.List;
18 /**
19 * This class splits a query with a not-equal filter as follows:
20 * <p>Create n + 1 queries components that restrict the queries
21 * range to values outside the given value. Consider the example:
22 * <pre>
23 * select from Person where age != 33
24 * </pre>
25 * this class would turn this into:
26 * <pre>
27 * select from Person where age < 33
28 * select from Person where age > 33
29 * <pre>
31 * <p>This class can also work for multiple inequality filters. For example:
32 * <pre>
33 * select from Person where age != 33 and age != 40 order by age desc
34 * </pre>
35 * we would turn this into:
36 * <pre>
37 * select from Person where age > 40
38 * select from Person where age > 33 and age < 40
39 * select from Person where age < 33
40 * </pre>
42 * <p>Just like other inequality filters, != can only filters can only
43 * be applied to a single property and the first sort order must
44 * be on the same property.
47 class NotEqualQuerySplitter extends BaseQuerySplitter {
48 @Override
49 public List<QuerySplitComponent> split(List<FilterPredicate> remainingFilters,
50 List<SortPredicate> sorts) {
51 String propertyName = null;
52 List<ComparableValue> values = null;
54 Iterator<FilterPredicate> itr = remainingFilters.iterator();
55 while (itr.hasNext()) {
56 FilterPredicate filter = itr.next();
57 if (filter.getOperator() == NOT_EQUAL) {
58 if (propertyName == null) {
59 propertyName = filter.getPropertyName();
60 values = new ArrayList<ComparableValue>();
61 } else if (!propertyName.equals(filter.getPropertyName())) {
62 throw new IllegalArgumentException(
63 "Queries with NOT_EQUAL filters on different properties are not supported.");
66 values.add(new ComparableValue(filter.getValue()));
67 itr.remove();
71 if (values != null) {
72 ArrayList<QuerySplitComponent> result = new ArrayList<QuerySplitComponent>(values.size() + 1);
73 result.add(makeComponent(propertyName, values, sorts));
74 return result;
76 return Collections.emptyList();
79 /**
80 * Constructs a {@link QuerySplitComponent} from the given set of not equal
81 * filters.
83 * @param propertyName the property which != values
84 * @param values the list of values to consider
85 * @param sorts the sort predicates imposed on this query
86 * @return the resulting {@link QuerySplitComponent}
88 private QuerySplitComponent makeComponent(String propertyName, List<ComparableValue> values,
89 List<SortPredicate> sorts) {
90 QuerySplitComponent result = new QuerySplitComponent(propertyName, sorts);
91 if (!sorts.isEmpty() && (result.getSortIndex() != 0)) {
92 throw new IllegalArgumentException(
93 "The first sort order must be on the same property as the NOT_EQUAL filter");
96 Collections.sort(values, getValueComparator(result.getDirection()));
97 Object first = values.get(0).getValue();
98 Object last = values.get(values.size() - 1).getValue();
99 if (result.getDirection() == SortDirection.DESCENDING) {
100 result.addFilters(new FilterPredicate(propertyName, GREATER_THAN, first));
101 for (int i = 1; i < values.size(); ++i) {
102 Object prev = values.get(i - 1).getValue();
103 Object next = values.get(i).getValue();
104 result.addFilters(new FilterPredicate(propertyName, LESS_THAN, prev),
105 new FilterPredicate(propertyName, GREATER_THAN, next));
107 if (last != null) {
108 result.addFilters(new FilterPredicate(propertyName, LESS_THAN, last));
110 } else {
111 if (first != null) {
112 result.addFilters(new FilterPredicate(propertyName, LESS_THAN, first));
114 for (int i = 1; i < values.size(); ++i) {
115 Object prev = values.get(i - 1).getValue();
116 Object next = values.get(i).getValue();
117 result.addFilters(new FilterPredicate(propertyName, GREATER_THAN, prev),
118 new FilterPredicate(propertyName, LESS_THAN, next));
120 result.addFilters(new FilterPredicate(propertyName, GREATER_THAN, last));
122 return result;