Skip to content

Commit 83d6008

Browse files
committed
Add documentation, and address/remove some TODOs.
1 parent a3b86c8 commit 83d6008

File tree

5 files changed

+218
-30
lines changed

5 files changed

+218
-30
lines changed

firebase-firestore/src/main/java/com/google/firebase/firestore/Filter.java

Lines changed: 179 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@
1717
import androidx.annotation.NonNull;
1818
import androidx.annotation.Nullable;
1919
import androidx.annotation.RestrictTo;
20-
import com.google.firebase.firestore.core.CompositeFilter;
2120
import com.google.firebase.firestore.core.FieldFilter.Operator;
2221
import java.util.Arrays;
2322
import java.util.List;
2423

24+
// TODO(orquery): Remove the `hide` and scope annotations.
2525
/** @hide */
2626
@RestrictTo(RestrictTo.Scope.LIBRARY)
27+
/**
28+
* A {@code Filter} represents a restriction on one or more field values and can be used to refine
29+
* the results of a {@code Query}.
30+
*/
2731
public class Filter {
2832
static class UnaryFilter extends Filter {
2933
private final FieldPath field;
@@ -70,112 +74,274 @@ public com.google.firebase.firestore.core.CompositeFilter.Operator getOperator()
7074
}
7175
}
7276

77+
/**
78+
* Creates a new filter for checking that the given field is equal to the given value.
79+
*
80+
* @param field The field used for the filter.
81+
* @param value The value used for the filter.
82+
* @return The newly created filter.
83+
*/
7384
@NonNull
7485
public static Filter equalTo(@NonNull String field, @Nullable Object value) {
7586
return equalTo(FieldPath.fromDotSeparatedPath(field), value);
7687
}
7788

89+
/**
90+
* Creates a new filter for checking that the given field is equal to the given value.
91+
*
92+
* @param fieldPath The field path used for the filter.
93+
* @param value The value used for the filter.
94+
* @return The newly created filter.
95+
*/
7896
@NonNull
7997
public static Filter equalTo(@NonNull FieldPath fieldPath, @Nullable Object value) {
8098
return new UnaryFilter(fieldPath, Operator.EQUAL, value);
8199
}
82100

101+
/**
102+
* Creates a new filter for checking that the given field is not equal to the given value.
103+
*
104+
* @param field The field used for the filter.
105+
* @param value The value used for the filter.
106+
* @return The newly created filter.
107+
*/
83108
@NonNull
84109
public static Filter notEqualTo(@NonNull String field, @Nullable Object value) {
85110
return notEqualTo(FieldPath.fromDotSeparatedPath(field), value);
86111
}
87112

113+
/**
114+
* Creates a new filter for checking that the given field is not equal to the given value.
115+
*
116+
* @param fieldPath The field path used for the filter.
117+
* @param value The value used for the filter.
118+
* @return The newly created filter.
119+
*/
88120
@NonNull
89121
public static Filter notEqualTo(@NonNull FieldPath fieldPath, @Nullable Object value) {
90122
return new UnaryFilter(fieldPath, Operator.NOT_EQUAL, value);
91123
}
92124

125+
/**
126+
* Creates a new filter for checking that the given field is greater than the given value.
127+
*
128+
* @param field The field used for the filter.
129+
* @param value The value used for the filter.
130+
* @return The newly created filter.
131+
*/
93132
@NonNull
94133
public static Filter greaterThan(@NonNull String field, @Nullable Object value) {
95134
return greaterThan(FieldPath.fromDotSeparatedPath(field), value);
96135
}
97136

137+
/**
138+
* Creates a new filter for checking that the given field is greater than the given value.
139+
*
140+
* @param fieldPath The field path used for the filter.
141+
* @param value The value used for the filter.
142+
* @return The newly created filter.
143+
*/
98144
@NonNull
99145
public static Filter greaterThan(@NonNull FieldPath fieldPath, @Nullable Object value) {
100146
return new UnaryFilter(fieldPath, Operator.GREATER_THAN, value);
101147
}
102148

