Skip to content
This repository was archived by the owner on May 8, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
417b288
Remove TODOs and add tests for OR Query support.
ehsannas Aug 9, 2022
1a8b103
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Aug 10, 2022
de8b441
Merge branch 'main' into ehsann/or-query
meredithslota Nov 10, 2022
96ee72f
Address comments and backport a new test.
ehsannas Jan 10, 2023
86e64da
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Jan 10, 2023
d9e124f
Merge remote-tracking branch 'origin/main' into or-query-tests-2
ehsannas Feb 15, 2023
498808c
Target backend for integration tests.
ehsannas Feb 15, 2023
c05d33c
Fix: uninitialized 'firestore' variable.
ehsannas Feb 15, 2023
34e2ba9
Merge remote-tracking branch 'origin/main' into or-query-tests-2
ehsannas Feb 16, 2023
94163ec
Add the docs.
ehsannas Feb 16, 2023
19778e2
Merge remote-tracking branch 'origin/main' into or-query-tests-2
ehsannas Feb 16, 2023
a92435a
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Feb 16, 2023
7bc622d
Merge remote-tracking branch 'origin/main' into or-query-new
ehsannas Feb 17, 2023
b412f2f
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Feb 17, 2023
e591104
Merge remote-tracking branch 'origin/main' into or-query-new
ehsannas Feb 21, 2023
4e1e371
Add test dependency.
ehsannas Feb 27, 2023
4dd8047
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Feb 27, 2023
14a92ef
Remove tests that require composite index and unsupported cases.
ehsannas Mar 3, 2023
4f9a7f4
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Mar 3, 2023
f49ce68
Remove the 'hide' annotation.
ehsannas Mar 3, 2023
f0445af
Rearrange/add tests.
ehsannas Mar 3, 2023
99463b0
remove duplicate test which is run only against emulator.
ehsannas Mar 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,20 @@ If you are using Maven without BOM, add this to your dependencies:
If you are using Gradle 5.x or later, add this to your dependencies:

```Groovy
implementation platform('com.google.cloud:libraries-bom:26.8.0')
implementation platform('com.google.cloud:libraries-bom:26.9.0')

implementation 'com.google.cloud:google-cloud-firestore'
```
If you are using Gradle without BOM, add this to your dependencies:

```Groovy
implementation 'com.google.cloud:google-cloud-firestore:3.8.1'
implementation 'com.google.cloud:google-cloud-firestore:3.8.2'
```

If you are using SBT, add this to your dependencies:

```Scala
libraryDependencies += "com.google.cloud" % "google-cloud-firestore" % "3.8.1"
libraryDependencies += "com.google.cloud" % "google-cloud-firestore" % "3.8.2"
```

## Authentication
Expand Down
5 changes: 5 additions & 0 deletions google-cloud-firestore/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@
<version>3.12.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<reporting>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/** @hide */
public class Filter {
static class UnaryFilter extends Filter {
private final FieldPath field;
Expand Down Expand Up @@ -69,113 +68,269 @@ public StructuredQuery.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.fromDotSeparatedString(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.fromDotSeparatedString(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.fromDotSeparatedString(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.fromDotSeparatedString(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.fromDotSeparatedString(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.fromDotSeparatedString(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.fromDotSeparatedString(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 value 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.fromDotSeparatedString(field), value);
}

/**
* 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 value 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);
}

/**
* 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 value 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.fromDotSeparatedString(field), value);
}

/**
* 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 value 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);
}

/**
* 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 value 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.fromDotSeparatedString(field), value);
}

/**
* 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 value 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);
}

/**
* Creates a new filter that is a disjunction of the given filters. A disjunction filter includes
* a document if it satisfies <em>any</em> 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) {
// TODO(orquery): Change this to Operator.OR once it is available.
return new CompositeFilter(
Arrays.asList(filters), StructuredQuery.CompositeFilter.Operator.OPERATOR_UNSPECIFIED);
return new CompositeFilter(Arrays.asList(filters), StructuredQuery.CompositeFilter.Operator.OR);
}

/**
* Creates a new filter that is a conjunction of the given filters. A conjunction filter includes
* a document if it satisfies <em>all</em> of the given filters.
*
* @param filters The list of filters to perform a conjunction for.
* @return The newly created filter.
*/
@Nonnull
public static Filter and(Filter... filters) {
return new CompositeFilter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -888,8 +888,13 @@ public Query whereNotIn(@Nonnull FieldPath fieldPath, @Nonnull List<? extends Ob
return where(new com.google.cloud.firestore.Filter.UnaryFilter(fieldPath, NOT_IN, values));
}

// TODO(orquery): This method will become public API. Change visibility and add documentation.
Query where(com.google.cloud.firestore.Filter filter) {
/**
* Creates and returns a new Query with the additional filter.
*
* @param filter The new filter to apply to the existing query.
* @return The newly created Query.
*/
public Query where(com.google.cloud.firestore.Filter filter) {
Preconditions.checkState(
options.getStartCursor() == null && options.getEndCursor() == null,
"Cannot call a where() clause after defining a boundary with startAt(), "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,7 @@ public static StructuredQuery.Filter andFilters(StructuredQuery.Filter... filter
}

public static StructuredQuery.Filter orFilters(StructuredQuery.Filter... filters) {
// TODO(orquery): Replace this with Operator.OR once it's available.
return compositeFilter(CompositeFilter.Operator.OPERATOR_UNSPECIFIED, Arrays.asList(filters));
return compositeFilter(CompositeFilter.Operator.OR, Arrays.asList(filters));
}

private static StructuredQuery.Filter compositeFilter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1331,12 +1331,12 @@ public void serializationTestWithSingleFilterCompositeFilters() {
}

@Test
public void serializationTestWithNestedCompositeFilters() {
public void serializationTestWithNestedCompositeFiltersOuterAnd() {
assertSerialization(query);
// a IN [1,2]
query.where(inArray("a", Arrays.asList(1, 2)));
assertSerialization(query);
// a IN [1,2] && (b==20 || c==30 || (d==40 && e>50)) || f==60
// a IN [1,2] && (b==20 || c==30 || (d==40 && e>50) || f==60)
query.where(
or(
equalTo("b", 20),
Expand All @@ -1361,6 +1361,36 @@ public void serializationTestWithNestedCompositeFilters() {
assertSerialization(query);
}

@Test
public void serializationTestWithNestedCompositeFiltersOuterOr() {
assertSerialization(query);
// a IN [1,2] || (b==20 && c==30 && (d==40 || e>50) && f==60)
query.where(
or(
inArray("a", Arrays.asList(1, 2)),
and(
equalTo("b", 20),
equalTo("c", 30),
or(equalTo("d", 40), greaterThan("e", 50)),
and(equalTo("f", 60)),
or(and()))));
assertSerialization(query);
query = query.orderBy("l");
assertSerialization(query);
query = query.startAt("o");
assertSerialization(query);
query = query.startAfter("p");
assertSerialization(query);
query = query.endBefore("q");
assertSerialization(query);
query = query.endAt("r");
assertSerialization(query);
query = query.limit(8);
assertSerialization(query);
query = query.offset(9);
assertSerialization(query);
}

private void assertSerialization(Query query) {
RunQueryRequest runQueryRequest = query.toProto();
Query deserializedQuery = Query.fromProto(firestoreMock, runQueryRequest);
Expand Down
Loading