diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Filter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/Filter.java index 0df73bce122..882a803cdac 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Filter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Filter.java @@ -17,13 +17,17 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; -import com.google.firebase.firestore.core.CompositeFilter; import com.google.firebase.firestore.core.FieldFilter.Operator; import java.util.Arrays; import java.util.List; +// TODO(orquery): Remove the `hide` and scope annotations. /** @hide */ @RestrictTo(RestrictTo.Scope.LIBRARY) +/** + * A {@code Filter} represents a restriction on one or more field values and can be used to refine + * the results of a {@code Query}. + */ public class Filter { static class UnaryFilter extends Filter { private final FieldPath field; @@ -70,112 +74,274 @@ public com.google.firebase.firestore.core.CompositeFilter.Operator getOperator() } } + /** + * Creates a new filter for checking that the given field is equal to the given value. + * + * @param field The field used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter equalTo(@NonNull String field, @Nullable Object value) { return equalTo(FieldPath.fromDotSeparatedPath(field), value); } + /** + * Creates a new filter for checking that the given field is equal to the given value. + * + * @param fieldPath The field path used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter equalTo(@NonNull FieldPath fieldPath, @Nullable Object value) { return new UnaryFilter(fieldPath, Operator.EQUAL, value); } + /** + * Creates a new filter for checking that the given field is not equal to the given value. + * + * @param field The field used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter notEqualTo(@NonNull String field, @Nullable Object value) { return notEqualTo(FieldPath.fromDotSeparatedPath(field), value); } + /** + * Creates a new filter for checking that the given field is not equal to the given value. + * + * @param fieldPath The field path used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter notEqualTo(@NonNull FieldPath fieldPath, @Nullable Object value) { return new UnaryFilter(fieldPath, Operator.NOT_EQUAL, value); } + /** + * Creates a new filter for checking that the given field is greater than the given value. + * + * @param field The field used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter greaterThan(@NonNull String field, @Nullable Object value) { return greaterThan(FieldPath.fromDotSeparatedPath(field), value); } + /** + * Creates a new filter for checking that the given field is greater than the given value. + * + * @param fieldPath The field path used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter greaterThan(@NonNull FieldPath fieldPath, @Nullable Object value) { return new UnaryFilter(fieldPath, Operator.GREATER_THAN, value); } + /** + * Creates a new filter for checking that the given field is greater than or equal to the given + * value. + * + * @param field The field used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter greaterThanOrEqualTo(@NonNull String field, @Nullable Object value) { return greaterThanOrEqualTo(FieldPath.fromDotSeparatedPath(field), value); } + /** + * Creates a new filter for checking that the given field is greater than or equal to the given + * value. + * + * @param fieldPath The field path used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter greaterThanOrEqualTo(@NonNull FieldPath fieldPath, @Nullable Object value) { return new UnaryFilter(fieldPath, Operator.GREATER_THAN_OR_EQUAL, value); } + /** + * Creates a new filter for checking that the given field is less than the given value. + * + * @param field The field used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter lessThan(@NonNull String field, @Nullable Object value) { return lessThan(FieldPath.fromDotSeparatedPath(field), value); } + /** + * Creates a new filter for checking that the given field is less than the given value. + * + * @param fieldPath The field path used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter lessThan(@NonNull FieldPath fieldPath, @Nullable Object value) { return new UnaryFilter(fieldPath, Operator.LESS_THAN, value); } + /** + * Creates a new filter for checking that the given field is less than or equal to the given + * value. + * + * @param field The field used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter lessThanOrEqualTo(@NonNull String field, @Nullable Object value) { return lessThanOrEqualTo(FieldPath.fromDotSeparatedPath(field), value); } + /** + * Creates a new filter for checking that the given field is less than or equal to the given + * value. + * + * @param fieldPath The field path used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter lessThanOrEqualTo(@NonNull FieldPath fieldPath, @Nullable Object value) { return new UnaryFilter(fieldPath, Operator.LESS_THAN_OR_EQUAL, value); } + /** + * Creates a new filter for checking that the given array field contains the given value. + * + * @param field The field used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter arrayContains(@NonNull String field, @Nullable Object value) { return arrayContains(FieldPath.fromDotSeparatedPath(field), value); } + /** + * Creates a new filter for checking that the given array field contains the given value. + * + * @param fieldPath The field path used for the filter. + * @param value The value used for the filter. + * @return The newly created filter. + */ @NonNull public static Filter arrayContains(@NonNull FieldPath fieldPath, @Nullable Object value) { return new UnaryFilter(fieldPath, Operator.ARRAY_CONTAINS, value); } + /** + * Creates a new filter for checking that the given array field contains any of the given values. + * + * @param field The field used for the filter. + * @param values The list of values used for the filter. + * @return The newly created filter. + */ @NonNull - public static Filter arrayContainsAny(@NonNull String field, @Nullable Object value) { - return arrayContainsAny(FieldPath.fromDotSeparatedPath(field), value); + public static Filter arrayContainsAny( + @NonNull String field, @NonNull List values) { + return arrayContainsAny(FieldPath.fromDotSeparatedPath(field), values); } + /** + * Creates a new filter for checking that the given array field contains any of the given values. + * + * @param fieldPath The field path used for the filter. + * @param values The list of values used for the filter. + * @return The newly created filter. + */ @NonNull - public static Filter arrayContainsAny(@NonNull FieldPath fieldPath, @Nullable Object value) { - return new UnaryFilter(fieldPath, Operator.ARRAY_CONTAINS_ANY, value); + public static Filter arrayContainsAny( + @NonNull FieldPath fieldPath, @NonNull List values) { + return new UnaryFilter(fieldPath, Operator.ARRAY_CONTAINS_ANY, values); } + /** + * Creates a new filter for checking that the given field equals any of the given values. + * + * @param field The field used for the filter. + * @param values The list of values used for the filter. + * @return The newly created filter. + */ @NonNull - public static Filter inArray(@NonNull String field, @Nullable Object value) { - return inArray(FieldPath.fromDotSeparatedPath(field), value); + public static Filter inArray(@NonNull String field, @NonNull List values) { + return inArray(FieldPath.fromDotSeparatedPath(field), values); } + /** + * Creates a new filter for checking that the given field equals any of the given values. + * + * @param fieldPath The field path used for the filter. + * @param values The list of values used for the filter. + * @return The newly created filter. + */ @NonNull - public static Filter inArray(@NonNull FieldPath fieldPath, @Nullable Object value) { - return new UnaryFilter(fieldPath, Operator.IN, value); + public static Filter inArray( + @NonNull FieldPath fieldPath, @NonNull List values) { + return new UnaryFilter(fieldPath, Operator.IN, values); } + /** + * Creates a new filter for checking that the given field does not equal any of the given values. + * + * @param field The field path used for the filter. + * @param values The list of values used for the filter. + * @return The newly created filter. + */ @NonNull - public static Filter notInArray(@NonNull String field, @Nullable Object value) { - return notInArray(FieldPath.fromDotSeparatedPath(field), value); + public static Filter notInArray(@NonNull String field, @NonNull List values) { + return notInArray(FieldPath.fromDotSeparatedPath(field), values); } + /** + * Creates a new filter for checking that the given field does not equal any of the given values. + * + * @param fieldPath The field path used for the filter. + * @param values The list of values used for the filter. + * @return The newly created filter. + */ @NonNull - public static Filter notInArray(@NonNull FieldPath fieldPath, @Nullable Object value) { - return new UnaryFilter(fieldPath, Operator.NOT_IN, value); + public static Filter notInArray( + @NonNull FieldPath fieldPath, @NonNull List values) { + return new UnaryFilter(fieldPath, Operator.NOT_IN, values); } + /** + * Creates a new filter that is a disjunction of the given filters. A disjunction filter includes + * a document if it satisfies any of the given filters. + * + * @param filters The list of filters to perform a disjunction for. + * @return The newly created filter. + */ @NonNull public static Filter or(Filter... filters) { return new CompositeFilter( Arrays.asList(filters), com.google.firebase.firestore.core.CompositeFilter.Operator.OR); } + /** + * Creates a new filter that is a conjunction of the given filters. A conjunction filter includes + * a document if it satisfies all of the given filters. + * + * @param filters The list of filters to perform a disjunction for. + * @return The newly created filter. + */ @NonNull public static Filter and(Filter... filters) { return new CompositeFilter( diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java index 8db1e9ff8db..a4519aacfb8 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Query.java @@ -388,6 +388,23 @@ public Query whereNotIn(@NonNull FieldPath fieldPath, @NonNull List decodeFilters(StructuredQuery.Filter proto) { Filter result = decodeFilter(proto); // Instead of a singletonList containing AND(F1, F2, ...), we can return a list containing F1, - // F2, ... - // TODO(orquery): Once proper support for composite filters has been completed, we can remove - // this flattening from here. + // F2, ... to stay consistent with the older SDK versions. if (result instanceof com.google.firebase.firestore.core.CompositeFilter) { com.google.firebase.firestore.core.CompositeFilter compositeFilter = (com.google.firebase.firestore.core.CompositeFilter) result; diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/core/FilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/core/FilterTest.java index 1fdbc88951b..0c5e55e2c51 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/core/FilterTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/core/FilterTest.java @@ -17,6 +17,7 @@ import static com.google.firebase.firestore.testutil.TestUtil.andFilters; import static com.google.firebase.firestore.testutil.TestUtil.filter; import static com.google.firebase.firestore.testutil.TestUtil.orFilters; +import static com.google.firebase.firestore.testutil.TestUtil.query; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -85,4 +86,11 @@ public void testCompositeFilterNestedChecks() { assertFalse(orFilter2.isFlat()); assertFalse(orFilter2.isFlatConjunction()); } + + @Test + public void testCanonicalIdOfFlatConjunctions() { + Target target1 = query("col").filter(A).filter(B).filter(C).toTarget(); + Target target2 = query("col").filter(andFilters(A, B, C)).toTarget(); + assertEquals(target1.getCanonicalId(), target2.getCanonicalId()); + } }