149+
/**
150+
* Creates a new filter for checking that the given field is greater than or equal to the given
151+
* value.
152+
*
153+
* @param field The field used for the filter.
154+
* @param value The value used for the filter.
155+
* @return The newly created filter.
156+
*/
103157
@NonNull
104158
public static Filter greaterThanOrEqualTo(@NonNull String field, @Nullable Object value) {
105159
return greaterThanOrEqualTo(FieldPath.fromDotSeparatedPath(field), value);
106160
}
107161

162+
/**
163+
* Creates a new filter for checking that the given field is greater than or equal to the given
164+
* value.
165+
*
166+
* @param fieldPath The field path used for the filter.
167+
* @param value The value used for the filter.
168+
* @return The newly created filter.
169+
*/
108170
@NonNull
109171
public static Filter greaterThanOrEqualTo(@NonNull FieldPath fieldPath, @Nullable Object value) {
110172
return new UnaryFilter(fieldPath, Operator.GREATER_THAN_OR_EQUAL, value);
111173
}
112174

175+
/**
176+
* Creates a new filter for checking that the given field is less than the given value.
177+
*
178+
* @param field The field used for the filter.
179+
* @param value The value used for the filter.
180+
* @return The newly created filter.
181+
*/
113182
@NonNull
114183
public static Filter lessThan(@NonNull String field, @Nullable Object value) {
115184
return lessThan(FieldPath.fromDotSeparatedPath(field), value);
116185
}
117186

187+
/**
188+
* Creates a new filter for checking that the given field is less than the given value.
189+
*
190+
* @param fieldPath The field path used for the filter.
191+
* @param value The value used for the filter.
192+
* @return The newly created filter.
193+
*/
118194
@NonNull
119195
public static Filter lessThan(@NonNull FieldPath fieldPath, @Nullable Object value) {
120196
return new UnaryFilter(fieldPath, Operator.LESS_THAN, value);
121197
}
122198

199+
/**
200+
* Creates a new filter for checking that the given field is less than or equal to the given
201+
* value.
202+
*
203+
* @param field The field used for the filter.
204+
* @param value The value used for the filter.
205+
* @return The newly created filter.
206+
*/
123207
@NonNull
124208
public static Filter lessThanOrEqualTo(@NonNull String field, @Nullable Object value) {
125209
return lessThanOrEqualTo(FieldPath.fromDotSeparatedPath(field), value);
126210
}
127211

212+
/**
213+
* Creates a new filter for checking that the given field is less than or equal to the given
214+
* value.
215+
*
216+
* @param fieldPath The field path used for the filter.
217+
* @param value The value used for the filter.
218+
* @return The newly created filter.
219+
*/
128220
@NonNull
129221
public static Filter lessThanOrEqualTo(@NonNull FieldPath fieldPath, @Nullable Object value) {
130222
return new UnaryFilter(fieldPath, Operator.LESS_THAN_OR_EQUAL, value);
131223
}
132224

225+
/**
226+
* Creates a new filter for checking that the given array field contains the given value.
227+
*
228+
* @param field The field used for the filter.
229+
* @param value The value used for the filter.
230+
* @return The newly created filter.
231+
*/
133232
@NonNull
134233
public static Filter arrayContains(@NonNull String field, @Nullable Object value) {
135234
return arrayContains(FieldPath.fromDotSeparatedPath(field), value);
136235
}
137236

237+
/**
238+
* Creates a new filter for checking that the given array field contains the given value.
239+
*
240+
* @param fieldPath The field path used for the filter.
241+
* @param value The value used for the filter.
242+
* @return The newly created filter.
243+
*/
138244
@NonNull
139245
public static Filter arrayContains(@NonNull FieldPath fieldPath, @Nullable Object value) {
140246
return new UnaryFilter(fieldPath, Operator.ARRAY_CONTAINS, value);
141247
}
142248

249+
/**
250+
* Creates a new filter for checking that the given array field contains any of the given values.
251+
*
252+
* @param field The field used for the filter.
253+
* @param values The list of values used for the filter.
254+
* @return The newly created filter.
255+
*/
143256
@NonNull
144-
public static Filter arrayContainsAny(@NonNull String field, @Nullable Object value) {
145-
return arrayContainsAny(FieldPath.fromDotSeparatedPath(field), value);
257+
public static Filter arrayContainsAny(
258+
@NonNull String field, @NonNull List<? extends Object> values) {
259+
return arrayContainsAny(FieldPath.fromDotSeparatedPath(field), values);
146260
}
147261

262+
/**
263+
* Creates a new filter for checking that the given array field contains any of the given values.
264+
*
265+
* @param fieldPath The field path used for the filter.
266+
* @param values The list of values used for the filter.
267+
* @return The newly created filter.
268+
*/
148269
@NonNull
149-
public static Filter arrayContainsAny(@NonNull FieldPath fieldPath, @Nullable Object value) {
150-
return new UnaryFilter(fieldPath, Operator.ARRAY_CONTAINS_ANY, value);
270+
public static Filter arrayContainsAny(
271+
@NonNull FieldPath fieldPath, @NonNull List<? extends Object> values) {
272+
return new UnaryFilter(fieldPath, Operator.ARRAY_CONTAINS_ANY, values);
151273
}
152274

275+
/**
276+
* Creates a new filter for checking that the given field equals any of the given values.
277+
*
278+
* @param field The field used for the filter.
279+
* @param values The list of values used for the filter.
280+
* @return The newly created filter.
281+
*/
153282
@NonNull
154-
public static Filter inArray(@NonNull String field, @Nullable Object value) {
155-
return inArray(FieldPath.fromDotSeparatedPath(field), value);
283+
public static Filter inArray(@NonNull String field, @NonNull List<? extends Object> values) {
284+
return inArray(FieldPath.fromDotSeparatedPath(field), values);
156285
}
157286

287+
/**
288+
* Creates a new filter for checking that the given field equals any of the given values.
289+
*
290+
* @param fieldPath The field path used for the filter.
291+
* @param values The list of values used for the filter.
292+
* @return The newly created filter.
293+
*/
158294
@NonNull
159-
public static Filter inArray(@NonNull FieldPath fieldPath, @Nullable Object value) {
160-
return new UnaryFilter(fieldPath, Operator.IN, value);
295+
public static Filter inArray(
296+
@NonNull FieldPath fieldPath, @NonNull List<? extends Object> values) {
297+
return new UnaryFilter(fieldPath, Operator.IN, values);
161298
}
162299

300+
/**
301+
* Creates a new filter for checking that the given field does not equal any of the given values.
302+
*
303+
* @param field The field path used for the filter.
304+
* @param values The list of values used for the filter.
305+
* @return The newly created filter.
306+
*/
163307
@NonNull
164-
public static Filter notInArray(@NonNull String field, @Nullable Object value) {
165-
return notInArray(FieldPath.fromDotSeparatedPath(field), value);
308+
public static Filter notInArray(@NonNull String field, @NonNull List<? extends Object> values) {
309+
return notInArray(FieldPath.fromDotSeparatedPath(field), values);
166310
}
167311

312+
/**
313+
* Creates a new filter for checking that the given field does not equal any of the given values.
314+
*
315+
* @param fieldPath The field path used for the filter.
316+
* @param values The list of values used for the filter.
317+
* @return The newly created filter.
318+
*/
168319
@NonNull
169-
public static Filter notInArray(@NonNull FieldPath fieldPath, @Nullable Object value) {
170-
return new UnaryFilter(fieldPath, Operator.NOT_IN, value);
320+
public static Filter notInArray(
321+
@NonNull FieldPath fieldPath, @NonNull List<? extends Object> values) {
322+
return new UnaryFilter(fieldPath, Operator.NOT_IN, values);
171323
}
172324

325+
/**
326+
* Creates a new filter that is a disjunction of the given filters. A disjunction filter includes
327+
* a document if it satisfies <em>any</em> of the given filters.
328+
*
329+
* @param filters The list of filters to perform a disjunction for.
330+
* @return The newly created filter.
331+
*/
173332
@NonNull
174333
public static Filter or(Filter... filters) {
175334
return new CompositeFilter(
176335
Arrays.asList(filters), com.google.firebase.firestore.core.CompositeFilter.Operator.OR);
177336
}
178337

338+
/**
339+
* Creates a new filter that is a conjunction of the given filters. A conjunction filter includes
340+
* a document if it satisfies <em>all</em> of the given filters.
341+
*
342+
* @param filters The list of filters to perform a disjunction for.
343+
* @return The newly created filter.
344+
*/
179345
@NonNull
180346
public static Filter and(Filter... filters) {
181347
return new CompositeFilter(

firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,23 @@ public Query whereNotIn(@NonNull FieldPath fieldPath, @NonNull List<? extends Ob
388388
return where(Filter.notInArray(fieldPath, values));
389389
}
390390

391+
// TODO(orquery): This method will become public API. Change visibility and add documentation.
392+
/**
393+
* Creates and returns a new {@code Query} with the additional filter.
394+
*
395+
* @param filter The new filter to apply to the existing query.
396+
* @return The newly created {@code Query}.
397+
*/
398+
Query where(Filter filter) {
399+
com.google.firebase.firestore.core.Filter parsedFilter = parseFilter(filter);
400+
if (parsedFilter.getFilters().isEmpty()) {
401+
// Return the existing query if not adding any more filters (e.g. an empty composite filter).
402+
return this;
403+
}
404+
validateNewFilter(parsedFilter);
405+
return new Query(query.filter(parsedFilter), firestore);
406+
}
407+
391408
/**
392409
* Takes a {@link Filter.UnaryFilter} object, parses the value object and returns a new {@link
393410
* FieldFilter} for the field, operator, and parsed value.
@@ -468,17 +485,6 @@ private com.google.firebase.firestore.core.Filter parseFilter(Filter filter) {
468485
return parseCompositeFilter((Filter.CompositeFilter) filter);
469486
}
470487

471-
// TODO(orquery): This method will become public API. Change visibility and add documentation.
472-
Query where(Filter filter) {
473-
com.google.firebase.firestore.core.Filter parsedFilter = parseFilter(filter);
474-
if (parsedFilter.getFilters().isEmpty()) {
475-
// Return the existing query if not adding any more filters (e.g. an empty composite filter).
476-
return this;
477-
}
478-
validateNewFilter(parsedFilter);
479-
return new Query(query.filter(parsedFilter), firestore);
480-
}
481-
482488
private void validateOrderByField(com.google.firebase.firestore.model.FieldPath field) {
483489
com.google.firebase.firestore.model.FieldPath inequalityField = query.inequalityField();
484490
if (query.getFirstOrderByField() == null && inequalityField != null) {

firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,20 @@ public boolean matches(Document doc) {
161161

162162
@Override
163163
public String getCanonicalId() {
164-
// TODO(orquery): Add special case for flat AND filters.
165-
166164
StringBuilder builder = new StringBuilder();
165+
166+
// Older SDK versions use an implicit AND operation between their filters. In the new SDK
167+
// versions, the developer may use an explicit AND filter. To stay consistent with the old
168+
// usages, we add a special case to ensure the canonical ID for these two are the same.
169+
// For example: `col.whereEquals("a", 1).whereEquals("b", 2)` should have the same canonical ID
170+
// as `col.where(and(equals("a",1), equals("b",2)))`.
171+
if (isFlatConjunction()) {
172+
for (Filter filter : filters) {
173+
builder.append(filter.getCanonicalId());
174+
}
175+
return builder.toString();
176+
}
177+
167178
builder.append(operator.toString() + "(");
168179
builder.append(TextUtils.join(",", filters));
169180
builder.append(")");
@@ -183,7 +194,6 @@ public boolean equals(Object o) {
183194
CompositeFilter other = (CompositeFilter) o;
184195
// Note: This comparison requires order of filters in the list to be the same, and it does not
185196
// remove duplicate subfilters from each composite filter. It is therefore way less expensive.
186-
// TODO(orquery): Consider removing duplicates and ignoring order of filters in the list.
187197
return operator == other.operator && filters.equals(other.filters);
188198
}
189199

firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -643,9 +643,7 @@ private List<Filter> decodeFilters(StructuredQuery.Filter proto) {
643643
Filter result = decodeFilter(proto);
644644

645645
// Instead of a singletonList containing AND(F1, F2, ...), we can return a list containing F1,
646-
// F2, ...
647-
// TODO(orquery): Once proper support for composite filters has been completed, we can remove
648-
// this flattening from here.
646+
// F2, ... to stay consistent with the older SDK versions.
649647
if (result instanceof com.google.firebase.firestore.core.CompositeFilter) {
650648
com.google.firebase.firestore.core.CompositeFilter compositeFilter =
651649
(com.google.firebase.firestore.core.CompositeFilter) result;

0 commit comments

Comments
 (0)