From fe05087659096748e4f6f0c72c7c185c0ef1ffc4 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 10 Oct 2024 16:32:14 -0400 Subject: [PATCH 01/77] Proto changes --- .../proto/google/firestore/v1/document.proto | 114 ++++++++++++++++++ .../proto/google/firestore/v1/firestore.proto | 84 +++++++++++++ .../proto/google/firestore/v1/pipeline.proto | 27 +++++ 3 files changed, 225 insertions(+) create mode 100644 firebase-firestore/src/proto/google/firestore/v1/pipeline.proto diff --git a/firebase-firestore/src/proto/google/firestore/v1/document.proto b/firebase-firestore/src/proto/google/firestore/v1/document.proto index 268947856a8..73b781df7a9 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/document.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/document.proto @@ -130,6 +130,50 @@ message Value { // A map value. MapValue map_value = 6; + + + // Value which references a field. + // + // This is considered relative (vs absolute) since it only refers to a field + // and not a field within a particular document. + // + // **Requires:** + // + // * Must follow [field reference][FieldReference.field_path] limitations. + // + // * Not allowed to be used when writing documents. + // + // (-- NOTE(batchik): long term, there is no reason this type should not be + // allowed to be used on the write path. --) + string field_reference_value = 19; + + // A value that represents an unevaluated expression. + // + // **Requires:** + // + // * Not allowed to be used when writing documents. + // + // (-- NOTE(batchik): similar to above, there is no reason to not allow + // storing expressions into the database, just no plan to support in + // the near term. + // + // This would actually be an interesting way to represent user-defined + // functions or more expressive rules-based systems. --) + Function function_value = 20; + + // A value that represents an unevaluated pipeline. + // + // **Requires:** + // + // * Not allowed to be used when writing documents. + // + // (-- NOTE(batchik): similar to above, there is no reason to not allow + // storing expressions into the database, just no plan to support in + // the near term. + // + // This would actually be an interesting way to represent user-defined + // functions or more expressive rules-based systems. --) + Pipeline pipeline_value = 21; } } @@ -149,3 +193,73 @@ message MapValue { // not exceed 1,500 bytes and cannot be empty. map fields = 1; } + +// Represents an unevaluated scalar expression. +// +// For example, the expression `like(user_name, "%alice%")` is represented as: +// +// ``` +// name: "like" +// args { field_reference: "user_name" } +// args { string_value: "%alice%" } +// ``` +// +// (-- api-linter: core::0123::resource-annotation=disabled +// aip.dev/not-precedent: this is not a One Platform API resource. --) +message Function { + // The name of the function to evaluate. + // + // **Requires:** + // + // * must be in snake case (lower case with underscore separator). + // + string name = 1; + + // Ordered list of arguments the given function expects. + repeated Value args = 2; + + // Optional named arguments that certain functions may support. + map options = 3; +} + +// A Firestore query represented as an ordered list of operations / stages. +message Pipeline { + // A single operation within a pipeline. + // + // A stage is made up of a unique name, and a list of arguments. The exact + // number of arguments & types is dependent on the stage type. + // + // To give an example, the stage `filter(state = "MD")` would be encoded as: + // + // ``` + // name: "filter" + // args { + // function_value { + // name: "eq" + // args { field_reference_value: "state" } + // args { string_value: "MD" } + // } + // } + // ``` + // + // See public documentation for the full list. + message Stage { + // The name of the stage to evaluate. + // + // **Requires:** + // + // * must be in snake case (lower case with underscore separator). + // + string name = 1; + + // Ordered list of arguments the given stage expects. + repeated Value args = 2; + + // Optional named arguments that certain functions may support. + map options = 3; + } + + // Ordered list of stages to evaluate. + repeated Stage stages = 1; +} + diff --git a/firebase-firestore/src/proto/google/firestore/v1/firestore.proto b/firebase-firestore/src/proto/google/firestore/v1/firestore.proto index 1bf75ea3c15..25e0b8dc76a 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/firestore.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/firestore.proto @@ -21,6 +21,7 @@ import "google/api/annotations.proto"; import "google/firestore/v1/aggregation_result.proto"; import "google/firestore/v1/common.proto"; import "google/firestore/v1/document.proto"; +import "google/firestore/v1/pipeline.proto"; import "google/firestore/v1/query.proto"; import "google/firestore/v1/write.proto"; import "google/protobuf/empty.proto"; @@ -138,6 +139,15 @@ service Firestore { }; } + // Executes a pipeline query. + rpc ExecutePipeline(ExecutePipelineRequest) + returns (stream ExecutePipelineResponse) { + option (google.api.http) = { + post: "/v1beta1/{database=projects/*/databases/*}:executePipeline" + body: "*" + }; + } + // Runs an aggregation query. // // Rather than producing [Document][google.firestore.v1.Document] results like [Firestore.RunQuery][google.firestore.v1.Firestore.RunQuery], @@ -510,6 +520,80 @@ message RunQueryResponse { int32 skipped_results = 4; } +// The request for [Firestore.ExecutePipeline][]. +message ExecutePipelineRequest { + // Database identifier, in the form `projects/{project}/databases/{database}`. + string database = 1; + + oneof pipeline_type { + // A pipelined operation. + StructuredPipeline structured_pipeline = 2; + } + + // Optional consistency arguments, defaults to strong consistency. + oneof consistency_selector { + // Run the query within an already active transaction. + // + // The value here is the opaque transaction ID to execute the query in. + bytes transaction = 5; + + // Execute the pipeline in a new transaction. + // + // The identifier of the newly created transaction will be returned in the + // first response on the stream. This defaults to a read-only transaction. + TransactionOptions new_transaction = 6; + + // Execute the pipeline in a snapshot transaction at the given time. + // + // This must be a microsecond precision timestamp within the past one hour, + // or if Point-in-Time Recovery is enabled, can additionally be a whole + // minute timestamp within the past 7 days. + google.protobuf.Timestamp read_time = 7; + } + + // Explain / analyze options for the pipeline. + // ExplainOptions explain_options = 8 [(google.api.field_behavior) = OPTIONAL]; +} + +// The response for [Firestore.Execute][]. +message ExecutePipelineResponse { + // Newly created transaction identifier. + // + // This field is only specified on the first response from the server when + // the request specified [ExecuteRequest.new_transaction][]. + bytes transaction = 1; + + // An ordered batch of results returned executing a pipeline. + // + // The batch size is variable, and can even be zero for when only a partial + // progress message is returned. + // + // The fields present in the returned documents are only those that were + // explicitly requested in the pipeline, this include those like + // [`__name__`][Document.name] & [`__update_time__`][Document.update_time]. + // This is explicitly a divergence from `Firestore.RunQuery` / + // `Firestore.GetDocument` RPCs which always return such fields even when they + // are not specified in the [`mask`][DocumentMask]. + repeated Document results = 2; + + // The time at which the document(s) were read. + // + // This may be monotonically increasing; in this case, the previous documents + // in the result stream are guaranteed not to have changed between their + // `execution_time` and this one. + // + // If the query returns no results, a response with `execution_time` and no + // `results` will be sent, and this represents the time at which the operation + // was run. + google.protobuf.Timestamp execution_time = 3; + + // Query explain metrics. + // + // Set on the last response when [ExecutePipelineRequest.explain_options][] + // was specified on the request. + // ExplainMetrics explain_metrics = 4; +} + // The request for [Firestore.RunAggregationQuery][google.firestore.v1.Firestore.RunAggregationQuery]. message RunAggregationQueryRequest { // Required. The parent resource name. In the format: diff --git a/firebase-firestore/src/proto/google/firestore/v1/pipeline.proto b/firebase-firestore/src/proto/google/firestore/v1/pipeline.proto new file mode 100644 index 00000000000..0a198cd6e29 --- /dev/null +++ b/firebase-firestore/src/proto/google/firestore/v1/pipeline.proto @@ -0,0 +1,27 @@ + +syntax = "proto3"; +package google.firestore.v1; +import "google/firestore/v1/document.proto"; +option csharp_namespace = "Google.Cloud.Firestore.V1"; +option php_namespace = "Google\\Cloud\\Firestore\\V1"; +option ruby_package = "Google::Cloud::Firestore::V1"; +option java_multiple_files = true; +option java_package = "com.google.firestore.v1"; +option java_outer_classname = "PipelineProto"; +option objc_class_prefix = "GCFS"; +// A Firestore query represented as an ordered list of operations / stages. +// +// This is considered the top-level function which plans & executes a query. +// It is logically equivalent to `query(stages, options)`, but prevents the +// client from having to build a function wrapper. +message StructuredPipeline { + // The pipeline query to execute. + Pipeline pipeline = 1; + // Optional query-level arguments. + // + // (-- Think query statement hints. --) + // + // (-- TODO(batchik): define the api contract of using an unsupported hint --) + map options = 2; +} + From 159cb37679facd57b64c3742ba94a5b8c11d251a Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 10 Oct 2024 16:35:11 -0400 Subject: [PATCH 02/77] Copyright --- .../src/proto/google/firestore/v1/pipeline.proto | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/firebase-firestore/src/proto/google/firestore/v1/pipeline.proto b/firebase-firestore/src/proto/google/firestore/v1/pipeline.proto index 0a198cd6e29..f425ec6911a 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/pipeline.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/pipeline.proto @@ -1,3 +1,16 @@ +// Copyright 2024 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. syntax = "proto3"; package google.firestore.v1; From 282409a1bd5827523c1b37307dc814d3cdcfccd5 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 24 Jan 2025 12:50:56 -0500 Subject: [PATCH 03/77] Expressions --- .../google/firebase/firestore/FieldPath.java | 14 +- .../firebase/firestore/model/FieldPath.java | 5 +- .../firebase/firestore/pipeline/Constant.kt | 84 ++++ .../firebase/firestore/pipeline/expression.kt | 444 ++++++++++++++++++ 4 files changed, 542 insertions(+), 5 deletions(-) create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FieldPath.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FieldPath.java index 2b5302cff19..a4293fc530b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FieldPath.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FieldPath.java @@ -18,6 +18,8 @@ import static com.google.firebase.firestore.util.Preconditions.checkNotNull; import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; + import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; @@ -33,15 +35,17 @@ public final class FieldPath { private final com.google.firebase.firestore.model.FieldPath internalPath; - private FieldPath(List segments) { + private FieldPath(@NonNull List segments) { this.internalPath = com.google.firebase.firestore.model.FieldPath.fromSegments(segments); } - private FieldPath(com.google.firebase.firestore.model.FieldPath internalPath) { + private FieldPath(@NonNull com.google.firebase.firestore.model.FieldPath internalPath) { this.internalPath = internalPath; } - com.google.firebase.firestore.model.FieldPath getInternalPath() { + @RestrictTo(RestrictTo.Scope.LIBRARY) + @NonNull + public com.google.firebase.firestore.model.FieldPath getInternalPath() { return internalPath; } @@ -78,7 +82,9 @@ public static FieldPath documentId() { } /** Parses a field path string into a {@code FieldPath}, treating dots as separators. */ - static FieldPath fromDotSeparatedPath(@NonNull String path) { + @RestrictTo(RestrictTo.Scope.LIBRARY) + @NonNull + public static FieldPath fromDotSeparatedPath(@NonNull String path) { checkNotNull(path, "Provided field path must not be null."); checkArgument( !RESERVED.matcher(path).find(), "Use FieldPath.of() for field names containing '~*/[]'."); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java index c1de25410fe..f28b07ff750 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java @@ -14,6 +14,8 @@ package com.google.firebase.firestore.model; +import androidx.annotation.NonNull; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -34,7 +36,8 @@ public static FieldPath fromSingleSegment(String fieldName) { } /** Creates a {@code FieldPath} from a list of parsed field path segments. */ - public static FieldPath fromSegments(List segments) { + @NonNull + public static FieldPath fromSegments(@NonNull List segments) { return segments.isEmpty() ? FieldPath.EMPTY_PATH : new FieldPath(segments); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt new file mode 100644 index 00000000000..69834c80e6f --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt @@ -0,0 +1,84 @@ +package com.google.firebase.firestore.pipeline + +import com.google.firebase.Timestamp +import com.google.firebase.firestore.Blob +import com.google.firebase.firestore.DocumentReference +import com.google.firebase.firestore.FieldValue +import com.google.firebase.firestore.GeoPoint +import com.google.firebase.firestore.VectorValue +import com.google.firestore.v1.Value +import java.util.Date + +class Constant internal constructor(val value: Any?) : Expr() { + + companion object { + fun of(value: Any): Constant { + return when (value) { + is String -> of(value) + is Number -> of(value) + is Date -> of(value) + is Timestamp -> of(value) + is Boolean -> of(value) + is GeoPoint -> of(value) + is Blob -> of(value) + is DocumentReference -> of(value) + is Value -> of(value) + is Iterable<*> -> of(value) + is Map<*, *> -> of(value) + else -> throw IllegalArgumentException("Unknown type: $value") + } + } + + fun of(value: String): Constant { + return Constant(value) + } + + fun of(value: Number): Constant { + return Constant(value) + } + + fun of(value: Date): Constant { + return Constant(value) + } + + fun of(value: Timestamp): Constant { + return Constant(value) + } + + fun of(value: Boolean): Constant { + return Constant(value) + } + + fun of(value: GeoPoint): Constant { + return Constant(value) + } + + fun of(value: Blob): Constant { + return Constant(value) + } + + fun of(value: DocumentReference): Constant { + return Constant(value) + } + + fun of(value: Value): Constant { + return Constant(value) + } + + fun of(value: VectorValue) : Constant { + return Constant(value) + } + + fun nullValue(): Constant { + return Constant(null) + } + + fun vector(value: DoubleArray): Constant { + return of(FieldValue.vector(value)) + } + + fun vector(value: VectorValue): Constant { + return of(value) + } + } +} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt new file mode 100644 index 00000000000..47f348a95bb --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt @@ -0,0 +1,444 @@ +package com.google.firebase.firestore.pipeline + +import com.google.firebase.firestore.FieldPath +import com.google.firebase.firestore.VectorValue +import com.google.firebase.firestore.model.DocumentKey +import com.google.firebase.firestore.model.FieldPath as ModelFieldPath + +open class Expr protected constructor() { + companion object { + internal fun toExprOrConstant(other: Any): Expr { + return when (other) { + is Expr -> other + else -> Constant.of(other) + } + } + + internal fun toArrayOfExprOrConstant(others: Array): Array { + return others.map(::toExprOrConstant).toTypedArray() + } + } + + /** + * Creates an expression that this expression to another expression. + * + *

Example: + * + *

{@code
+     * // Add the value of the 'quantity' field and the 'reserve' field.
+     * Field.of("quantity").add(Field.of("reserve"));
+     * }
+ * + * @param other The expression to add to this expression. + * @return A new {@code Expr} representing the addition operation. + */ + fun add(other: Expr): Add { + return Add(this, other) + } + + /** + * Creates an expression that this expression to another expression. + * + *

Example: + * + *

{@code
+     * // Add the value of the 'quantity' field and the 'reserve' field.
+     * Field.of("quantity").add(Field.of("reserve"));
+     * }
+ * + * @param other The constant value to add to this expression. + * @return A new {@code Expr} representing the addition operation. + */ + fun add(other: Any): Add { + return Add(this, toExprOrConstant(other)) + } + + fun subtract(other: Expr): Subtract { + return Subtract(this, other) + } +} + +class Field private constructor(val fieldPath: ModelFieldPath) : Expr() { + companion object { + fun of(name: String): Field { + if (name == DocumentKey.KEY_FIELD_NAME) { + return Field(ModelFieldPath.KEY_PATH) + } + return Field(FieldPath.fromDotSeparatedPath(name).internalPath) + } + + fun of(fieldPath: FieldPath): Field { + if (fieldPath == FieldPath.documentId()) { + return Field(FieldPath.documentId().internalPath) + } + return Field(fieldPath.internalPath) + } + } +} + +class ListOfExpr(val expressions: Array) : Expr() { + constructor(vararg expressions: Expr) : this(arrayOf(*expressions)) + constructor(vararg expressions: Any) : this(expressions.map(::toExprOrConstant).toTypedArray()) +} + +open class Function protected constructor( + private val name: String, + private val params: Array +) : Expr() { + protected constructor(name: String, vararg params: Expr) : this(name, arrayOf(*params)) +} + +open class FilterCondition protected constructor( + name: String, + vararg params: Expr +) : Function(name, *params) + +open class Accumulator protected constructor( + name: String, + params: Array +) : Function(name, params) { + protected constructor(name: String, vararg params: Expr) : this(name, arrayOf(*params)) + protected constructor(name: String, param: Expr?) : this(name, if (param == null) emptyArray() else arrayOf(param)) +} + +class Add(left: Expr, right: Expr) : Function("add", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Subtract(left: Expr, right: Expr) : Function("subtract", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Multiply(left: Expr, right: Expr) : Function("multiply", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Divide(left: Expr, right: Expr) : Function("divide", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Mod(left: Expr, right: Expr) : Function("mod", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +// class BitAnd(left: Expr, right: Expr) : Function("bit_and", left, right) { +// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) +// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) +// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +//} + +// class BitOr(left: Expr, right: Expr) : Function("bit_or", left, right) { +// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) +// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) +// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +//} + +// class BitXor(left: Expr, right: Expr) : Function("bit_xor", left, right) { +// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) +// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) +// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +//} + +// class BitNot(left: Expr, right: Expr) : Function("bit_not", left, right) { +// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) +// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) +// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +//} + +// class BitLeftShift(left: Expr, right: Expr) : Function("bit_left_shift", left, right) { +// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) +// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) +// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +//} + +// class BitRightShift(left: Expr, right: Expr) : Function("bit_right_shift", left, right) { +// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) +// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) +// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +//} + +class Eq(left: Expr, right: Expr) : FilterCondition("eq", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Neq(left: Expr, right: Expr) : FilterCondition("neq", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Lt(left: Expr, right: Expr) : FilterCondition("lt", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Lte(left: Expr, right: Expr) : FilterCondition("lte", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Gt(left: Expr, right: Expr) : FilterCondition("gt", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Gte(left: Expr, right: Expr) : FilterCondition("gte", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class ArrayConcat(array: Expr, vararg arrays: Expr) : Function("array_concat", array, *arrays) { + constructor(array: Expr, arrays: List) : this(array, toExprOrConstant(arrays)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class ArrayReverse(array: Expr) : Function("array_reverse", array) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class ArrayContains(array: Expr, value: Expr) : FilterCondition("array_contains", array, value) { + constructor(array: Expr, right: Any) : this(array, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class ArrayContainsAll(array: Expr, values: List) : FilterCondition("array_contains_all", array, ListOfExpr(values)) { + constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) +} + +class ArrayContainsAny(array: Expr, values: List) : FilterCondition("array_contains_any", array, ListOfExpr(values)) { + constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) +} + +class ArrayLength(array: Expr) : Function("array_length", array) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class In(array: Expr, values: List) : FilterCondition("in", array, ListOfExpr(values)) { + constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) +} + +class IsNan(expr: Expr) : FilterCondition("is_nan", expr) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Exists(expr: Expr) : FilterCondition("exists", expr) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Not(expr: Expr) : FilterCondition("not", expr) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class And(condition: Expr, vararg conditions: Expr) : FilterCondition("and", condition, *conditions) { + constructor(condition: Expr, vararg conditions: Any) : this(condition, *toArrayOfExprOrConstant(conditions)) + constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) + constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) +} + +class Or(condition: Expr, vararg conditions: Expr) : FilterCondition("or", condition, *conditions) { + constructor(condition: Expr, vararg conditions: Any) : this(condition, *toArrayOfExprOrConstant(conditions)) + constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) + constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) +} + +class Xor(condition: Expr, vararg conditions: Expr) : FilterCondition("xor", condition, *conditions) { + constructor(condition: Expr, vararg conditions: Any) : this(condition, *toArrayOfExprOrConstant(conditions)) + constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) + constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) +} + +class If(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr) : Function("if", condition, thenExpr, elseExpr) + +class LogicalMax(left: Expr, right: Expr) : Function("logical_max", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class LogicalMin(left: Expr, right: Expr) : Function("logical_min", left, right) { + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) +} + +class Reverse(expr: Expr) : Function("reverse", expr) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class ReplaceFirst(value: Expr, find: Expr, replace: Expr) : Function("replace_first", value, find, replace) { + constructor(value: Expr, find: String, replace: String) : this(value, Constant.of(find), Constant.of(replace)) + constructor(fieldName: String, find: String, replace: String) : this(Field.of(fieldName), find, replace) +} + +class ReplaceAll(value: Expr, find: Expr, replace: Expr) : Function("replace_all", value, find, replace) { + constructor(value: Expr, find: String, replace: String) : this(value, Constant.of(find), Constant.of(replace)) + constructor(fieldName: String, find: String, replace: String) : this(Field.of(fieldName), find, replace) +} + +class CharLength(value: Expr) : Function("char_length", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class ByteLength(value: Expr) : Function("byte_length", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Like(expr: Expr, pattern: Expr) : FilterCondition("like", expr, pattern) { + constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) + constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) + constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) +} + +class RegexContains(expr: Expr, pattern: Expr) : FilterCondition("regex_contains", expr, pattern) { + constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) + constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) + constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) +} + +class RegexMatch(expr: Expr, pattern: Expr) : FilterCondition("regex_match", expr, pattern) { + constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) + constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) + constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) +} + +class StrContains(expr: Expr, substring: Expr) : FilterCondition("str_contains", expr, substring) { + constructor(expr: Expr, substring: String) : this(expr, Constant.of(substring)) + constructor(fieldName: String, substring: Expr) : this(Field.of(fieldName), substring) + constructor(fieldName: String, substring: String) : this(Field.of(fieldName), substring) +} + +class StartsWith(expr: Expr, prefix: Expr) : FilterCondition("starts_with", expr, prefix) { + constructor(expr: Expr, prefix: String) : this(expr, Constant.of(prefix)) + constructor(fieldName: String, prefix: Expr) : this(Field.of(fieldName), prefix) + constructor(fieldName: String, prefix: String) : this(Field.of(fieldName), prefix) +} + +class EndsWith(expr: Expr, suffix: Expr) : FilterCondition("ends_with", expr, suffix) { + constructor(expr: Expr, suffix: String) : this(expr, Constant.of(suffix)) + constructor(fieldName: String, suffix: Expr) : this(Field.of(fieldName), suffix) + constructor(fieldName: String, suffix: String) : this(Field.of(fieldName), suffix) +} + +class ToLower(expr: Expr) : Function("to_lower", expr) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class ToUpper(expr: Expr) : Function("to_upper", expr) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Trim(expr: Expr) : Function("trim", expr) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class StrConcat internal constructor(first: Expr, vararg rest: Expr) : Function("str_concat", first, *rest) { + constructor(first: Expr, vararg rest: String) : this(first, *rest.map(Constant::of).toTypedArray()) + constructor(fieldName: String, vararg rest: Expr) : this(Field.of(fieldName), *rest) + constructor(fieldName: String, vararg rest: String) : this(Field.of(fieldName), *rest) +} + +class MapGet(map: Expr, name: String) : Function("map_get", map, Constant.of(name)) { + constructor(fieldName: String, name: String) : this(Field.of(fieldName), name) +} + +class Count(value: Expr?) : Accumulator("count", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Sum(value: Expr) : Accumulator("sum", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Avg(value: Expr) : Accumulator("avg", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Min(value: Expr) : Accumulator("min", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Max(value: Expr) : Accumulator("max", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class CosineDistance(vector1: Expr, vector2: Expr) : Function("cosine_distance", vector1, vector2) { + constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) + constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) + constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) +} + +class DotProduct(vector1: Expr, vector2: Expr) : Function("dot_product", vector1, vector2) { + constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) + constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) + constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) +} + +class EuclideanDistance(vector1: Expr, vector2: Expr) : Function("euclidean_distance", vector1, vector2) { + constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) + constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) + constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) +} + +class VectorLength(vector: Expr) : Function("vector_length", vector) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class UnixMicrosToTimestamp(input: Expr) : Function("unix_micros_to_timestamp", input) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class TimestampToUnixMicros(input: Expr) : Function("timestamp_to_unix_micros", input) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class UnixMillisToTimestamp(input: Expr) : Function("unix_millis_to_timestamp", input) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class TimestampToUnixMillis(input: Expr) : Function("timestamp_to_unix_millis", input) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class UnixSecondsToTimestamp(input: Expr) : Function("unix_seconds_to_timestamp", input) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class TimestampToUnixSeconds(input: Expr) : Function("timestamp_to_unix_seconds", input) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class TimestampAdd(timestamp: Expr, unit: Expr, amount: Expr) : Function("timestamp_add", timestamp, unit, amount) { + constructor(timestamp: Expr, unit: String, amount: Double) : this(timestamp, Constant.of(unit), Constant.of(amount)) + constructor(fieldName: String, unit: String, amount: Double) : this(Field.of(fieldName), unit, amount) + constructor(fieldName: String, unit: Expr, amount: Expr) : this(Field.of(fieldName), unit, amount) +} + +class TimestampSub(timestamp: Expr, unit: Expr, amount: Expr) : Function("timestamp_sub", timestamp, unit, amount) { + constructor(timestamp: Expr, unit: String, amount: Double) : this(timestamp, Constant.of(unit), Constant.of(amount)) + constructor(fieldName: String, unit: String, amount: Double) : this(Field.of(fieldName), unit, amount) + constructor(fieldName: String, unit: Expr, amount: Expr) : this(Field.of(fieldName), unit, amount) +} From 7f95bb5b907d41a1b35dd7ba39c391c5e0ded344 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 3 Feb 2025 11:34:59 -0500 Subject: [PATCH 04/77] Test --- .../firebase/firestore/pipeline/ExprTest.java | 16 ++++++++++++++++ .../firebase/firestore/pipeline/StageTest.java | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java create mode 100644 firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java new file mode 100644 index 00000000000..2d7e3b47243 --- /dev/null +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java @@ -0,0 +1,16 @@ +package com.google.firebase.firestore.pipeline; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class ExprTest { + + @Test + public void test() { + + } +} diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java new file mode 100644 index 00000000000..938960c5bab --- /dev/null +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java @@ -0,0 +1,16 @@ +package com.google.firebase.firestore.pipeline; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class StageTest { + + @Test + public void test() { + + } +} From 2ec848d690f9ceef325094aa9580e62c4a97d505 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 3 Feb 2025 11:36:02 -0500 Subject: [PATCH 05/77] Stage --- .../firebase/firestore/pipeline/stage.kt | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt new file mode 100644 index 00000000000..516db44bc4e --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -0,0 +1,44 @@ +package com.google.firebase.firestore.pipeline + +import com.google.firebase.firestore.DocumentReference +import com.google.firestore.v1.Pipeline +import com.google.firestore.v1.Value + +abstract class Stage(protected val name: String) { + internal fun toProtoStage(): Pipeline.Stage { + val builder = Pipeline.Stage.newBuilder() + builder.setName(name) + args().forEach { arg -> builder.addArgs(arg) } + return builder.build(); + } + protected abstract fun args(): Sequence +} + +class DatabaseSource : Stage("database") { + override fun args(): Sequence { + return emptySequence() + } +} + +class CollectionSource internal constructor(path: String) : Stage("collection") { + private val path: String = if (path.startsWith("/")) path else "/" + path + override fun args(): Sequence { + return sequenceOf(Value.newBuilder().setReferenceValue(path).build()) + } +} + +class CollectionGroupSource internal constructor(val collectionId: String): Stage("collection_group") { + override fun args(): Sequence { + return sequenceOf( + Value.newBuilder().setReferenceValue("").build(), + Value.newBuilder().setStringValue(collectionId).build() + ) + } +} + +class DocumentsSource private constructor(private val documents: List) : Stage("documents") { + internal constructor(documents: Array) : this(documents.map { docRef -> "/" + docRef.path }) + override fun args(): Sequence { + return documents.asSequence().map { doc -> Value.newBuilder().setStringValue(doc).build() } + } +} From 16bb38ca4ed881686489a18228ec8adfb382f465 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 3 Feb 2025 11:42:45 -0500 Subject: [PATCH 06/77] Pipeline --- .../firebase/firestore/FirebaseFirestore.java | 5 + .../com/google/firebase/firestore/Pipeline.kt | 122 ++++++++++++++++++ .../firestore/core/FirestoreClient.java | 6 + .../firebase/firestore/remote/Datastore.java | 44 +++++++ .../firestore/remote/RemoteStore.java | 12 ++ 5 files changed, 189 insertions(+) create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java index c1218829b8a..079619647ab 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java @@ -881,4 +881,9 @@ void validateReference(DocumentReference docRef) { static void setClientLanguage(@NonNull String languageToken) { FirestoreChannel.setClientLanguage(languageToken); } + + @NonNull + public PipelineSource pipeline() { + return new PipelineSource(this); + } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt new file mode 100644 index 00000000000..44e0c61cae3 --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -0,0 +1,122 @@ +package com.google.firebase.firestore + +import com.google.android.gms.tasks.Task +import com.google.android.gms.tasks.TaskCompletionSource +import com.google.common.collect.FluentIterable +import com.google.common.collect.ImmutableList +import com.google.firebase.firestore.model.DocumentKey +import com.google.firebase.firestore.model.SnapshotVersion +import com.google.firebase.firestore.pipeline.CollectionGroupSource +import com.google.firebase.firestore.pipeline.CollectionSource +import com.google.firebase.firestore.pipeline.DatabaseSource +import com.google.firebase.firestore.pipeline.DocumentsSource +import com.google.firebase.firestore.pipeline.Stage +import com.google.firestore.v1.ExecutePipelineRequest +import com.google.firestore.v1.StructuredPipeline +import com.google.firestore.v1.Value + +class Pipeline internal constructor( + internal val firestore: FirebaseFirestore, + internal val stages: FluentIterable +) { + internal constructor(firestore: FirebaseFirestore, stage: Stage) : this(firestore, FluentIterable.of(stage)) + + private fun append(stage: Stage): Pipeline { + return Pipeline(firestore, stages.append(stage)) + } + + fun execute(): Task { + val observerTask = ObserverSnapshotTask() + execute(observerTask); + return observerTask.task + } + + private fun execute(observer: PipelineResultObserver) { + firestore.callClient { call -> call!!.executePipeline(toProto(), observer) } + } + + internal fun documentReference(key: DocumentKey): DocumentReference { + return DocumentReference(key, firestore) + } + + fun toProto(): ExecutePipelineRequest { + val database = firestore.databaseId + val builder = ExecutePipelineRequest.newBuilder() + builder.database = "projects/${database.projectId}/databases/${database.databaseId}" + builder.structuredPipeline = toStructuredPipelineProto() + return builder.build() + } + + private fun toStructuredPipelineProto(): StructuredPipeline { + val builder = StructuredPipeline.newBuilder() + builder.pipeline = toPipelineProto() + return builder.build() + } + + private fun toPipelineProto(): com.google.firestore.v1.Pipeline = + com.google.firestore.v1.Pipeline.newBuilder() + .addAllStages(stages.map(Stage::toProtoStage)) + .build() + + private inner class ObserverSnapshotTask : PipelineResultObserver { + private val taskCompletionSource = TaskCompletionSource() + private val results: ImmutableList.Builder = ImmutableList.builder() + override fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) { + results.add( + PipelineResult( + if (key == null) null else DocumentReference(key, firestore), + data, + version + ) + ) + } + + override fun onComplete(executionTime: SnapshotVersion) { + taskCompletionSource.setResult(PipelineSnapshot(executionTime, results.build())) + } + + override fun onError(exception: FirebaseFirestoreException) { + taskCompletionSource.setException(exception) + } + + val task: Task + get() = taskCompletionSource.task + } +} + +class PipelineSource( + private val firestore: FirebaseFirestore +) { + fun collection(path: String): Pipeline { + return Pipeline(firestore, CollectionSource(path)) + } + + fun collectionGroup(collectionId: String): Pipeline { + return Pipeline(firestore, CollectionGroupSource(collectionId)) + } + + fun database(): Pipeline { + return Pipeline(firestore, DatabaseSource()) + } + + fun documents(vararg documents: DocumentReference): Pipeline { + return Pipeline(firestore, DocumentsSource(documents)) + } +} + +class PipelineSnapshot internal constructor( + val executionTime: SnapshotVersion, + val results: List +) + +class PipelineResult internal constructor( + private val key: DocumentReference?, + val fields: Map, + val version: SnapshotVersion, +) + +interface PipelineResultObserver { + fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) + fun onComplete(executionTime: SnapshotVersion) + fun onError(exception: FirebaseFirestoreException) +} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FirestoreClient.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FirestoreClient.java index 6e2d9b87b84..d54e3458d52 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FirestoreClient.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FirestoreClient.java @@ -27,6 +27,7 @@ import com.google.firebase.firestore.FirebaseFirestoreException; import com.google.firebase.firestore.FirebaseFirestoreException.Code; import com.google.firebase.firestore.LoadBundleTask; +import com.google.firebase.firestore.PipelineResultObserver; import com.google.firebase.firestore.TransactionOptions; import com.google.firebase.firestore.auth.CredentialsProvider; import com.google.firebase.firestore.auth.User; @@ -49,6 +50,7 @@ import com.google.firebase.firestore.util.AsyncQueue; import com.google.firebase.firestore.util.Function; import com.google.firebase.firestore.util.Logger; +import com.google.firestore.v1.ExecutePipelineRequest; import com.google.firestore.v1.Value; import java.io.InputStream; import java.util.List; @@ -249,6 +251,10 @@ public Task> runAggregateQuery( return result.getTask(); } + public void executePipeline(ExecutePipelineRequest request, PipelineResultObserver observer) { + asyncQueue.enqueueAndForget(() -> remoteStore.executePipeline(request, observer)); + } + /** * Returns a task resolves when all the pending writes at the time when this method is called * received server acknowledgement. An acknowledgement can be either acceptance or rejections. diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java index 87365361be4..db9e06ad219 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java @@ -23,6 +23,7 @@ import com.google.android.gms.tasks.TaskCompletionSource; import com.google.firebase.firestore.AggregateField; import com.google.firebase.firestore.FirebaseFirestoreException; +import com.google.firebase.firestore.PipelineResultObserver; import com.google.firebase.firestore.core.Query; import com.google.firebase.firestore.model.DocumentKey; import com.google.firebase.firestore.model.MutableDocument; @@ -34,6 +35,8 @@ import com.google.firestore.v1.BatchGetDocumentsResponse; import com.google.firestore.v1.CommitRequest; import com.google.firestore.v1.CommitResponse; +import com.google.firestore.v1.ExecutePipelineRequest; +import com.google.firestore.v1.ExecutePipelineResponse; import com.google.firestore.v1.FirestoreGrpc; import com.google.firestore.v1.RunAggregationQueryRequest; import com.google.firestore.v1.RunAggregationQueryResponse; @@ -237,6 +240,47 @@ public Task> runAggregateQuery( }); } + public void executePipeline( + ExecutePipelineRequest request, + PipelineResultObserver observer + ) { + channel + .runStreamingResponseRpc(FirestoreGrpc.getExecutePipelineMethod(), request, new FirestoreChannel.StreamingListener() { + + private SnapshotVersion executionTime = SnapshotVersion.NONE; + + @Override + public void onMessage(ExecutePipelineResponse message) { + setExecutionTime(serializer.decodeVersion(message.getExecutionTime())); + message.getResultsList().forEach(document -> observer.onDocument( + document.getName() == null ? null : serializer.decodeKey(document.getName()), + document.getFieldsMap(), + serializer.decodeVersion(document.getUpdateTime()) + )); + } + + @Override + public void onClose(Status status) { + if (status.isOk()) { + observer.onComplete(executionTime); + } else { + FirebaseFirestoreException exception = exceptionFromStatus(status); + if (exception.getCode() == FirebaseFirestoreException.Code.UNAUTHENTICATED) { + channel.invalidateToken(); + } + observer.onError(exception); + } + } + + private void setExecutionTime(SnapshotVersion executionTime) { + if (executionTime.equals(SnapshotVersion.NONE)) { + return; + } + this.executionTime = executionTime; + } + }); + } + /** * Determines whether the given status has an error code that represents a permanent error when * received in response to a non-write operation. diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java index d2a139d4b6f..05f2bfa9837 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java @@ -23,6 +23,7 @@ import com.google.firebase.database.collection.ImmutableSortedSet; import com.google.firebase.firestore.AggregateField; import com.google.firebase.firestore.FirebaseFirestoreException; +import com.google.firebase.firestore.PipelineResultObserver; import com.google.firebase.firestore.core.OnlineState; import com.google.firebase.firestore.core.Query; import com.google.firebase.firestore.core.Transaction; @@ -43,6 +44,7 @@ import com.google.firebase.firestore.util.AsyncQueue; import com.google.firebase.firestore.util.Logger; import com.google.firebase.firestore.util.Util; +import com.google.firestore.v1.ExecutePipelineRequest; import com.google.firestore.v1.Value; import com.google.protobuf.ByteString; import io.grpc.Status; @@ -777,4 +779,14 @@ public Task> runAggregateQuery( "Failed to get result from server.", FirebaseFirestoreException.Code.UNAVAILABLE)); } } + + public void executePipeline(ExecutePipelineRequest request, PipelineResultObserver observer) { + if (canUseNetwork()) { + datastore.executePipeline(request, observer); + } else { + observer.onError( + new FirebaseFirestoreException( + "Failed to get result from server.", FirebaseFirestoreException.Code.UNAVAILABLE)); + } + } } From a8361ca490d86b8c8ff884c537de2cd7844add8f Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 3 Feb 2025 13:06:54 -0500 Subject: [PATCH 07/77] Fix --- .../firebase/firestore/pipeline/expression.kt | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt index 47f348a95bb..4f169e522a0 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt @@ -14,7 +14,11 @@ open class Expr protected constructor() { } } - internal fun toArrayOfExprOrConstant(others: Array): Array { + internal fun toArrayOfExprOrConstant(others: Iterable): Array { + return others.map(::toExprOrConstant).toTypedArray() + } + + internal fun toArrayOfExprOrConstant(others: Array): Array { return others.map(::toExprOrConstant).toTypedArray() } } @@ -76,28 +80,26 @@ class Field private constructor(val fieldPath: ModelFieldPath) : Expr() { } } -class ListOfExpr(val expressions: Array) : Expr() { - constructor(vararg expressions: Expr) : this(arrayOf(*expressions)) - constructor(vararg expressions: Any) : this(expressions.map(::toExprOrConstant).toTypedArray()) -} +class ListOfExpr(val expressions: Array) : Expr() open class Function protected constructor( private val name: String, - private val params: Array + private val params: Array ) : Expr() { - protected constructor(name: String, vararg params: Expr) : this(name, arrayOf(*params)) + protected constructor(name: String, param1: Expr) : this(name, arrayOf(param1)) + protected constructor(name: String, param1: Expr, param2: Expr) : this(name, arrayOf(param1, param2)) + protected constructor(name: String, param1: Expr, param2: Expr, param3: Expr) : this(name, arrayOf(param1, param2, param3)) } open class FilterCondition protected constructor( name: String, vararg params: Expr -) : Function(name, *params) +) : Function(name, params) open class Accumulator protected constructor( name: String, - params: Array + params: Array ) : Function(name, params) { - protected constructor(name: String, vararg params: Expr) : this(name, arrayOf(*params)) protected constructor(name: String, param: Expr?) : this(name, if (param == null) emptyArray() else arrayOf(param)) } @@ -203,10 +205,10 @@ class Gte(left: Expr, right: Expr) : FilterCondition("gte", left, right) { constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } -class ArrayConcat(array: Expr, vararg arrays: Expr) : Function("array_concat", array, *arrays) { +class ArrayConcat(array: Expr, vararg arrays: Expr) : Function("array_concat", arrayOf(array, *arrays)) { constructor(array: Expr, arrays: List) : this(array, toExprOrConstant(arrays)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, vararg arrays: Expr) : this(Field.of(fieldName), *arrays) + constructor(fieldName: String, right: List) : this(Field.of(fieldName), right) } class ArrayReverse(array: Expr) : Function("array_reverse", array) { @@ -219,11 +221,11 @@ class ArrayContains(array: Expr, value: Expr) : FilterCondition("array_contains" constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } -class ArrayContainsAll(array: Expr, values: List) : FilterCondition("array_contains_all", array, ListOfExpr(values)) { +class ArrayContainsAll(array: Expr, values: List) : FilterCondition("array_contains_all", array, ListOfExpr(toArrayOfExprOrConstant(values))) { constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) } -class ArrayContainsAny(array: Expr, values: List) : FilterCondition("array_contains_any", array, ListOfExpr(values)) { +class ArrayContainsAny(array: Expr, values: List) : FilterCondition("array_contains_any", array, ListOfExpr(toArrayOfExprOrConstant(values))) { constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) } @@ -231,7 +233,7 @@ class ArrayLength(array: Expr) : Function("array_length", array) { constructor(fieldName: String) : this(Field.of(fieldName)) } -class In(array: Expr, values: List) : FilterCondition("in", array, ListOfExpr(values)) { +class In(array: Expr, values: List) : FilterCondition("in", array, ListOfExpr(toArrayOfExprOrConstant(values))) { constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) } @@ -349,7 +351,7 @@ class Trim(expr: Expr) : Function("trim", expr) { constructor(fieldName: String) : this(Field.of(fieldName)) } -class StrConcat internal constructor(first: Expr, vararg rest: Expr) : Function("str_concat", first, *rest) { +class StrConcat internal constructor(first: Expr, vararg rest: Expr) : Function("str_concat", arrayOf(first, *rest)) { constructor(first: Expr, vararg rest: String) : this(first, *rest.map(Constant::of).toTypedArray()) constructor(fieldName: String, vararg rest: Expr) : this(Field.of(fieldName), *rest) constructor(fieldName: String, vararg rest: String) : this(Field.of(fieldName), *rest) From a0da1508300fe6aefbbf74601300f2b11cd530d7 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 3 Feb 2025 18:22:50 -0500 Subject: [PATCH 08/77] Spotless --- .../google/firebase/firestore/FieldPath.java | 2 +- .../com/google/firebase/firestore/Pipeline.kt | 172 +++--- .../firebase/firestore/model/FieldPath.java | 1 - .../firebase/firestore/pipeline/Constant.kt | 138 ++--- .../firebase/firestore/pipeline/expression.kt | 525 ++++++++++-------- .../firebase/firestore/pipeline/stage.kt | 56 +- .../firebase/firestore/remote/Datastore.java | 26 +- .../firebase/firestore/pipeline/ExprTest.java | 4 +- .../firestore/pipeline/StageTest.java | 4 +- 9 files changed, 495 insertions(+), 433 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FieldPath.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FieldPath.java index a4293fc530b..fe353b3391b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FieldPath.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FieldPath.java @@ -19,7 +19,6 @@ import androidx.annotation.NonNull; import androidx.annotation.RestrictTo; - import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; @@ -43,6 +42,7 @@ private FieldPath(@NonNull com.google.firebase.firestore.model.FieldPath interna this.internalPath = internalPath; } + /** @hide */ @RestrictTo(RestrictTo.Scope.LIBRARY) @NonNull public com.google.firebase.firestore.model.FieldPath getInternalPath() { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 44e0c61cae3..c75e7106c4e 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -15,108 +15,108 @@ import com.google.firestore.v1.ExecutePipelineRequest import com.google.firestore.v1.StructuredPipeline import com.google.firestore.v1.Value -class Pipeline internal constructor( - internal val firestore: FirebaseFirestore, - internal val stages: FluentIterable +class Pipeline +internal constructor( + internal val firestore: FirebaseFirestore, + internal val stages: FluentIterable ) { - internal constructor(firestore: FirebaseFirestore, stage: Stage) : this(firestore, FluentIterable.of(stage)) - - private fun append(stage: Stage): Pipeline { - return Pipeline(firestore, stages.append(stage)) - } - - fun execute(): Task { - val observerTask = ObserverSnapshotTask() - execute(observerTask); - return observerTask.task - } - - private fun execute(observer: PipelineResultObserver) { - firestore.callClient { call -> call!!.executePipeline(toProto(), observer) } - } - - internal fun documentReference(key: DocumentKey): DocumentReference { - return DocumentReference(key, firestore) + internal constructor( + firestore: FirebaseFirestore, + stage: Stage + ) : this(firestore, FluentIterable.of(stage)) + + private fun append(stage: Stage): Pipeline { + return Pipeline(firestore, stages.append(stage)) + } + + fun execute(): Task { + val observerTask = ObserverSnapshotTask() + execute(observerTask) + return observerTask.task + } + + private fun execute(observer: PipelineResultObserver) { + firestore.callClient { call -> call!!.executePipeline(toProto(), observer) } + } + + internal fun documentReference(key: DocumentKey): DocumentReference { + return DocumentReference(key, firestore) + } + + fun toProto(): ExecutePipelineRequest { + val database = firestore.databaseId + val builder = ExecutePipelineRequest.newBuilder() + builder.database = "projects/${database.projectId}/databases/${database.databaseId}" + builder.structuredPipeline = toStructuredPipelineProto() + return builder.build() + } + + private fun toStructuredPipelineProto(): StructuredPipeline { + val builder = StructuredPipeline.newBuilder() + builder.pipeline = toPipelineProto() + return builder.build() + } + + private fun toPipelineProto(): com.google.firestore.v1.Pipeline = + com.google.firestore.v1.Pipeline.newBuilder() + .addAllStages(stages.map(Stage::toProtoStage)) + .build() + + private inner class ObserverSnapshotTask : PipelineResultObserver { + private val taskCompletionSource = TaskCompletionSource() + private val results: ImmutableList.Builder = ImmutableList.builder() + override fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) { + results.add( + PipelineResult(if (key == null) null else DocumentReference(key, firestore), data, version) + ) } - fun toProto(): ExecutePipelineRequest { - val database = firestore.databaseId - val builder = ExecutePipelineRequest.newBuilder() - builder.database = "projects/${database.projectId}/databases/${database.databaseId}" - builder.structuredPipeline = toStructuredPipelineProto() - return builder.build() + override fun onComplete(executionTime: SnapshotVersion) { + taskCompletionSource.setResult(PipelineSnapshot(executionTime, results.build())) } - private fun toStructuredPipelineProto(): StructuredPipeline { - val builder = StructuredPipeline.newBuilder() - builder.pipeline = toPipelineProto() - return builder.build() + override fun onError(exception: FirebaseFirestoreException) { + taskCompletionSource.setException(exception) } - private fun toPipelineProto(): com.google.firestore.v1.Pipeline = - com.google.firestore.v1.Pipeline.newBuilder() - .addAllStages(stages.map(Stage::toProtoStage)) - .build() - - private inner class ObserverSnapshotTask : PipelineResultObserver { - private val taskCompletionSource = TaskCompletionSource() - private val results: ImmutableList.Builder = ImmutableList.builder() - override fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) { - results.add( - PipelineResult( - if (key == null) null else DocumentReference(key, firestore), - data, - version - ) - ) - } - - override fun onComplete(executionTime: SnapshotVersion) { - taskCompletionSource.setResult(PipelineSnapshot(executionTime, results.build())) - } - - override fun onError(exception: FirebaseFirestoreException) { - taskCompletionSource.setException(exception) - } - - val task: Task - get() = taskCompletionSource.task - } + val task: Task + get() = taskCompletionSource.task + } } -class PipelineSource( - private val firestore: FirebaseFirestore -) { - fun collection(path: String): Pipeline { - return Pipeline(firestore, CollectionSource(path)) - } +class PipelineSource(private val firestore: FirebaseFirestore) { + fun collection(path: String): Pipeline { + return Pipeline(firestore, CollectionSource(path)) + } - fun collectionGroup(collectionId: String): Pipeline { - return Pipeline(firestore, CollectionGroupSource(collectionId)) - } + fun collectionGroup(collectionId: String): Pipeline { + return Pipeline(firestore, CollectionGroupSource(collectionId)) + } - fun database(): Pipeline { - return Pipeline(firestore, DatabaseSource()) - } + fun database(): Pipeline { + return Pipeline(firestore, DatabaseSource()) + } - fun documents(vararg documents: DocumentReference): Pipeline { - return Pipeline(firestore, DocumentsSource(documents)) - } + fun documents(vararg documents: DocumentReference): Pipeline { + return Pipeline(firestore, DocumentsSource(documents)) + } } -class PipelineSnapshot internal constructor( - val executionTime: SnapshotVersion, - val results: List +class PipelineSnapshot +internal constructor( + private val executionTime: SnapshotVersion, + private val results: List ) -class PipelineResult internal constructor( - private val key: DocumentReference?, - val fields: Map, - val version: SnapshotVersion, +class PipelineResult +internal constructor( + private val key: DocumentReference?, + private val fields: Map, + private val version: SnapshotVersion, ) -interface PipelineResultObserver { - fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) - fun onComplete(executionTime: SnapshotVersion) - fun onError(exception: FirebaseFirestoreException) +internal interface PipelineResultObserver { + fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) + fun onComplete(executionTime: SnapshotVersion) + fun onError(exception: FirebaseFirestoreException) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java index f28b07ff750..051dfce922b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java @@ -15,7 +15,6 @@ package com.google.firebase.firestore.model; import androidx.annotation.NonNull; - import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt index 69834c80e6f..4ff2a25ee86 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt @@ -11,74 +11,74 @@ import java.util.Date class Constant internal constructor(val value: Any?) : Expr() { - companion object { - fun of(value: Any): Constant { - return when (value) { - is String -> of(value) - is Number -> of(value) - is Date -> of(value) - is Timestamp -> of(value) - is Boolean -> of(value) - is GeoPoint -> of(value) - is Blob -> of(value) - is DocumentReference -> of(value) - is Value -> of(value) - is Iterable<*> -> of(value) - is Map<*, *> -> of(value) - else -> throw IllegalArgumentException("Unknown type: $value") - } - } - - fun of(value: String): Constant { - return Constant(value) - } - - fun of(value: Number): Constant { - return Constant(value) - } - - fun of(value: Date): Constant { - return Constant(value) - } - - fun of(value: Timestamp): Constant { - return Constant(value) - } - - fun of(value: Boolean): Constant { - return Constant(value) - } - - fun of(value: GeoPoint): Constant { - return Constant(value) - } - - fun of(value: Blob): Constant { - return Constant(value) - } - - fun of(value: DocumentReference): Constant { - return Constant(value) - } - - fun of(value: Value): Constant { - return Constant(value) - } - - fun of(value: VectorValue) : Constant { - return Constant(value) - } - - fun nullValue(): Constant { - return Constant(null) - } - - fun vector(value: DoubleArray): Constant { - return of(FieldValue.vector(value)) - } - - fun vector(value: VectorValue): Constant { - return of(value) - } + companion object { + fun of(value: Any): Constant { + return when (value) { + is String -> of(value) + is Number -> of(value) + is Date -> of(value) + is Timestamp -> of(value) + is Boolean -> of(value) + is GeoPoint -> of(value) + is Blob -> of(value) + is DocumentReference -> of(value) + is Value -> of(value) + is Iterable<*> -> of(value) + is Map<*, *> -> of(value) + else -> throw IllegalArgumentException("Unknown type: $value") + } } + + fun of(value: String): Constant { + return Constant(value) + } + + fun of(value: Number): Constant { + return Constant(value) + } + + fun of(value: Date): Constant { + return Constant(value) + } + + fun of(value: Timestamp): Constant { + return Constant(value) + } + + fun of(value: Boolean): Constant { + return Constant(value) + } + + fun of(value: GeoPoint): Constant { + return Constant(value) + } + + fun of(value: Blob): Constant { + return Constant(value) + } + + fun of(value: DocumentReference): Constant { + return Constant(value) + } + + fun of(value: Value): Constant { + return Constant(value) + } + + fun of(value: VectorValue): Constant { + return Constant(value) + } + + fun nullValue(): Constant { + return Constant(null) + } + + fun vector(value: DoubleArray): Constant { + return of(FieldValue.vector(value)) + } + + fun vector(value: VectorValue): Constant { + return of(value) + } + } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt index 4f169e522a0..b5449fc570b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt @@ -6,441 +6,500 @@ import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.FieldPath as ModelFieldPath open class Expr protected constructor() { - companion object { - internal fun toExprOrConstant(other: Any): Expr { - return when (other) { - is Expr -> other - else -> Constant.of(other) - } - } - - internal fun toArrayOfExprOrConstant(others: Iterable): Array { - return others.map(::toExprOrConstant).toTypedArray() - } - - internal fun toArrayOfExprOrConstant(others: Array): Array { - return others.map(::toExprOrConstant).toTypedArray() - } + companion object { + internal fun toExprOrConstant(other: Any): Expr { + return when (other) { + is Expr -> other + else -> Constant.of(other) + } } - /** - * Creates an expression that this expression to another expression. - * - *

Example: - * - *

{@code
-     * // Add the value of the 'quantity' field and the 'reserve' field.
-     * Field.of("quantity").add(Field.of("reserve"));
-     * }
- * - * @param other The expression to add to this expression. - * @return A new {@code Expr} representing the addition operation. - */ - fun add(other: Expr): Add { - return Add(this, other) + internal fun toArrayOfExprOrConstant(others: Iterable): Array { + return others.map(::toExprOrConstant).toTypedArray() } - /** - * Creates an expression that this expression to another expression. - * - *

Example: - * - *

{@code
-     * // Add the value of the 'quantity' field and the 'reserve' field.
-     * Field.of("quantity").add(Field.of("reserve"));
-     * }
- * - * @param other The constant value to add to this expression. - * @return A new {@code Expr} representing the addition operation. - */ - fun add(other: Any): Add { - return Add(this, toExprOrConstant(other)) + internal fun toArrayOfExprOrConstant(others: Array): Array { + return others.map(::toExprOrConstant).toTypedArray() } - - fun subtract(other: Expr): Subtract { - return Subtract(this, other) + } + + /** + * Creates an expression that this expression to another expression. + * + *

Example: + * + *

{@code // Add the value of the 'quantity' field and the 'reserve' field.
+   * Field.of("quantity").add(Field.of("reserve")); }
+ * + * @param other The expression to add to this expression. + * @return A new {@code Expr} representing the addition operation. + */ + fun add(other: Expr): Add { + return Add(this, other) + } + + /** + * Creates an expression that this expression to another expression. + * + *

Example: + * + *

{@code // Add the value of the 'quantity' field and the 'reserve' field.
+   * Field.of("quantity").add(Field.of("reserve")); }
+ * + * @param other The constant value to add to this expression. + * @return A new {@code Expr} representing the addition operation. + */ + fun add(other: Any): Add { + return Add(this, toExprOrConstant(other)) + } + + fun subtract(other: Expr): Subtract { + return Subtract(this, other) + } +} + +class Field private constructor(private val fieldPath: ModelFieldPath) : Expr() { + companion object { + fun of(name: String): Field { + if (name == DocumentKey.KEY_FIELD_NAME) { + return Field(ModelFieldPath.KEY_PATH) + } + return Field(FieldPath.fromDotSeparatedPath(name).internalPath) } -} -class Field private constructor(val fieldPath: ModelFieldPath) : Expr() { - companion object { - fun of(name: String): Field { - if (name == DocumentKey.KEY_FIELD_NAME) { - return Field(ModelFieldPath.KEY_PATH) - } - return Field(FieldPath.fromDotSeparatedPath(name).internalPath) - } - - fun of(fieldPath: FieldPath): Field { - if (fieldPath == FieldPath.documentId()) { - return Field(FieldPath.documentId().internalPath) - } - return Field(fieldPath.internalPath) - } + fun of(fieldPath: FieldPath): Field { + if (fieldPath == FieldPath.documentId()) { + return Field(FieldPath.documentId().internalPath) + } + return Field(fieldPath.internalPath) } + } } class ListOfExpr(val expressions: Array) : Expr() -open class Function protected constructor( - private val name: String, - private val params: Array -) : Expr() { - protected constructor(name: String, param1: Expr) : this(name, arrayOf(param1)) - protected constructor(name: String, param1: Expr, param2: Expr) : this(name, arrayOf(param1, param2)) - protected constructor(name: String, param1: Expr, param2: Expr, param3: Expr) : this(name, arrayOf(param1, param2, param3)) +open class Function +protected constructor(private val name: String, private val params: Array) : Expr() { + protected constructor(name: String, param1: Expr) : this(name, arrayOf(param1)) + protected constructor( + name: String, + param1: Expr, + param2: Expr + ) : this(name, arrayOf(param1, param2)) + protected constructor( + name: String, + param1: Expr, + param2: Expr, + param3: Expr + ) : this(name, arrayOf(param1, param2, param3)) } -open class FilterCondition protected constructor( - name: String, - vararg params: Expr -) : Function(name, params) +open class FilterCondition protected constructor(name: String, vararg params: Expr) : + Function(name, params) -open class Accumulator protected constructor( +open class Accumulator protected constructor(name: String, params: Array) : + Function(name, params) { + protected constructor( name: String, - params: Array -) : Function(name, params) { - protected constructor(name: String, param: Expr?) : this(name, if (param == null) emptyArray() else arrayOf(param)) + param: Expr? + ) : this(name, if (param == null) emptyArray() else arrayOf(param)) } class Add(left: Expr, right: Expr) : Function("add", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Subtract(left: Expr, right: Expr) : Function("subtract", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Multiply(left: Expr, right: Expr) : Function("multiply", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Divide(left: Expr, right: Expr) : Function("divide", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Mod(left: Expr, right: Expr) : Function("mod", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } // class BitAnd(left: Expr, right: Expr) : Function("bit_and", left, right) { // constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) // constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) // constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -//} +// } // class BitOr(left: Expr, right: Expr) : Function("bit_or", left, right) { // constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) // constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) // constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -//} +// } // class BitXor(left: Expr, right: Expr) : Function("bit_xor", left, right) { // constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) // constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) // constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -//} +// } // class BitNot(left: Expr, right: Expr) : Function("bit_not", left, right) { // constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) // constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) // constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -//} +// } // class BitLeftShift(left: Expr, right: Expr) : Function("bit_left_shift", left, right) { // constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) // constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) // constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -//} +// } // class BitRightShift(left: Expr, right: Expr) : Function("bit_right_shift", left, right) { // constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) // constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) // constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -//} +// } class Eq(left: Expr, right: Expr) : FilterCondition("eq", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Neq(left: Expr, right: Expr) : FilterCondition("neq", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Lt(left: Expr, right: Expr) : FilterCondition("lt", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Lte(left: Expr, right: Expr) : FilterCondition("lte", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Gt(left: Expr, right: Expr) : FilterCondition("gt", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Gte(left: Expr, right: Expr) : FilterCondition("gte", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } -class ArrayConcat(array: Expr, vararg arrays: Expr) : Function("array_concat", arrayOf(array, *arrays)) { - constructor(array: Expr, arrays: List) : this(array, toExprOrConstant(arrays)) - constructor(fieldName: String, vararg arrays: Expr) : this(Field.of(fieldName), *arrays) - constructor(fieldName: String, right: List) : this(Field.of(fieldName), right) +class ArrayConcat(array: Expr, vararg arrays: Expr) : + Function("array_concat", arrayOf(array, *arrays)) { + constructor(array: Expr, arrays: List) : this(array, toExprOrConstant(arrays)) + constructor(fieldName: String, vararg arrays: Expr) : this(Field.of(fieldName), *arrays) + constructor(fieldName: String, right: List) : this(Field.of(fieldName), right) } class ArrayReverse(array: Expr) : Function("array_reverse", array) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class ArrayContains(array: Expr, value: Expr) : FilterCondition("array_contains", array, value) { - constructor(array: Expr, right: Any) : this(array, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(array: Expr, right: Any) : this(array, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } -class ArrayContainsAll(array: Expr, values: List) : FilterCondition("array_contains_all", array, ListOfExpr(toArrayOfExprOrConstant(values))) { - constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) +class ArrayContainsAll(array: Expr, values: List) : + FilterCondition("array_contains_all", array, ListOfExpr(toArrayOfExprOrConstant(values))) { + constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) } -class ArrayContainsAny(array: Expr, values: List) : FilterCondition("array_contains_any", array, ListOfExpr(toArrayOfExprOrConstant(values))) { - constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) +class ArrayContainsAny(array: Expr, values: List) : + FilterCondition("array_contains_any", array, ListOfExpr(toArrayOfExprOrConstant(values))) { + constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) } class ArrayLength(array: Expr) : Function("array_length", array) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } -class In(array: Expr, values: List) : FilterCondition("in", array, ListOfExpr(toArrayOfExprOrConstant(values))) { - constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) +class In(array: Expr, values: List) : + FilterCondition("in", array, ListOfExpr(toArrayOfExprOrConstant(values))) { + constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) } class IsNan(expr: Expr) : FilterCondition("is_nan", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class Exists(expr: Expr) : FilterCondition("exists", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class Not(expr: Expr) : FilterCondition("not", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } -class And(condition: Expr, vararg conditions: Expr) : FilterCondition("and", condition, *conditions) { - constructor(condition: Expr, vararg conditions: Any) : this(condition, *toArrayOfExprOrConstant(conditions)) - constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) - constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) +class And(condition: Expr, vararg conditions: Expr) : + FilterCondition("and", condition, *conditions) { + constructor( + condition: Expr, + vararg conditions: Any + ) : this(condition, *toArrayOfExprOrConstant(conditions)) + constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) + constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) } class Or(condition: Expr, vararg conditions: Expr) : FilterCondition("or", condition, *conditions) { - constructor(condition: Expr, vararg conditions: Any) : this(condition, *toArrayOfExprOrConstant(conditions)) - constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) - constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) + constructor( + condition: Expr, + vararg conditions: Any + ) : this(condition, *toArrayOfExprOrConstant(conditions)) + constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) + constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) } -class Xor(condition: Expr, vararg conditions: Expr) : FilterCondition("xor", condition, *conditions) { - constructor(condition: Expr, vararg conditions: Any) : this(condition, *toArrayOfExprOrConstant(conditions)) - constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) - constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) +class Xor(condition: Expr, vararg conditions: Expr) : + FilterCondition("xor", condition, *conditions) { + constructor( + condition: Expr, + vararg conditions: Any + ) : this(condition, *toArrayOfExprOrConstant(conditions)) + constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) + constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) } -class If(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr) : Function("if", condition, thenExpr, elseExpr) +class If(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr) : + Function("if", condition, thenExpr, elseExpr) class LogicalMax(left: Expr, right: Expr) : Function("logical_max", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class LogicalMin(left: Expr, right: Expr) : Function("logical_min", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class Reverse(expr: Expr) : Function("reverse", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class ReplaceFirst(value: Expr, find: Expr, replace: Expr) : Function("replace_first", value, find, replace) { - constructor(value: Expr, find: String, replace: String) : this(value, Constant.of(find), Constant.of(replace)) - constructor(fieldName: String, find: String, replace: String) : this(Field.of(fieldName), find, replace) -} - -class ReplaceAll(value: Expr, find: Expr, replace: Expr) : Function("replace_all", value, find, replace) { - constructor(value: Expr, find: String, replace: String) : this(value, Constant.of(find), Constant.of(replace)) - constructor(fieldName: String, find: String, replace: String) : this(Field.of(fieldName), find, replace) + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class ReplaceFirst(value: Expr, find: Expr, replace: Expr) : + Function("replace_first", value, find, replace) { + constructor( + value: Expr, + find: String, + replace: String + ) : this(value, Constant.of(find), Constant.of(replace)) + constructor( + fieldName: String, + find: String, + replace: String + ) : this(Field.of(fieldName), find, replace) +} + +class ReplaceAll(value: Expr, find: Expr, replace: Expr) : + Function("replace_all", value, find, replace) { + constructor( + value: Expr, + find: String, + replace: String + ) : this(value, Constant.of(find), Constant.of(replace)) + constructor( + fieldName: String, + find: String, + replace: String + ) : this(Field.of(fieldName), find, replace) } class CharLength(value: Expr) : Function("char_length", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class ByteLength(value: Expr) : Function("byte_length", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class Like(expr: Expr, pattern: Expr) : FilterCondition("like", expr, pattern) { - constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) - constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) - constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) + constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) + constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) + constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) } class RegexContains(expr: Expr, pattern: Expr) : FilterCondition("regex_contains", expr, pattern) { - constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) - constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) - constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) + constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) + constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) + constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) } class RegexMatch(expr: Expr, pattern: Expr) : FilterCondition("regex_match", expr, pattern) { - constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) - constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) - constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) + constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) + constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) + constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) } class StrContains(expr: Expr, substring: Expr) : FilterCondition("str_contains", expr, substring) { - constructor(expr: Expr, substring: String) : this(expr, Constant.of(substring)) - constructor(fieldName: String, substring: Expr) : this(Field.of(fieldName), substring) - constructor(fieldName: String, substring: String) : this(Field.of(fieldName), substring) + constructor(expr: Expr, substring: String) : this(expr, Constant.of(substring)) + constructor(fieldName: String, substring: Expr) : this(Field.of(fieldName), substring) + constructor(fieldName: String, substring: String) : this(Field.of(fieldName), substring) } class StartsWith(expr: Expr, prefix: Expr) : FilterCondition("starts_with", expr, prefix) { - constructor(expr: Expr, prefix: String) : this(expr, Constant.of(prefix)) - constructor(fieldName: String, prefix: Expr) : this(Field.of(fieldName), prefix) - constructor(fieldName: String, prefix: String) : this(Field.of(fieldName), prefix) + constructor(expr: Expr, prefix: String) : this(expr, Constant.of(prefix)) + constructor(fieldName: String, prefix: Expr) : this(Field.of(fieldName), prefix) + constructor(fieldName: String, prefix: String) : this(Field.of(fieldName), prefix) } class EndsWith(expr: Expr, suffix: Expr) : FilterCondition("ends_with", expr, suffix) { - constructor(expr: Expr, suffix: String) : this(expr, Constant.of(suffix)) - constructor(fieldName: String, suffix: Expr) : this(Field.of(fieldName), suffix) - constructor(fieldName: String, suffix: String) : this(Field.of(fieldName), suffix) + constructor(expr: Expr, suffix: String) : this(expr, Constant.of(suffix)) + constructor(fieldName: String, suffix: Expr) : this(Field.of(fieldName), suffix) + constructor(fieldName: String, suffix: String) : this(Field.of(fieldName), suffix) } class ToLower(expr: Expr) : Function("to_lower", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class ToUpper(expr: Expr) : Function("to_upper", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class Trim(expr: Expr) : Function("trim", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } -class StrConcat internal constructor(first: Expr, vararg rest: Expr) : Function("str_concat", arrayOf(first, *rest)) { - constructor(first: Expr, vararg rest: String) : this(first, *rest.map(Constant::of).toTypedArray()) - constructor(fieldName: String, vararg rest: Expr) : this(Field.of(fieldName), *rest) - constructor(fieldName: String, vararg rest: String) : this(Field.of(fieldName), *rest) +class StrConcat internal constructor(first: Expr, vararg rest: Expr) : + Function("str_concat", arrayOf(first, *rest)) { + constructor( + first: Expr, + vararg rest: String + ) : this(first, *rest.map(Constant::of).toTypedArray()) + constructor(fieldName: String, vararg rest: Expr) : this(Field.of(fieldName), *rest) + constructor(fieldName: String, vararg rest: String) : this(Field.of(fieldName), *rest) } class MapGet(map: Expr, name: String) : Function("map_get", map, Constant.of(name)) { - constructor(fieldName: String, name: String) : this(Field.of(fieldName), name) + constructor(fieldName: String, name: String) : this(Field.of(fieldName), name) } class Count(value: Expr?) : Accumulator("count", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class Sum(value: Expr) : Accumulator("sum", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class Avg(value: Expr) : Accumulator("avg", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class Min(value: Expr) : Accumulator("min", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class Max(value: Expr) : Accumulator("max", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class CosineDistance(vector1: Expr, vector2: Expr) : Function("cosine_distance", vector1, vector2) { - constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) - constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) - constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) + constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) + constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) + constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) } class DotProduct(vector1: Expr, vector2: Expr) : Function("dot_product", vector1, vector2) { - constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) - constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) - constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) + constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) + constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) + constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) } -class EuclideanDistance(vector1: Expr, vector2: Expr) : Function("euclidean_distance", vector1, vector2) { - constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) - constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) - constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) +class EuclideanDistance(vector1: Expr, vector2: Expr) : + Function("euclidean_distance", vector1, vector2) { + constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) + constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) + constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) + constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) } class VectorLength(vector: Expr) : Function("vector_length", vector) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class UnixMicrosToTimestamp(input: Expr) : Function("unix_micros_to_timestamp", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class TimestampToUnixMicros(input: Expr) : Function("timestamp_to_unix_micros", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class UnixMillisToTimestamp(input: Expr) : Function("unix_millis_to_timestamp", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class TimestampToUnixMillis(input: Expr) : Function("timestamp_to_unix_millis", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class UnixSecondsToTimestamp(input: Expr) : Function("unix_seconds_to_timestamp", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String) : this(Field.of(fieldName)) } class TimestampToUnixSeconds(input: Expr) : Function("timestamp_to_unix_seconds", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class TimestampAdd(timestamp: Expr, unit: Expr, amount: Expr) : Function("timestamp_add", timestamp, unit, amount) { - constructor(timestamp: Expr, unit: String, amount: Double) : this(timestamp, Constant.of(unit), Constant.of(amount)) - constructor(fieldName: String, unit: String, amount: Double) : this(Field.of(fieldName), unit, amount) - constructor(fieldName: String, unit: Expr, amount: Expr) : this(Field.of(fieldName), unit, amount) -} - -class TimestampSub(timestamp: Expr, unit: Expr, amount: Expr) : Function("timestamp_sub", timestamp, unit, amount) { - constructor(timestamp: Expr, unit: String, amount: Double) : this(timestamp, Constant.of(unit), Constant.of(amount)) - constructor(fieldName: String, unit: String, amount: Double) : this(Field.of(fieldName), unit, amount) - constructor(fieldName: String, unit: Expr, amount: Expr) : this(Field.of(fieldName), unit, amount) + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class TimestampAdd(timestamp: Expr, unit: Expr, amount: Expr) : + Function("timestamp_add", timestamp, unit, amount) { + constructor( + timestamp: Expr, + unit: String, + amount: Double + ) : this(timestamp, Constant.of(unit), Constant.of(amount)) + constructor( + fieldName: String, + unit: String, + amount: Double + ) : this(Field.of(fieldName), unit, amount) + constructor(fieldName: String, unit: Expr, amount: Expr) : this(Field.of(fieldName), unit, amount) +} + +class TimestampSub(timestamp: Expr, unit: Expr, amount: Expr) : + Function("timestamp_sub", timestamp, unit, amount) { + constructor( + timestamp: Expr, + unit: String, + amount: Double + ) : this(timestamp, Constant.of(unit), Constant.of(amount)) + constructor( + fieldName: String, + unit: String, + amount: Double + ) : this(Field.of(fieldName), unit, amount) + constructor(fieldName: String, unit: Expr, amount: Expr) : this(Field.of(fieldName), unit, amount) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index 516db44bc4e..ce63d74389d 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -5,40 +5,44 @@ import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value abstract class Stage(protected val name: String) { - internal fun toProtoStage(): Pipeline.Stage { - val builder = Pipeline.Stage.newBuilder() - builder.setName(name) - args().forEach { arg -> builder.addArgs(arg) } - return builder.build(); - } - protected abstract fun args(): Sequence + internal fun toProtoStage(): Pipeline.Stage { + val builder = Pipeline.Stage.newBuilder() + builder.setName(name) + args().forEach { arg -> builder.addArgs(arg) } + return builder.build() + } + protected abstract fun args(): Sequence } class DatabaseSource : Stage("database") { - override fun args(): Sequence { - return emptySequence() - } + override fun args(): Sequence { + return emptySequence() + } } class CollectionSource internal constructor(path: String) : Stage("collection") { - private val path: String = if (path.startsWith("/")) path else "/" + path - override fun args(): Sequence { - return sequenceOf(Value.newBuilder().setReferenceValue(path).build()) - } + private val path: String = if (path.startsWith("/")) path else "/" + path + override fun args(): Sequence { + return sequenceOf(Value.newBuilder().setReferenceValue(path).build()) + } } -class CollectionGroupSource internal constructor(val collectionId: String): Stage("collection_group") { - override fun args(): Sequence { - return sequenceOf( - Value.newBuilder().setReferenceValue("").build(), - Value.newBuilder().setStringValue(collectionId).build() - ) - } +class CollectionGroupSource internal constructor(val collectionId: String) : + Stage("collection_group") { + override fun args(): Sequence { + return sequenceOf( + Value.newBuilder().setReferenceValue("").build(), + Value.newBuilder().setStringValue(collectionId).build() + ) + } } -class DocumentsSource private constructor(private val documents: List) : Stage("documents") { - internal constructor(documents: Array) : this(documents.map { docRef -> "/" + docRef.path }) - override fun args(): Sequence { - return documents.asSequence().map { doc -> Value.newBuilder().setStringValue(doc).build() } - } +class DocumentsSource private constructor(private val documents: List) : + Stage("documents") { + internal constructor( + documents: Array + ) : this(documents.map { docRef -> "/" + docRef.path }) + override fun args(): Sequence { + return documents.asSequence().map { doc -> Value.newBuilder().setStringValue(doc).build() } + } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java index db9e06ad219..9ea1d7513cb 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java @@ -240,23 +240,27 @@ public Task> runAggregateQuery( }); } - public void executePipeline( - ExecutePipelineRequest request, - PipelineResultObserver observer - ) { - channel - .runStreamingResponseRpc(FirestoreGrpc.getExecutePipelineMethod(), request, new FirestoreChannel.StreamingListener() { + public void executePipeline(ExecutePipelineRequest request, PipelineResultObserver observer) { + channel.runStreamingResponseRpc( + FirestoreGrpc.getExecutePipelineMethod(), + request, + new FirestoreChannel.StreamingListener() { private SnapshotVersion executionTime = SnapshotVersion.NONE; @Override public void onMessage(ExecutePipelineResponse message) { setExecutionTime(serializer.decodeVersion(message.getExecutionTime())); - message.getResultsList().forEach(document -> observer.onDocument( - document.getName() == null ? null : serializer.decodeKey(document.getName()), - document.getFieldsMap(), - serializer.decodeVersion(document.getUpdateTime()) - )); + message + .getResultsList() + .forEach( + document -> + observer.onDocument( + document.getName() == null + ? null + : serializer.decodeKey(document.getName()), + document.getFieldsMap(), + serializer.decodeVersion(document.getUpdateTime()))); } @Override diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java index 2d7e3b47243..4468151e344 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java @@ -10,7 +10,5 @@ public class ExprTest { @Test - public void test() { - - } + public void test() {} } diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java index 938960c5bab..eb1b03119f4 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java @@ -10,7 +10,5 @@ public class StageTest { @Test - public void test() { - - } + public void test() {} } From 0ce7d4f8410e13e381a14ff6c69a600101360f33 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 3 Feb 2025 18:39:55 -0500 Subject: [PATCH 09/77] Spotless --- .../firebase/firestore/remote/Datastore.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java index 9ea1d7513cb..8e7aab83565 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java @@ -35,6 +35,7 @@ import com.google.firestore.v1.BatchGetDocumentsResponse; import com.google.firestore.v1.CommitRequest; import com.google.firestore.v1.CommitResponse; +import com.google.firestore.v1.Document; import com.google.firestore.v1.ExecutePipelineRequest; import com.google.firestore.v1.ExecutePipelineResponse; import com.google.firestore.v1.FirestoreGrpc; @@ -251,16 +252,13 @@ public void executePipeline(ExecutePipelineRequest request, PipelineResultObserv @Override public void onMessage(ExecutePipelineResponse message) { setExecutionTime(serializer.decodeVersion(message.getExecutionTime())); - message - .getResultsList() - .forEach( - document -> - observer.onDocument( - document.getName() == null - ? null - : serializer.decodeKey(document.getName()), - document.getFieldsMap(), - serializer.decodeVersion(document.getUpdateTime()))); + for (Document document : message.getResultsList()) { + String documentName = document.getName(); + observer.onDocument( + documentName == null ? null : serializer.decodeKey(documentName), + document.getFieldsMap(), + serializer.decodeVersion(document.getUpdateTime())); + } } @Override From ab5f2173e8e92df3b30a228daa1ab15ba4ec286d Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 14 Feb 2025 20:23:58 -0500 Subject: [PATCH 10/77] Rename .java to .kt --- .../google/firebase/firestore/model/{Values.java => Values.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename firebase-firestore/src/main/java/com/google/firebase/firestore/model/{Values.java => Values.kt} (100%) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt similarity index 100% rename from firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.java rename to firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt From dec61c0b808c90751d701ef93efb465e2b91e284 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 14 Feb 2025 20:23:58 -0500 Subject: [PATCH 11/77] Work --- .../firebase/firestore/PipelineTest.java | 437 ++++++++ .../firestore/CollectionReference.java | 6 + .../firebase/firestore/DocumentReference.java | 12 +- .../firebase/firestore/DocumentSnapshot.java | 1 + .../firebase/firestore/FirebaseFirestore.java | 6 +- .../com/google/firebase/firestore/Pipeline.kt | 144 ++- .../firebase/firestore/UserDataReader.java | 91 +- .../firebase/firestore/VectorValue.java | 17 - .../firestore/model/ResourcePath.java | 12 +- .../google/firebase/firestore/model/Values.kt | 962 ++++++++++-------- .../firebase/firestore/pipeline/Constant.kt | 51 +- .../firestore/pipeline/accumulators.kt | 104 ++ .../firebase/firestore/pipeline/expression.kt | 488 +++++++-- .../firebase/firestore/pipeline/stage.kt | 172 +++- .../firebase/firestore/remote/Datastore.java | 3 +- .../firebase/firestore/TestAccessHelper.java | 6 +- 16 files changed, 1793 insertions(+), 719 deletions(-) create mode 100644 firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java new file mode 100644 index 00000000000..a88959dd930 --- /dev/null +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -0,0 +1,437 @@ +package com.google.firebase.firestore; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.firebase.firestore.pipeline.Function.and; +import static com.google.firebase.firestore.pipeline.Function.arrayContains; +import static com.google.firebase.firestore.pipeline.Function.arrayContainsAny; +import static com.google.firebase.firestore.pipeline.Function.eq; +import static com.google.firebase.firestore.pipeline.Function.gt; +import static com.google.firebase.firestore.pipeline.Function.or; +import static com.google.firebase.firestore.pipeline.Ordering.ascending; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.waitFor; +import static java.util.Map.entry; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.android.gms.tasks.Task; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.truth.Correspondence; +import com.google.firebase.firestore.pipeline.Accumulator; +import com.google.firebase.firestore.pipeline.AggregateStage; +import com.google.firebase.firestore.pipeline.Field; +import com.google.firebase.firestore.pipeline.Function; +import com.google.firebase.firestore.testutil.IntegrationTestUtil; +import java.util.Map; +import java.util.Objects; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class PipelineTest { + + private static final Correspondence> DATA_CORRESPONDENCE = Correspondence.from((result, expected) -> { + assertThat(result.getData()) + .comparingValuesUsing(Correspondence.from( + (x, y) -> { + if (x instanceof Long && y instanceof Integer) { + return (long) x == (long) (int) y; + } + return Objects.equals(x, y); + }, + "MapValueCompare" + )) + .containsExactlyEntriesIn(expected); + return true; + }, "GetData"); + + private static final Correspondence ID_CORRESPONDENCE = Correspondence.transforming(x -> x.getRef().getId(), "GetRefId"); + + private CollectionReference randomCol; + private FirebaseFirestore firestore; + + @After + public void tearDown() { + IntegrationTestUtil.tearDown(); + } + + private Map> bookDocs = + ImmutableMap.ofEntries( + entry( + "book1", + ImmutableMap.ofEntries( + entry("title", "The Hitchhiker's Guide to the Galaxy"), + entry("author", "Douglas Adams"), + entry("genre", "Science Fiction"), + entry("published", 1979), + entry("rating", 4.2), + entry("tags", ImmutableList.of("comedy", "space", "adventure")), + entry("awards", ImmutableMap.of("hugo", true, "nebula", false)))), + entry( + "book2", + ImmutableMap.ofEntries( + entry("title", "Pride and Prejudice"), + entry("author", "Jane Austen"), + entry("genre", "Romance"), + entry("published", 1813), + entry("rating", 4.5), + entry("tags", ImmutableList.of("classic", "social commentary", "love")), + entry("awards", ImmutableMap.of("none", true)))), + entry( + "book3", + ImmutableMap.ofEntries( + entry("title", "One Hundred Years of Solitude"), + entry("author", "Gabriel García Márquez"), + entry("genre", "Magical Realism"), + entry("published", 1967), + entry("rating", 4.3), + entry("tags", ImmutableList.of("family", "history", "fantasy")), + entry("awards", ImmutableMap.of("nobel", true, "nebula", false)))), + entry( + "book4", + ImmutableMap.ofEntries( + entry("title", "The Lord of the Rings"), + entry("author", "J.R.R. Tolkien"), + entry("genre", "Fantasy"), + entry("published", 1954), + entry("rating", 4.7), + entry("tags", ImmutableList.of("adventure", "magic", "epic")), + entry("awards", ImmutableMap.of("hugo", false, "nebula", false)))), + entry( + "book5", + ImmutableMap.ofEntries( + entry("title", "The Handmaid's Tale"), + entry("author", "Margaret Atwood"), + entry("genre", "Dystopian"), + entry("published", 1985), + entry("rating", 4.1), + entry("tags", ImmutableList.of("feminism", "totalitarianism", "resistance")), + entry( + "awards", ImmutableMap.of("arthur c. clarke", true, "booker prize", false)))), + entry( + "book6", + ImmutableMap.ofEntries( + entry("title", "Crime and Punishment"), + entry("author", "Fyodor Dostoevsky"), + entry("genre", "Psychological Thriller"), + entry("published", 1866), + entry("rating", 4.3), + entry("tags", ImmutableList.of("philosophy", "crime", "redemption")), + entry("awards", ImmutableMap.of("none", true)))), + entry( + "book7", + ImmutableMap.ofEntries( + entry("title", "To Kill a Mockingbird"), + entry("author", "Harper Lee"), + entry("genre", "Southern Gothic"), + entry("published", 1960), + entry("rating", 4.2), + entry("tags", ImmutableList.of("racism", "injustice", "coming-of-age")), + entry("awards", ImmutableMap.of("pulitzer", true)))), + entry( + "book8", + ImmutableMap.ofEntries( + entry("title", "1984"), + entry("author", "George Orwell"), + entry("genre", "Dystopian"), + entry("published", 1949), + entry("rating", 4.2), + entry("tags", ImmutableList.of("surveillance", "totalitarianism", "propaganda")), + entry("awards", ImmutableMap.of("prometheus", true)))), + entry( + "book9", + ImmutableMap.ofEntries( + entry("title", "The Great Gatsby"), + entry("author", "F. Scott Fitzgerald"), + entry("genre", "Modernist"), + entry("published", 1925), + entry("rating", 4.0), + entry("tags", ImmutableList.of("wealth", "american dream", "love")), + entry("awards", ImmutableMap.of("none", true)))), + entry( + "book10", + ImmutableMap.ofEntries( + entry("title", "Dune"), + entry("author", "Frank Herbert"), + entry("genre", "Science Fiction"), + entry("published", 1965), + entry("rating", 4.6), + entry("tags", ImmutableList.of("politics", "desert", "ecology")), + entry("awards", ImmutableMap.of("hugo", true, "nebula", true))))); + + @Before + public void setup() { + randomCol = IntegrationTestUtil.testCollectionWithDocs(bookDocs); + firestore = randomCol.firestore; + } + + @Test + public void emptyResults() { + Task execute = + firestore.pipeline().collection(randomCol.getPath()).limit(0).execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()).isEmpty(); + } + + @Test + public void fullResults() { + Task execute = firestore.pipeline().collection(randomCol.getPath()).execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()).hasSize(10); + } + + @Test + public void aggregateResultsCountAll() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .aggregate(Accumulator.countAll().as("count")) + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("count", 10)); + } + + @Test + @Ignore("Not supported yet") + public void aggregateResultsMany() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .where(Function.eq("genre", "Science Fiction")) + .aggregate( + Accumulator.countAll().as("count"), + Accumulator.avg("rating").as("avgRating"), + Field.of("rating").max().as("maxRating")) + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.ofEntries( + entry("count", 10), entry("avgRating", 4.4), entry("maxRating", 4.6))); + } + + @Test + public void groupAndAccumulateResults() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .where(Function.lt(Field.of("published"), 1984)) + .aggregate( + AggregateStage.withAccumulators(Accumulator.avg("rating").as("avgRating")) + .withGroups("genre")) + .where(Function.gt("avgRating", 4.3)) + .sort(Field.of("avgRating").descending()) + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.ofEntries(entry("avgRating", 4.7), entry("genre", "Fantasy")), + ImmutableMap.ofEntries(entry("avgRating", 4.5), entry("genre", "Romance")), + ImmutableMap.ofEntries(entry("avgRating", 4.4), entry("genre", "Science Fiction"))); + } + + @Test + @Ignore("Not supported yet") + public void minAndMaxAccumulations() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .aggregate( + Accumulator.countAll().as("count"), + Field.of("rating").max().as("maxRating"), + Field.of("published").min().as("minPublished")) + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.ofEntries( + entry("count", 10), entry("maxRating", 4.7), entry("minPublished", 1813))); + } + + @Test + public void canSelectFields() { + Task execute = + firestore.pipeline().collection(randomCol).select("title", "author").sort(Field.of("author").ascending()).execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.ofEntries( + entry("title", "The Hitchhiker's Guide to the Galaxy"), + entry("author", "Douglas Adams")), + ImmutableMap.ofEntries( + entry("title", "The Great Gatsby"), entry("author", "F. Scott Fitzgerald")), + ImmutableMap.ofEntries(entry("title", "Dune"), entry("author", "Frank Herbert")), + ImmutableMap.ofEntries( + entry("title", "Crime and Punishment"), entry("author", "Fyodor Dostoevsky")), + ImmutableMap.ofEntries( + entry("title", "One Hundred Years of Solitude"), + entry("author", "Gabriel García Márquez")), + ImmutableMap.ofEntries(entry("title", "1984"), entry("author", "George Orwell")), + ImmutableMap.ofEntries( + entry("title", "To Kill a Mockingbird"), entry("author", "Harper Lee")), + ImmutableMap.ofEntries( + entry("title", "The Lord of the Rings"), entry("author", "J.R.R. Tolkien")), + ImmutableMap.ofEntries( + entry("title", "Pride and Prejudice"), entry("author", "Jane Austen")), + ImmutableMap.ofEntries( + entry("title", "The Handmaid's Tale"), entry("author", "Margaret Atwood"))) + .inOrder(); + } + + @Test + public void whereWithAnd() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .where(and(gt("rating", 4.5), eq("genre", "Science Fiction"))) + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(ID_CORRESPONDENCE) + .containsExactly("book10"); + } + + @Test + public void whereWithOr() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .where(or(eq("genre", "Romance"), eq("genre", "Dystopian"))) + .select("title") + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("title", "Pride and Prejudice"), + ImmutableMap.of("title", "The Handmaid's Tale"), + ImmutableMap.of("title", "1984")); + } + + @Test + public void offsetAndLimits() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .sort(ascending("author")) + .offset(5) + .limit(3) + .select("title", "author") + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.ofEntries(entry("title", "1984"), entry("author", "George Orwell")), + ImmutableMap.ofEntries( + entry("title", "To Kill a Mockingbird"), entry("author", "Harper Lee")), + ImmutableMap.ofEntries( + entry("title", "The Lord of the Rings"), entry("author", "J.R.R. Tolkien"))); + } + + @Test + public void arrayContainsWorks() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .where(arrayContains("tags", "comedy")) + .select("title") + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("title", "The Hitchhiker's Guide to the Galaxy")); + } + + @Test + public void arrayContainsAnyWorks() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .where(arrayContainsAny("tags", ImmutableList.of("comedy", "classic"))) + .select("title") + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("title", "The Hitchhiker's Guide to the Galaxy"), + ImmutableMap.of("title", "Pride and Prejudice")); + } + + @Test + public void arrayContainsAllWorks() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .where(Field.of("tags").arrayContainsAll(ImmutableList.of("adventure", "magic"))) + .select("title") + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("title", "The Lord of the Rings")); + } + + @Test + public void arrayLengthWorks() { + Task execute = + randomCol + .pipeline() + .select(Field.of("tags").arrayLength().as("tagsCount")) + .where(eq("tagsCount", 3)) + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()).hasSize(10); + } + + @Test + @Ignore("Not supported yet") + public void arrayConcatWorks() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .where(eq("title", "The Hitchhiker's Guide to the Galaxy")) + .select(Field.of("tags").arrayConcat(ImmutableList.of("newTag1", "newTag2")).as("modifiedTags")) + .limit(1) + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("modifiedTags", ImmutableList.of("comedy", "space", "adventure", "newTag1", "newTag2"))); + } + + @Test + public void testStrConcat() { + Task execute = + randomCol + .pipeline() + .select(Field.of("author").strConcat(" - ", Field.of("title")).as("bookInfo")) + .limit(1) + .execute(); + PipelineSnapshot snapshot = waitFor(execute); + assertThat(snapshot.getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("bookInfo", "Douglas Adams - The Hitchhiker's Guide to the Galaxy")); + } +} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java index d0a358e2233..297d018c9d6 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java @@ -21,6 +21,7 @@ import com.google.android.gms.tasks.Task; import com.google.firebase.firestore.model.DocumentKey; import com.google.firebase.firestore.model.ResourcePath; +import com.google.firebase.firestore.pipeline.CollectionSource; import com.google.firebase.firestore.util.Executors; import com.google.firebase.firestore.util.Util; @@ -127,4 +128,9 @@ public Task add(@NonNull Object data) { return ref; }); } + + @NonNull + public Pipeline pipeline() { + return new Pipeline(firestore, new CollectionSource(getPath())); + } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentReference.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentReference.java index e3097d32b00..0161432843f 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentReference.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentReference.java @@ -57,7 +57,7 @@ * in test mocks. Subclassing is not supported in production code and new SDK releases may break * code that does so. */ -public class DocumentReference { +public final class DocumentReference { private final DocumentKey key; @@ -65,9 +65,7 @@ public class DocumentReference { DocumentReference(DocumentKey key, FirebaseFirestore firestore) { this.key = checkNotNull(key); - // TODO: We should checkNotNull(firestore), but tests are currently cheating - // and setting it to null. - this.firestore = firestore; + this.firestore = checkNotNull(firestore); } /** @hide */ @@ -564,6 +562,12 @@ public int hashCode() { return result; } + @NonNull + @Override + public String toString() { + return "DocumentReference{" + "key=" + key + ", firestore=" + firestore + '}'; + } + private com.google.firebase.firestore.core.Query asQuery() { return com.google.firebase.firestore.core.Query.atPath(key.getPath()); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentSnapshot.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentSnapshot.java index 4540608fc48..5c978b8cce9 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentSnapshot.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentSnapshot.java @@ -555,6 +555,7 @@ public int hashCode() { return hash; } + @NonNull @Override public String toString() { return "DocumentSnapshot{" + "key=" + key + ", metadata=" + metadata + ", doc=" + doc + '}'; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java index 079619647ab..557471c9b3d 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java @@ -23,6 +23,7 @@ import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; import androidx.annotation.VisibleForTesting; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; @@ -850,7 +851,9 @@ T callClient(Function call) { return clientProvider.call(call); } - DatabaseId getDatabaseId() { + @RestrictTo(RestrictTo.Scope.LIBRARY) + @NonNull + public DatabaseId getDatabaseId() { return databaseId; } @@ -884,6 +887,7 @@ static void setClientLanguage(@NonNull String languageToken) { @NonNull public PipelineSource pipeline() { + clientProvider.ensureConfigured(); return new PipelineSource(this); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index c75e7106c4e..4eb6ba5d1d6 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -6,11 +6,26 @@ import com.google.common.collect.FluentIterable import com.google.common.collect.ImmutableList import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.SnapshotVersion +import com.google.firebase.firestore.pipeline.AccumulatorWithAlias +import com.google.firebase.firestore.pipeline.AddFieldsStage +import com.google.firebase.firestore.pipeline.AggregateStage +import com.google.firebase.firestore.pipeline.BooleanExpr import com.google.firebase.firestore.pipeline.CollectionGroupSource import com.google.firebase.firestore.pipeline.CollectionSource import com.google.firebase.firestore.pipeline.DatabaseSource +import com.google.firebase.firestore.pipeline.DistinctStage import com.google.firebase.firestore.pipeline.DocumentsSource +import com.google.firebase.firestore.pipeline.Field +import com.google.firebase.firestore.pipeline.LimitStage +import com.google.firebase.firestore.pipeline.OffsetStage +import com.google.firebase.firestore.pipeline.Ordering +import com.google.firebase.firestore.pipeline.RemoveFieldsStage +import com.google.firebase.firestore.pipeline.SelectStage +import com.google.firebase.firestore.pipeline.Selectable +import com.google.firebase.firestore.pipeline.SortStage import com.google.firebase.firestore.pipeline.Stage +import com.google.firebase.firestore.pipeline.WhereStage +import com.google.firebase.firestore.util.Preconditions import com.google.firestore.v1.ExecutePipelineRequest import com.google.firestore.v1.StructuredPipeline import com.google.firestore.v1.Value @@ -31,19 +46,15 @@ internal constructor( fun execute(): Task { val observerTask = ObserverSnapshotTask() - execute(observerTask) + firestore.callClient { call -> call!!.executePipeline(toProto(), observerTask) } return observerTask.task } - private fun execute(observer: PipelineResultObserver) { - firestore.callClient { call -> call!!.executePipeline(toProto(), observer) } - } - internal fun documentReference(key: DocumentKey): DocumentReference { return DocumentReference(key, firestore) } - fun toProto(): ExecutePipelineRequest { + internal fun toProto(): ExecutePipelineRequest { val database = firestore.databaseId val builder = ExecutePipelineRequest.newBuilder() builder.database = "projects/${database.projectId}/databases/${database.databaseId}" @@ -57,17 +68,74 @@ internal constructor( return builder.build() } - private fun toPipelineProto(): com.google.firestore.v1.Pipeline = + internal fun toPipelineProto(): com.google.firestore.v1.Pipeline = com.google.firestore.v1.Pipeline.newBuilder() .addAllStages(stages.map(Stage::toProtoStage)) .build() - private inner class ObserverSnapshotTask : PipelineResultObserver { + fun addFields(vararg fields: Selectable): Pipeline { + return append(AddFieldsStage(fields)) + } + + fun removeFields(vararg fields: Field): Pipeline { + return append(RemoveFieldsStage(fields)) + } + + fun removeFields(vararg fields: String): Pipeline { + return append(RemoveFieldsStage(fields.map(Field::of).toTypedArray())) + } + + fun select(vararg fields: Selectable): Pipeline { + return append(SelectStage(fields)) + } + + fun select(vararg fields: String): Pipeline { + return append(SelectStage(fields.map(Field::of).toTypedArray())) + } + + fun sort(vararg orders: Ordering): Pipeline { + return append(SortStage(orders)) + } + + fun where(condition: BooleanExpr): Pipeline { + return append(WhereStage(condition)) + } + + fun offset(offset: Long): Pipeline { + return append(OffsetStage(offset)) + } + + fun limit(limit: Long): Pipeline { + return append(LimitStage(limit)) + } + + fun distinct(vararg groups: Selectable): Pipeline { + return append(DistinctStage(groups)) + } + + fun distinct(vararg groups: String): Pipeline { + return append(DistinctStage(groups.map(Field::of).toTypedArray())) + } + + fun aggregate(vararg accumulators: AccumulatorWithAlias): Pipeline { + return append(AggregateStage.withAccumulators(*accumulators)) + } + + fun aggregate(aggregateStage: AggregateStage): Pipeline { + return append(aggregateStage) + } + + private inner class ObserverSnapshotTask() : PipelineResultObserver { private val taskCompletionSource = TaskCompletionSource() private val results: ImmutableList.Builder = ImmutableList.builder() override fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) { results.add( - PipelineResult(if (key == null) null else DocumentReference(key, firestore), data, version) + PipelineResult( + firestore, + if (key == null) null else DocumentReference(key, firestore), + data, + version + ) ) } @@ -84,12 +152,26 @@ internal constructor( } } -class PipelineSource(private val firestore: FirebaseFirestore) { +class PipelineSource internal constructor(private val firestore: FirebaseFirestore) { fun collection(path: String): Pipeline { - return Pipeline(firestore, CollectionSource(path)) + // Validate path by converting to CollectionReference + return collection(firestore.collection(path)) + } + + fun collection(ref: CollectionReference): Pipeline { + if (ref.firestore.databaseId != firestore.databaseId) { + throw IllegalArgumentException( + "Provided collection reference is from a different Firestore instance." + ) + } + return Pipeline(firestore, CollectionSource(ref.path)) } fun collectionGroup(collectionId: String): Pipeline { + Preconditions.checkNotNull(collectionId, "Provided collection ID must not be null.") + require(!collectionId.contains("/")) { + "Invalid collectionId '$collectionId'. Collection IDs must not contain '/'." + } return Pipeline(firestore, CollectionGroupSource(collectionId)) } @@ -97,23 +179,49 @@ class PipelineSource(private val firestore: FirebaseFirestore) { return Pipeline(firestore, DatabaseSource()) } + fun documents(vararg documents: String): Pipeline { + // Validate document path by converting to DocumentReference + return documents(*documents.map(firestore::document).toTypedArray()) + } + fun documents(vararg documents: DocumentReference): Pipeline { - return Pipeline(firestore, DocumentsSource(documents)) + val databaseId = firestore.databaseId + for (document in documents) { + if (document.firestore.databaseId != databaseId) { + throw IllegalArgumentException( + "Provided document reference is from a different Firestore instance." + ) + } + } + return Pipeline( + firestore, + DocumentsSource(documents.map { docRef -> "/" + docRef.path }.toTypedArray()) + ) } } class PipelineSnapshot -internal constructor( - private val executionTime: SnapshotVersion, - private val results: List -) +internal constructor(private val executionTime: SnapshotVersion, val results: List) class PipelineResult internal constructor( - private val key: DocumentReference?, + private val firestore: FirebaseFirestore, + val ref: DocumentReference?, private val fields: Map, private val version: SnapshotVersion, -) +) { + + fun getData(): Map { + return userDataWriter().convertObject(fields) + } + + private fun userDataWriter(): UserDataWriter = + UserDataWriter(firestore, DocumentSnapshot.ServerTimestampBehavior.DEFAULT) + + override fun toString(): String { + return "PipelineResult{ref=$ref, version=$version}, data=${getData()}" + } +} internal interface PipelineResultObserver { fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java index 297479d0262..8079a30cf57 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java @@ -19,7 +19,6 @@ import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; -import com.google.firebase.Timestamp; import com.google.firebase.firestore.FieldValue.ArrayRemoveFieldValue; import com.google.firebase.firestore.FieldValue.ArrayUnionFieldValue; import com.google.firebase.firestore.FieldValue.DeleteFieldValue; @@ -44,9 +43,7 @@ import com.google.firestore.v1.MapValue; import com.google.firestore.v1.Value; import com.google.protobuf.NullValue; -import com.google.type.LatLng; import java.util.ArrayList; -import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -387,92 +384,18 @@ private void parseSentinelFieldValue( * @return The parsed value, or {@code null} if the value was a FieldValue sentinel that should * not be included in the resulting parsed data. */ - private Value parseScalarValue(Object input, ParseContext context) { - if (input == null) { - return Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(); - } else if (input instanceof Integer) { - return Value.newBuilder().setIntegerValue((Integer) input).build(); - } else if (input instanceof Long) { - return Value.newBuilder().setIntegerValue((Long) input).build(); - } else if (input instanceof Float) { - return Value.newBuilder().setDoubleValue(((Float) input).doubleValue()).build(); - } else if (input instanceof Double) { - return Value.newBuilder().setDoubleValue((Double) input).build(); - } else if (input instanceof Boolean) { - return Value.newBuilder().setBooleanValue((Boolean) input).build(); - } else if (input instanceof String) { - return Value.newBuilder().setStringValue((String) input).build(); - } else if (input instanceof Date) { - Timestamp timestamp = new Timestamp((Date) input); - return parseTimestamp(timestamp); - } else if (input instanceof Timestamp) { - Timestamp timestamp = (Timestamp) input; - return parseTimestamp(timestamp); - } else if (input instanceof GeoPoint) { - GeoPoint geoPoint = (GeoPoint) input; - return Value.newBuilder() - .setGeoPointValue( - LatLng.newBuilder() - .setLatitude(geoPoint.getLatitude()) - .setLongitude(geoPoint.getLongitude())) - .build(); - } else if (input instanceof Blob) { - return Value.newBuilder().setBytesValue(((Blob) input).toByteString()).build(); - } else if (input instanceof DocumentReference) { - DocumentReference ref = (DocumentReference) input; - // TODO: Rework once pre-converter is ported to Android. - if (ref.getFirestore() != null) { - DatabaseId otherDb = ref.getFirestore().getDatabaseId(); - if (!otherDb.equals(databaseId)) { - throw context.createError( - String.format( - "Document reference is for database %s/%s but should be for database %s/%s", - otherDb.getProjectId(), - otherDb.getDatabaseId(), - databaseId.getProjectId(), - databaseId.getDatabaseId())); - } - } - return Value.newBuilder() - .setReferenceValue( - String.format( - "projects/%s/databases/%s/documents/%s", - databaseId.getProjectId(), - databaseId.getDatabaseId(), - ((DocumentReference) input).getPath())) - .build(); - } else if (input instanceof VectorValue) { - return parseVectorValue(((VectorValue) input), context); - } else if (input.getClass().isArray()) { + public Value parseScalarValue(Object input, ParseContext context) { + if (input.getClass().isArray()) { throw context.createError("Arrays are not supported; use a List instead"); } else { - throw context.createError("Unsupported type: " + Util.typeName(input)); + try { + return Values.encodeAnyValue(input); + } catch (IllegalArgumentException e) { + throw context.createError("Unsupported type: " + Util.typeName(input)); + } } } - private Value parseVectorValue(VectorValue vector, ParseContext context) { - MapValue.Builder mapBuilder = MapValue.newBuilder(); - - mapBuilder.putFields(Values.TYPE_KEY, Values.VECTOR_VALUE_TYPE); - mapBuilder.putFields(Values.VECTOR_MAP_VECTORS_KEY, parseData(vector.toList(), context)); - - return Value.newBuilder().setMapValue(mapBuilder).build(); - } - - private Value parseTimestamp(Timestamp timestamp) { - // Firestore backend truncates precision down to microseconds. To ensure offline mode works - // the same with regards to truncation, perform the truncation immediately without waiting for - // the backend to do that. - int truncatedNanoseconds = timestamp.getNanoseconds() / 1000 * 1000; - - return Value.newBuilder() - .setTimestampValue( - com.google.protobuf.Timestamp.newBuilder() - .setSeconds(timestamp.getSeconds()) - .setNanos(truncatedNanoseconds)) - .build(); - } - private List parseArrayTransformElements(List elements) { ParseAccumulator accumulator = new ParseAccumulator(UserData.Source.Argument); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/VectorValue.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/VectorValue.java index 2f355648376..efcefd45bf4 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/VectorValue.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/VectorValue.java @@ -16,9 +16,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; /** * Represent a vector type in Firestore documents. @@ -41,21 +39,6 @@ public double[] toArray() { return this.values.clone(); } - /** - * Package private. - * Returns a representation of the vector as a List. - * - * @return A representation of the vector as an List - */ - @NonNull - List toList() { - ArrayList result = new ArrayList(this.values.length); - for (int i = 0; i < this.values.length; i++) { - result.add(i, this.values[i]); - } - return result; - } - /** * Returns true if this VectorValue is equal to the provided object. * diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/ResourcePath.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/ResourcePath.java index c96fcbdc3ee..776953d55d2 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/ResourcePath.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/ResourcePath.java @@ -14,6 +14,7 @@ package com.google.firebase.firestore.model; +import androidx.annotation.NonNull; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -36,7 +37,7 @@ public static ResourcePath fromSegments(List segments) { return segments.isEmpty() ? ResourcePath.EMPTY : new ResourcePath(segments); } - public static ResourcePath fromString(String path) { + public static ResourcePath fromString(@NonNull String path) { // NOTE: The client is ignorant of any path segments containing escape // sequences (for example, __id123__) and just passes them through raw (they exist // for legacy reasons and should not be used frequently). @@ -65,13 +66,6 @@ public String canonicalString() { // NOTE: The client is ignorant of any path segments containing escape // sequences (for example, __id123__) and just passes them through raw (they exist // for legacy reasons and should not be used frequently). - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < segments.size(); i++) { - if (i > 0) { - builder.append("/"); - } - builder.append(segments.get(i)); - } - return builder.toString(); + return String.join("/", segments); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt index 834fb2454a3..6504208f082 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt @@ -11,605 +11,683 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - -package com.google.firebase.firestore.model; - -import static com.google.firebase.firestore.model.ServerTimestamps.getLocalWriteTime; -import static com.google.firebase.firestore.model.ServerTimestamps.isServerTimestamp; -import static com.google.firebase.firestore.util.Assert.fail; -import static com.google.firebase.firestore.util.Assert.hardAssert; - -import androidx.annotation.Nullable; -import com.google.firebase.firestore.util.Util; -import com.google.firestore.v1.ArrayValue; -import com.google.firestore.v1.ArrayValueOrBuilder; -import com.google.firestore.v1.MapValue; -import com.google.firestore.v1.Value; -import com.google.protobuf.ByteString; -import com.google.protobuf.NullValue; -import com.google.protobuf.Timestamp; -import com.google.type.LatLng; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -public class Values { - public static final String TYPE_KEY = "__type__"; - public static final Value NAN_VALUE = Value.newBuilder().setDoubleValue(Double.NaN).build(); - public static final Value NULL_VALUE = - Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(); - public static final Value MIN_VALUE = NULL_VALUE; - public static final Value MAX_VALUE_TYPE = Value.newBuilder().setStringValue("__max__").build(); - public static final Value MAX_VALUE = - Value.newBuilder() - .setMapValue(MapValue.newBuilder().putFields(TYPE_KEY, MAX_VALUE_TYPE)) - .build(); - - public static final Value VECTOR_VALUE_TYPE = - Value.newBuilder().setStringValue("__vector__").build(); - public static final String VECTOR_MAP_VECTORS_KEY = "value"; - private static final Value MIN_VECTOR_VALUE = - Value.newBuilder() - .setMapValue( - MapValue.newBuilder() - .putFields(TYPE_KEY, VECTOR_VALUE_TYPE) - .putFields( - VECTOR_MAP_VECTORS_KEY, - Value.newBuilder().setArrayValue(ArrayValue.newBuilder()).build())) - .build(); +package com.google.firebase.firestore.model + +import com.google.firebase.firestore.Blob +import com.google.firebase.firestore.DocumentReference +import com.google.firebase.firestore.GeoPoint +import com.google.firebase.firestore.VectorValue +import com.google.firebase.firestore.util.Assert +import com.google.firebase.firestore.util.Util +import com.google.firestore.v1.ArrayValue +import com.google.firestore.v1.ArrayValueOrBuilder +import com.google.firestore.v1.MapValue +import com.google.firestore.v1.Value +import com.google.firestore.v1.Value.ValueTypeCase +import com.google.protobuf.ByteString +import com.google.protobuf.NullValue +import com.google.protobuf.Timestamp +import com.google.type.LatLng +import java.lang.Double.doubleToLongBits +import java.util.Date +import java.util.TreeMap +import kotlin.math.min + +internal object Values { + const val TYPE_KEY: String = "__type__" + @JvmField val NAN_VALUE: Value = Value.newBuilder().setDoubleValue(Double.NaN).build() + @JvmField val NULL_VALUE: Value = Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build() + @JvmField val MIN_VALUE: Value = NULL_VALUE + @JvmField val MAX_VALUE_TYPE: Value = Value.newBuilder().setStringValue("__max__").build() + @JvmField + val MAX_VALUE: Value = + Value.newBuilder() + .setMapValue(MapValue.newBuilder().putFields(TYPE_KEY, MAX_VALUE_TYPE)) + .build() + + @JvmField val VECTOR_VALUE_TYPE: Value = Value.newBuilder().setStringValue("__vector__").build() + const val VECTOR_MAP_VECTORS_KEY: String = "value" + private val MIN_VECTOR_VALUE: Value = + Value.newBuilder() + .setMapValue( + MapValue.newBuilder() + .putFields(TYPE_KEY, VECTOR_VALUE_TYPE) + .putFields( + VECTOR_MAP_VECTORS_KEY, + Value.newBuilder().setArrayValue(ArrayValue.newBuilder()).build() + ) + ) + .build() /** * The order of types in Firestore. This order is based on the backend's ordering, but modified to - * support server timestamps and {@link #MAX_VALUE}. + * support server timestamps and [.MAX_VALUE]. */ - public static final int TYPE_ORDER_NULL = 0; - - public static final int TYPE_ORDER_BOOLEAN = 1; - public static final int TYPE_ORDER_NUMBER = 2; - public static final int TYPE_ORDER_TIMESTAMP = 3; - public static final int TYPE_ORDER_SERVER_TIMESTAMP = 4; - public static final int TYPE_ORDER_STRING = 5; - public static final int TYPE_ORDER_BLOB = 6; - public static final int TYPE_ORDER_REFERENCE = 7; - public static final int TYPE_ORDER_GEOPOINT = 8; - public static final int TYPE_ORDER_ARRAY = 9; - public static final int TYPE_ORDER_VECTOR = 10; - public static final int TYPE_ORDER_MAP = 11; - - public static final int TYPE_ORDER_MAX_VALUE = Integer.MAX_VALUE; + const val TYPE_ORDER_NULL: Int = 0 + + const val TYPE_ORDER_BOOLEAN: Int = 1 + const val TYPE_ORDER_NUMBER: Int = 2 + const val TYPE_ORDER_TIMESTAMP: Int = 3 + const val TYPE_ORDER_SERVER_TIMESTAMP: Int = 4 + const val TYPE_ORDER_STRING: Int = 5 + const val TYPE_ORDER_BLOB: Int = 6 + const val TYPE_ORDER_REFERENCE: Int = 7 + const val TYPE_ORDER_GEOPOINT: Int = 8 + const val TYPE_ORDER_ARRAY: Int = 9 + const val TYPE_ORDER_VECTOR: Int = 10 + const val TYPE_ORDER_MAP: Int = 11 + + const val TYPE_ORDER_MAX_VALUE: Int = Int.MAX_VALUE /** Returns the backend's type order of the given Value type. */ - public static int typeOrder(Value value) { - switch (value.getValueTypeCase()) { - case NULL_VALUE: - return TYPE_ORDER_NULL; - case BOOLEAN_VALUE: - return TYPE_ORDER_BOOLEAN; - case INTEGER_VALUE: - return TYPE_ORDER_NUMBER; - case DOUBLE_VALUE: - return TYPE_ORDER_NUMBER; - case TIMESTAMP_VALUE: - return TYPE_ORDER_TIMESTAMP; - case STRING_VALUE: - return TYPE_ORDER_STRING; - case BYTES_VALUE: - return TYPE_ORDER_BLOB; - case REFERENCE_VALUE: - return TYPE_ORDER_REFERENCE; - case GEO_POINT_VALUE: - return TYPE_ORDER_GEOPOINT; - case ARRAY_VALUE: - return TYPE_ORDER_ARRAY; - case MAP_VALUE: - if (isServerTimestamp(value)) { - return TYPE_ORDER_SERVER_TIMESTAMP; + @JvmStatic + fun typeOrder(value: Value): Int { + return when (value.valueTypeCase) { + ValueTypeCase.NULL_VALUE -> TYPE_ORDER_NULL + ValueTypeCase.BOOLEAN_VALUE -> TYPE_ORDER_BOOLEAN + ValueTypeCase.INTEGER_VALUE -> TYPE_ORDER_NUMBER + ValueTypeCase.DOUBLE_VALUE -> TYPE_ORDER_NUMBER + ValueTypeCase.TIMESTAMP_VALUE -> TYPE_ORDER_TIMESTAMP + ValueTypeCase.STRING_VALUE -> TYPE_ORDER_STRING + ValueTypeCase.BYTES_VALUE -> TYPE_ORDER_BLOB + ValueTypeCase.REFERENCE_VALUE -> TYPE_ORDER_REFERENCE + ValueTypeCase.GEO_POINT_VALUE -> TYPE_ORDER_GEOPOINT + ValueTypeCase.ARRAY_VALUE -> TYPE_ORDER_ARRAY + ValueTypeCase.MAP_VALUE -> + if (ServerTimestamps.isServerTimestamp(value)) { + TYPE_ORDER_SERVER_TIMESTAMP } else if (isMaxValue(value)) { - return TYPE_ORDER_MAX_VALUE; + TYPE_ORDER_MAX_VALUE } else if (isVectorValue(value)) { - return TYPE_ORDER_VECTOR; + TYPE_ORDER_VECTOR } else { - return TYPE_ORDER_MAP; + TYPE_ORDER_MAP } - default: - throw fail("Invalid value type: " + value.getValueTypeCase()); + else -> throw Assert.fail("Invalid value type: " + value.valueTypeCase) } } - public static boolean equals(Value left, Value right) { - if (left == right) { - return true; + @JvmStatic + fun equals(left: Value?, right: Value?): Boolean { + if (left === right) { + return true } if (left == null || right == null) { - return false; + return false } - int leftType = typeOrder(left); - int rightType = typeOrder(right); + val leftType = typeOrder(left) + val rightType = typeOrder(right) if (leftType != rightType) { - return false; + return false } - switch (leftType) { - case TYPE_ORDER_NUMBER: - return numberEquals(left, right); - case TYPE_ORDER_ARRAY: - return arrayEquals(left, right); - case TYPE_ORDER_VECTOR: - case TYPE_ORDER_MAP: - return objectEquals(left, right); - case TYPE_ORDER_SERVER_TIMESTAMP: - return getLocalWriteTime(left).equals(getLocalWriteTime(right)); - case TYPE_ORDER_MAX_VALUE: - return true; - default: - return left.equals(right); + return when (leftType) { + TYPE_ORDER_NUMBER -> numberEquals(left, right) + TYPE_ORDER_ARRAY -> arrayEquals(left, right) + TYPE_ORDER_VECTOR, + TYPE_ORDER_MAP -> objectEquals(left, right) + TYPE_ORDER_SERVER_TIMESTAMP -> + ServerTimestamps.getLocalWriteTime(left) == ServerTimestamps.getLocalWriteTime(right) + TYPE_ORDER_MAX_VALUE -> true + else -> left == right } } - private static boolean numberEquals(Value left, Value right) { - if (left.getValueTypeCase() == Value.ValueTypeCase.INTEGER_VALUE - && right.getValueTypeCase() == Value.ValueTypeCase.INTEGER_VALUE) { - return left.getIntegerValue() == right.getIntegerValue(); - } else if (left.getValueTypeCase() == Value.ValueTypeCase.DOUBLE_VALUE - && right.getValueTypeCase() == Value.ValueTypeCase.DOUBLE_VALUE) { - return Double.doubleToLongBits(left.getDoubleValue()) - == Double.doubleToLongBits(right.getDoubleValue()); + private fun numberEquals(left: Value, right: Value): Boolean { + if (left.valueTypeCase != right.valueTypeCase) { + return false + } + return when (left.valueTypeCase) { + ValueTypeCase.INTEGER_VALUE -> left.integerValue == right.integerValue + ValueTypeCase.DOUBLE_VALUE -> + doubleToLongBits(left.doubleValue) == doubleToLongBits(right.doubleValue) + else -> false } - - return false; } - private static boolean arrayEquals(Value left, Value right) { - ArrayValue leftArray = left.getArrayValue(); - ArrayValue rightArray = right.getArrayValue(); + private fun arrayEquals(left: Value, right: Value): Boolean { + val leftArray = left.arrayValue + val rightArray = right.arrayValue - if (leftArray.getValuesCount() != rightArray.getValuesCount()) { - return false; + if (leftArray.valuesCount != rightArray.valuesCount) { + return false } - for (int i = 0; i < leftArray.getValuesCount(); ++i) { + for (i in 0 until leftArray.valuesCount) { if (!equals(leftArray.getValues(i), rightArray.getValues(i))) { - return false; + return false } } - return true; + return true } - private static boolean objectEquals(Value left, Value right) { - MapValue leftMap = left.getMapValue(); - MapValue rightMap = right.getMapValue(); + private fun objectEquals(left: Value, right: Value): Boolean { + val leftMap = left.mapValue + val rightMap = right.mapValue - if (leftMap.getFieldsCount() != rightMap.getFieldsCount()) { - return false; + if (leftMap.fieldsCount != rightMap.fieldsCount) { + return false } - for (Map.Entry entry : leftMap.getFieldsMap().entrySet()) { - Value otherEntry = rightMap.getFieldsMap().get(entry.getKey()); - if (!equals(entry.getValue(), otherEntry)) { - return false; + for ((key, value) in leftMap.fieldsMap) { + val otherEntry = rightMap.fieldsMap[key] + if (!equals(value, otherEntry)) { + return false } } - return true; + return true } /** Returns true if the Value list contains the specified element. */ - public static boolean contains(ArrayValueOrBuilder haystack, Value needle) { - for (Value haystackElement : haystack.getValuesList()) { + @JvmStatic + fun contains(haystack: ArrayValueOrBuilder, needle: Value?): Boolean { + for (haystackElement in haystack.valuesList) { if (equals(haystackElement, needle)) { - return true; + return true } } - return false; + return false } - public static int compare(Value left, Value right) { - int leftType = typeOrder(left); - int rightType = typeOrder(right); + @JvmStatic + fun compare(left: Value, right: Value): Int { + val leftType = typeOrder(left) + val rightType = typeOrder(right) if (leftType != rightType) { - return Util.compareIntegers(leftType, rightType); - } - - switch (leftType) { - case TYPE_ORDER_NULL: - case TYPE_ORDER_MAX_VALUE: - return 0; - case TYPE_ORDER_BOOLEAN: - return Util.compareBooleans(left.getBooleanValue(), right.getBooleanValue()); - case TYPE_ORDER_NUMBER: - return compareNumbers(left, right); - case TYPE_ORDER_TIMESTAMP: - return compareTimestamps(left.getTimestampValue(), right.getTimestampValue()); - case TYPE_ORDER_SERVER_TIMESTAMP: - return compareTimestamps(getLocalWriteTime(left), getLocalWriteTime(right)); - case TYPE_ORDER_STRING: - return Util.compareUtf8Strings(left.getStringValue(), right.getStringValue()); - case TYPE_ORDER_BLOB: - return Util.compareByteStrings(left.getBytesValue(), right.getBytesValue()); - case TYPE_ORDER_REFERENCE: - return compareReferences(left.getReferenceValue(), right.getReferenceValue()); - case TYPE_ORDER_GEOPOINT: - return compareGeoPoints(left.getGeoPointValue(), right.getGeoPointValue()); - case TYPE_ORDER_ARRAY: - return compareArrays(left.getArrayValue(), right.getArrayValue()); - case TYPE_ORDER_MAP: - return compareMaps(left.getMapValue(), right.getMapValue()); - case TYPE_ORDER_VECTOR: - return compareVectors(left.getMapValue(), right.getMapValue()); - default: - throw fail("Invalid value type: " + leftType); - } - } - - public static int lowerBoundCompare( - Value left, boolean leftInclusive, Value right, boolean rightInclusive) { - int cmp = compare(left, right); + return Util.compareIntegers(leftType, rightType) + } + + return when (leftType) { + TYPE_ORDER_NULL, + TYPE_ORDER_MAX_VALUE -> 0 + TYPE_ORDER_BOOLEAN -> Util.compareBooleans(left.booleanValue, right.booleanValue) + TYPE_ORDER_NUMBER -> compareNumbers(left, right) + TYPE_ORDER_TIMESTAMP -> compareTimestamps(left.timestampValue, right.timestampValue) + TYPE_ORDER_SERVER_TIMESTAMP -> + compareTimestamps( + ServerTimestamps.getLocalWriteTime(left), + ServerTimestamps.getLocalWriteTime(right) + ) + TYPE_ORDER_STRING -> Util.compareUtf8Strings(left.stringValue, right.stringValue) + TYPE_ORDER_BLOB -> Util.compareByteStrings(left.bytesValue, right.bytesValue) + TYPE_ORDER_REFERENCE -> compareReferences(left.referenceValue, right.referenceValue) + TYPE_ORDER_GEOPOINT -> compareGeoPoints(left.geoPointValue, right.geoPointValue) + TYPE_ORDER_ARRAY -> compareArrays(left.arrayValue, right.arrayValue) + TYPE_ORDER_MAP -> compareMaps(left.mapValue, right.mapValue) + TYPE_ORDER_VECTOR -> compareVectors(left.mapValue, right.mapValue) + else -> throw Assert.fail("Invalid value type: $leftType") + } + } + + @JvmStatic + fun lowerBoundCompare( + left: Value, + leftInclusive: Boolean, + right: Value, + rightInclusive: Boolean + ): Int { + val cmp = compare(left, right) if (cmp != 0) { - return cmp; + return cmp } if (leftInclusive && !rightInclusive) { - return -1; + return -1 } else if (!leftInclusive && rightInclusive) { - return 1; + return 1 } - return 0; + return 0 } - public static int upperBoundCompare( - Value left, boolean leftInclusive, Value right, boolean rightInclusive) { - int cmp = compare(left, right); + @JvmStatic + fun upperBoundCompare( + left: Value, + leftInclusive: Boolean, + right: Value, + rightInclusive: Boolean + ): Int { + val cmp = compare(left, right) if (cmp != 0) { - return cmp; + return cmp } if (leftInclusive && !rightInclusive) { - return 1; + return 1 } else if (!leftInclusive && rightInclusive) { - return -1; + return -1 } - return 0; + return 0 } - private static int compareNumbers(Value left, Value right) { - if (left.getValueTypeCase() == Value.ValueTypeCase.DOUBLE_VALUE) { - double leftDouble = left.getDoubleValue(); - if (right.getValueTypeCase() == Value.ValueTypeCase.DOUBLE_VALUE) { - return Util.compareDoubles(leftDouble, right.getDoubleValue()); - } else if (right.getValueTypeCase() == Value.ValueTypeCase.INTEGER_VALUE) { - return Util.compareMixed(leftDouble, right.getIntegerValue()); + private fun compareNumbers(left: Value, right: Value): Int { + if (left.valueTypeCase == ValueTypeCase.DOUBLE_VALUE) { + if (right.valueTypeCase == ValueTypeCase.DOUBLE_VALUE) { + return Util.compareDoubles(left.doubleValue, right.doubleValue) + } else if (right.valueTypeCase == ValueTypeCase.INTEGER_VALUE) { + return Util.compareMixed(left.doubleValue, right.integerValue) } - } else if (left.getValueTypeCase() == Value.ValueTypeCase.INTEGER_VALUE) { - long leftLong = left.getIntegerValue(); - if (right.getValueTypeCase() == Value.ValueTypeCase.INTEGER_VALUE) { - return Util.compareLongs(leftLong, right.getIntegerValue()); - } else if (right.getValueTypeCase() == Value.ValueTypeCase.DOUBLE_VALUE) { - return -1 * Util.compareMixed(right.getDoubleValue(), leftLong); + } else if (left.valueTypeCase == ValueTypeCase.INTEGER_VALUE) { + if (right.valueTypeCase == ValueTypeCase.INTEGER_VALUE) { + return Util.compareLongs(left.integerValue, right.integerValue) + } else if (right.valueTypeCase == ValueTypeCase.DOUBLE_VALUE) { + return -1 * Util.compareMixed(right.doubleValue, left.integerValue) } } - throw fail("Unexpected values: %s vs %s", left, right); + throw Assert.fail("Unexpected values: %s vs %s", left, right) } - private static int compareTimestamps(Timestamp left, Timestamp right) { - int cmp = Util.compareLongs(left.getSeconds(), right.getSeconds()); + private fun compareTimestamps(left: Timestamp, right: Timestamp): Int { + val cmp = Util.compareLongs(left.seconds, right.seconds) if (cmp != 0) { - return cmp; + return cmp } - return Util.compareIntegers(left.getNanos(), right.getNanos()); + return Util.compareIntegers(left.nanos, right.nanos) } - private static int compareReferences(String leftPath, String rightPath) { - String[] leftSegments = leftPath.split("/", -1); - String[] rightSegments = rightPath.split("/", -1); + private fun compareReferences(leftPath: String, rightPath: String): Int { + val leftSegments = leftPath.split("/".toRegex()).toTypedArray() + val rightSegments = rightPath.split("/".toRegex()).toTypedArray() - int minLength = Math.min(leftSegments.length, rightSegments.length); - for (int i = 0; i < minLength; i++) { - int cmp = leftSegments[i].compareTo(rightSegments[i]); + val minLength = min(leftSegments.size.toDouble(), rightSegments.size.toDouble()).toInt() + for (i in 0 until minLength) { + val cmp = leftSegments[i].compareTo(rightSegments[i]) if (cmp != 0) { - return cmp; + return cmp } } - return Util.compareIntegers(leftSegments.length, rightSegments.length); + return Util.compareIntegers(leftSegments.size, rightSegments.size) } - private static int compareGeoPoints(LatLng left, LatLng right) { - int comparison = Util.compareDoubles(left.getLatitude(), right.getLatitude()); + private fun compareGeoPoints(left: LatLng, right: LatLng): Int { + val comparison = Util.compareDoubles(left.latitude, right.latitude) if (comparison == 0) { - return Util.compareDoubles(left.getLongitude(), right.getLongitude()); + return Util.compareDoubles(left.longitude, right.longitude) } - return comparison; + return comparison } - private static int compareArrays(ArrayValue left, ArrayValue right) { - int minLength = Math.min(left.getValuesCount(), right.getValuesCount()); - for (int i = 0; i < minLength; i++) { - int cmp = compare(left.getValues(i), right.getValues(i)); + private fun compareArrays(left: ArrayValue, right: ArrayValue): Int { + val minLength = min(left.valuesCount.toDouble(), right.valuesCount.toDouble()).toInt() + for (i in 0 until minLength) { + val cmp = compare(left.getValues(i), right.getValues(i)) if (cmp != 0) { - return cmp; + return cmp } } - return Util.compareIntegers(left.getValuesCount(), right.getValuesCount()); + return Util.compareIntegers(left.valuesCount, right.valuesCount) } - private static int compareMaps(MapValue left, MapValue right) { - Iterator> iterator1 = - new TreeMap<>(left.getFieldsMap()).entrySet().iterator(); - Iterator> iterator2 = - new TreeMap<>(right.getFieldsMap()).entrySet().iterator(); + private fun compareMaps(left: MapValue, right: MapValue): Int { + val iterator1: Iterator> = TreeMap(left.fieldsMap).entries.iterator() + val iterator2: Iterator> = TreeMap(right.fieldsMap).entries.iterator() while (iterator1.hasNext() && iterator2.hasNext()) { - Map.Entry entry1 = iterator1.next(); - Map.Entry entry2 = iterator2.next(); - int keyCompare = Util.compareUtf8Strings(entry1.getKey(), entry2.getKey()); + val entry1 = iterator1.next() + val entry2 = iterator2.next() + val keyCompare = Util.compareUtf8Strings(entry1.key, entry2.key) if (keyCompare != 0) { - return keyCompare; + return keyCompare } - int valueCompare = compare(entry1.getValue(), entry2.getValue()); + val valueCompare = compare(entry1.value, entry2.value) if (valueCompare != 0) { - return valueCompare; + return valueCompare } } // Only equal if both iterators are exhausted. - return Util.compareBooleans(iterator1.hasNext(), iterator2.hasNext()); + return Util.compareBooleans(iterator1.hasNext(), iterator2.hasNext()) } - private static int compareVectors(MapValue left, MapValue right) { - Map leftMap = left.getFieldsMap(); - Map rightMap = right.getFieldsMap(); + private fun compareVectors(left: MapValue, right: MapValue): Int { + val leftMap = left.fieldsMap + val rightMap = right.fieldsMap // The vector is a map, but only vector value is compared. - ArrayValue leftArrayValue = leftMap.get(Values.VECTOR_MAP_VECTORS_KEY).getArrayValue(); - ArrayValue rightArrayValue = rightMap.get(Values.VECTOR_MAP_VECTORS_KEY).getArrayValue(); + val leftArrayValue = leftMap[VECTOR_MAP_VECTORS_KEY]!!.arrayValue + val rightArrayValue = rightMap[VECTOR_MAP_VECTORS_KEY]!!.arrayValue - int lengthCompare = - Util.compareIntegers(leftArrayValue.getValuesCount(), rightArrayValue.getValuesCount()); + val lengthCompare = + Util.compareIntegers(leftArrayValue.valuesCount, rightArrayValue.valuesCount) if (lengthCompare != 0) { - return lengthCompare; + return lengthCompare } - return compareArrays(leftArrayValue, rightArrayValue); + return compareArrays(leftArrayValue, rightArrayValue) } /** Generate the canonical ID for the provided field value (as used in Target serialization). */ - public static String canonicalId(Value value) { - StringBuilder builder = new StringBuilder(); - canonifyValue(builder, value); - return builder.toString(); - } - - private static void canonifyValue(StringBuilder builder, Value value) { - switch (value.getValueTypeCase()) { - case NULL_VALUE: - builder.append("null"); - break; - case BOOLEAN_VALUE: - builder.append(value.getBooleanValue()); - break; - case INTEGER_VALUE: - builder.append(value.getIntegerValue()); - break; - case DOUBLE_VALUE: - builder.append(value.getDoubleValue()); - break; - case TIMESTAMP_VALUE: - canonifyTimestamp(builder, value.getTimestampValue()); - break; - case STRING_VALUE: - builder.append(value.getStringValue()); - break; - case BYTES_VALUE: - builder.append(Util.toDebugString(value.getBytesValue())); - break; - case REFERENCE_VALUE: - canonifyReference(builder, value); - break; - case GEO_POINT_VALUE: - canonifyGeoPoint(builder, value.getGeoPointValue()); - break; - case ARRAY_VALUE: - canonifyArray(builder, value.getArrayValue()); - break; - case MAP_VALUE: - canonifyObject(builder, value.getMapValue()); - break; - default: - throw fail("Invalid value type: " + value.getValueTypeCase()); - } - } - - private static void canonifyTimestamp(StringBuilder builder, Timestamp timestamp) { - builder.append(String.format("time(%s,%s)", timestamp.getSeconds(), timestamp.getNanos())); - } - - private static void canonifyGeoPoint(StringBuilder builder, LatLng latLng) { - builder.append(String.format("geo(%s,%s)", latLng.getLatitude(), latLng.getLongitude())); - } - - private static void canonifyReference(StringBuilder builder, Value value) { - hardAssert(isReferenceValue(value), "Value should be a ReferenceValue"); - builder.append(DocumentKey.fromName(value.getReferenceValue())); - } - - private static void canonifyObject(StringBuilder builder, MapValue mapValue) { + @JvmStatic + fun canonicalId(value: Value): String { + val builder = StringBuilder() + canonifyValue(builder, value) + return builder.toString() + } + + private fun canonifyValue(builder: StringBuilder, value: Value) { + when (value.valueTypeCase) { + ValueTypeCase.NULL_VALUE -> builder.append("null") + ValueTypeCase.BOOLEAN_VALUE -> builder.append(value.booleanValue) + ValueTypeCase.INTEGER_VALUE -> builder.append(value.integerValue) + ValueTypeCase.DOUBLE_VALUE -> builder.append(value.doubleValue) + ValueTypeCase.TIMESTAMP_VALUE -> canonifyTimestamp(builder, value.timestampValue) + ValueTypeCase.STRING_VALUE -> builder.append(value.stringValue) + ValueTypeCase.BYTES_VALUE -> builder.append(Util.toDebugString(value.bytesValue)) + ValueTypeCase.REFERENCE_VALUE -> canonifyReference(builder, value) + ValueTypeCase.GEO_POINT_VALUE -> canonifyGeoPoint(builder, value.geoPointValue) + ValueTypeCase.ARRAY_VALUE -> canonifyArray(builder, value.arrayValue) + ValueTypeCase.MAP_VALUE -> canonifyObject(builder, value.mapValue) + else -> throw Assert.fail("Invalid value type: " + value.valueTypeCase) + } + } + + private fun canonifyTimestamp(builder: StringBuilder, timestamp: Timestamp) { + builder.append(String.format("time(%s,%s)", timestamp.seconds, timestamp.nanos)) + } + + private fun canonifyGeoPoint(builder: StringBuilder, latLng: LatLng) { + builder.append(String.format("geo(%s,%s)", latLng.latitude, latLng.longitude)) + } + + private fun canonifyReference(builder: StringBuilder, value: Value) { + Assert.hardAssert(isReferenceValue(value), "Value should be a ReferenceValue") + builder.append(DocumentKey.fromName(value.referenceValue)) + } + + private fun canonifyObject(builder: StringBuilder, mapValue: MapValue) { // Even though MapValue are likely sorted correctly based on their insertion order (for example, // when received from the backend), local modifications can bring elements out of order. We need // to re-sort the elements to ensure that canonical IDs are independent of insertion order. - List keys = new ArrayList<>(mapValue.getFieldsMap().keySet()); - Collections.sort(keys); - - builder.append("{"); - boolean first = true; - for (String key : keys) { - if (!first) { - builder.append(","); - } else { - first = false; + val keys = ArrayList(mapValue.fieldsMap.keys) + keys.sort() + + builder.append("{") + val iterator = keys.iterator() + while (iterator.hasNext()) { + val key = iterator.next() + builder.append(key).append(":") + canonifyValue(builder, mapValue.getFieldsOrThrow(key)) + if (iterator.hasNext()) { + builder.append(",") } - builder.append(key).append(":"); - canonifyValue(builder, mapValue.getFieldsOrThrow(key)); } - builder.append("}"); + builder.append("}") } - private static void canonifyArray(StringBuilder builder, ArrayValue arrayValue) { - builder.append("["); - for (int i = 0; i < arrayValue.getValuesCount(); ++i) { - canonifyValue(builder, arrayValue.getValues(i)); - if (i != arrayValue.getValuesCount() - 1) { - builder.append(","); + private fun canonifyArray(builder: StringBuilder, arrayValue: ArrayValue) { + builder.append("[") + if (arrayValue.valuesCount > 0) { + canonifyValue(builder, arrayValue.getValues(0)) + for (i in 1 until arrayValue.valuesCount) { + builder.append(",") + canonifyValue(builder, arrayValue.getValues(i)) } } - builder.append("]"); + builder.append("]") } /** Returns true if `value` is a INTEGER_VALUE. */ - public static boolean isInteger(@Nullable Value value) { - return value != null && value.getValueTypeCase() == Value.ValueTypeCase.INTEGER_VALUE; + @JvmStatic + fun isInteger(value: Value?): Boolean { + return value != null && value.valueTypeCase == ValueTypeCase.INTEGER_VALUE } /** Returns true if `value` is a DOUBLE_VALUE. */ - public static boolean isDouble(@Nullable Value value) { - return value != null && value.getValueTypeCase() == Value.ValueTypeCase.DOUBLE_VALUE; + @JvmStatic + fun isDouble(value: Value?): Boolean { + return value != null && value.valueTypeCase == ValueTypeCase.DOUBLE_VALUE } /** Returns true if `value` is either a INTEGER_VALUE or a DOUBLE_VALUE. */ - public static boolean isNumber(@Nullable Value value) { - return isInteger(value) || isDouble(value); + @JvmStatic + fun isNumber(value: Value?): Boolean { + return isInteger(value) || isDouble(value) } /** Returns true if `value` is an ARRAY_VALUE. */ - public static boolean isArray(@Nullable Value value) { - return value != null && value.getValueTypeCase() == Value.ValueTypeCase.ARRAY_VALUE; - } - - public static boolean isReferenceValue(@Nullable Value value) { - return value != null && value.getValueTypeCase() == Value.ValueTypeCase.REFERENCE_VALUE; + @JvmStatic + fun isArray(value: Value?): Boolean { + return value != null && value.valueTypeCase == ValueTypeCase.ARRAY_VALUE } - public static boolean isNullValue(@Nullable Value value) { - return value != null && value.getValueTypeCase() == Value.ValueTypeCase.NULL_VALUE; + @JvmStatic + fun isReferenceValue(value: Value?): Boolean { + return value != null && value.valueTypeCase == ValueTypeCase.REFERENCE_VALUE } - public static boolean isNanValue(@Nullable Value value) { - return value != null && Double.isNaN(value.getDoubleValue()); + @JvmStatic + fun isNullValue(value: Value?): Boolean { + return value != null && value.valueTypeCase == ValueTypeCase.NULL_VALUE } - public static boolean isMapValue(@Nullable Value value) { - return value != null && value.getValueTypeCase() == Value.ValueTypeCase.MAP_VALUE; + @JvmStatic + fun isNanValue(value: Value?): Boolean { + return value != null && java.lang.Double.isNaN(value.doubleValue) } - public static Value refValue(DatabaseId databaseId, DocumentKey key) { - Value value = - Value.newBuilder() - .setReferenceValue( - String.format( - "projects/%s/databases/%s/documents/%s", - databaseId.getProjectId(), databaseId.getDatabaseId(), key.toString())) - .build(); - return value; + @JvmStatic + fun isMapValue(value: Value?): Boolean { + return value != null && value.valueTypeCase == ValueTypeCase.MAP_VALUE } - public static Value MIN_BOOLEAN = Value.newBuilder().setBooleanValue(false).build(); - public static Value MIN_NUMBER = Value.newBuilder().setDoubleValue(Double.NaN).build(); - public static Value MIN_TIMESTAMP = + @JvmStatic + fun refValue(databaseId: DatabaseId, key: DocumentKey): Value { + val value = Value.newBuilder() - .setTimestampValue(Timestamp.newBuilder().setSeconds(Long.MIN_VALUE)) - .build(); - public static Value MIN_STRING = Value.newBuilder().setStringValue("").build(); - public static Value MIN_BYTES = Value.newBuilder().setBytesValue(ByteString.EMPTY).build(); - public static Value MIN_REFERENCE = refValue(DatabaseId.EMPTY, DocumentKey.empty()); - public static Value MIN_GEO_POINT = - Value.newBuilder() - .setGeoPointValue(LatLng.newBuilder().setLatitude(-90.0).setLongitude(-180.0)) - .build(); - public static Value MIN_ARRAY = - Value.newBuilder().setArrayValue(ArrayValue.getDefaultInstance()).build(); - public static Value MIN_MAP = - Value.newBuilder().setMapValue(MapValue.getDefaultInstance()).build(); + .setReferenceValue( + String.format( + "projects/%s/databases/%s/documents/%s", + databaseId.projectId, + databaseId.databaseId, + key.toString() + ) + ) + .build() + return value + } + + private val MIN_BOOLEAN: Value = Value.newBuilder().setBooleanValue(false).build() + private val MIN_NUMBER: Value = Value.newBuilder().setDoubleValue(Double.NaN).build() + private val MIN_TIMESTAMP: Value = + Value.newBuilder().setTimestampValue(Timestamp.newBuilder().setSeconds(Long.MIN_VALUE)).build() + private val MIN_STRING: Value = Value.newBuilder().setStringValue("").build() + private val MIN_BYTES: Value = Value.newBuilder().setBytesValue(ByteString.EMPTY).build() + private val MIN_REFERENCE: Value = refValue(DatabaseId.EMPTY, DocumentKey.empty()) + private val MIN_GEO_POINT: Value = + Value.newBuilder() + .setGeoPointValue(LatLng.newBuilder().setLatitude(-90.0).setLongitude(-180.0)) + .build() + private val MIN_ARRAY: Value = + Value.newBuilder().setArrayValue(ArrayValue.getDefaultInstance()).build() + private val MIN_MAP: Value = Value.newBuilder().setMapValue(MapValue.getDefaultInstance()).build() /** Returns the lowest value for the given value type (inclusive). */ - public static Value getLowerBound(Value value) { - switch (value.getValueTypeCase()) { - case NULL_VALUE: - return Values.NULL_VALUE; - case BOOLEAN_VALUE: - return MIN_BOOLEAN; - case INTEGER_VALUE: - case DOUBLE_VALUE: - return MIN_NUMBER; - case TIMESTAMP_VALUE: - return MIN_TIMESTAMP; - case STRING_VALUE: - return MIN_STRING; - case BYTES_VALUE: - return MIN_BYTES; - case REFERENCE_VALUE: - return MIN_REFERENCE; - case GEO_POINT_VALUE: - return MIN_GEO_POINT; - case ARRAY_VALUE: - return MIN_ARRAY; - case MAP_VALUE: - // VectorValue sorts after ArrayValue and before an empty MapValue - if (isVectorValue(value)) { - return MIN_VECTOR_VALUE; - } - return MIN_MAP; - default: - throw new IllegalArgumentException("Unknown value type: " + value.getValueTypeCase()); + @JvmStatic + fun getLowerBound(value: Value): Value { + return when (value.valueTypeCase) { + ValueTypeCase.NULL_VALUE -> NULL_VALUE + ValueTypeCase.BOOLEAN_VALUE -> MIN_BOOLEAN + ValueTypeCase.INTEGER_VALUE, + ValueTypeCase.DOUBLE_VALUE -> MIN_NUMBER + ValueTypeCase.TIMESTAMP_VALUE -> MIN_TIMESTAMP + ValueTypeCase.STRING_VALUE -> MIN_STRING + ValueTypeCase.BYTES_VALUE -> MIN_BYTES + ValueTypeCase.REFERENCE_VALUE -> MIN_REFERENCE + ValueTypeCase.GEO_POINT_VALUE -> MIN_GEO_POINT + ValueTypeCase.ARRAY_VALUE -> MIN_ARRAY + // VectorValue sorts after ArrayValue and before an empty MapValue + ValueTypeCase.MAP_VALUE -> if (isVectorValue(value)) MIN_VECTOR_VALUE else MIN_MAP + else -> throw IllegalArgumentException("Unknown value type: " + value.valueTypeCase) } } /** Returns the largest value for the given value type (exclusive). */ - public static Value getUpperBound(Value value) { - switch (value.getValueTypeCase()) { - case NULL_VALUE: - return MIN_BOOLEAN; - case BOOLEAN_VALUE: - return MIN_NUMBER; - case INTEGER_VALUE: - case DOUBLE_VALUE: - return MIN_TIMESTAMP; - case TIMESTAMP_VALUE: - return MIN_STRING; - case STRING_VALUE: - return MIN_BYTES; - case BYTES_VALUE: - return MIN_REFERENCE; - case REFERENCE_VALUE: - return MIN_GEO_POINT; - case GEO_POINT_VALUE: - return MIN_ARRAY; - case ARRAY_VALUE: - return MIN_VECTOR_VALUE; - case MAP_VALUE: - // VectorValue sorts after ArrayValue and before an empty MapValue - if (isVectorValue(value)) { - return MIN_MAP; - } - return MAX_VALUE; - default: - throw new IllegalArgumentException("Unknown value type: " + value.getValueTypeCase()); + @JvmStatic + fun getUpperBound(value: Value): Value { + return when (value.valueTypeCase) { + ValueTypeCase.NULL_VALUE -> MIN_BOOLEAN + ValueTypeCase.BOOLEAN_VALUE -> MIN_NUMBER + ValueTypeCase.INTEGER_VALUE, + ValueTypeCase.DOUBLE_VALUE -> MIN_TIMESTAMP + ValueTypeCase.TIMESTAMP_VALUE -> MIN_STRING + ValueTypeCase.STRING_VALUE -> MIN_BYTES + ValueTypeCase.BYTES_VALUE -> MIN_REFERENCE + ValueTypeCase.REFERENCE_VALUE -> MIN_GEO_POINT + ValueTypeCase.GEO_POINT_VALUE -> MIN_ARRAY + ValueTypeCase.ARRAY_VALUE -> MIN_VECTOR_VALUE + // VectorValue sorts after ArrayValue and before an empty MapValue + ValueTypeCase.MAP_VALUE -> if (isVectorValue(value)) MIN_MAP else MAX_VALUE + else -> throw IllegalArgumentException("Unknown value type: " + value.valueTypeCase) } } - /** Returns true if the Value represents the canonical {@link #MAX_VALUE} . */ - public static boolean isMaxValue(Value value) { - return MAX_VALUE_TYPE.equals(value.getMapValue().getFieldsMap().get(TYPE_KEY)); + /** Returns true if the Value represents the canonical [.MAX_VALUE] . */ + @JvmStatic + fun isMaxValue(value: Value): Boolean { + return MAX_VALUE_TYPE == value.mapValue.fieldsMap[TYPE_KEY] } /** Returns true if the Value represents a VectorValue . */ - public static boolean isVectorValue(Value value) { - return VECTOR_VALUE_TYPE.equals(value.getMapValue().getFieldsMap().get(TYPE_KEY)); + @JvmStatic + fun isVectorValue(value: Value): Boolean { + return VECTOR_VALUE_TYPE == value.mapValue.fieldsMap[TYPE_KEY] + } + + @JvmStatic + fun encodeValue(value: Long): Value { + return Value.newBuilder().setIntegerValue(value).build() + } + + @JvmStatic + fun encodeValue(value: Int): Value { + return Value.newBuilder().setIntegerValue(value.toLong()).build() + } + + @JvmStatic + fun encodeValue(value: Double): Value { + return Value.newBuilder().setDoubleValue(value).build() + } + + @JvmStatic + fun encodeValue(value: Float): Value { + return Value.newBuilder().setDoubleValue(value.toDouble()).build() + } + + @JvmStatic + fun encodeValue(value: Number): Value { + return when (value) { + is Long -> encodeValue(value) + is Int -> encodeValue(value) + is Double -> encodeValue(value) + is Float -> encodeValue(value) + else -> throw IllegalArgumentException("Unexpected number type: $value") + } + } + + @JvmStatic + fun encodeValue(value: String): Value { + return Value.newBuilder().setStringValue(value).build() + } + + @JvmStatic + fun encodeValue(date: Date): Value { + return encodeValue(com.google.firebase.Timestamp((date))) + } + + @JvmStatic + fun encodeValue(timestamp: com.google.firebase.Timestamp): Value { + // Firestore backend truncates precision down to microseconds. To ensure offline mode works + // the same with regards to truncation, perform the truncation immediately without waiting for + // the backend to do that. + val truncatedNanoseconds: Int = timestamp.nanoseconds / 1000 * 1000 + + return Value.newBuilder() + .setTimestampValue( + com.google.protobuf.Timestamp.newBuilder() + .setSeconds(timestamp.seconds) + .setNanos(truncatedNanoseconds) + ) + .build() + } + + @JvmStatic + fun encodeValue(value: Boolean): Value { + return Value.newBuilder().setBooleanValue(value).build() + } + + @JvmStatic + fun encodeValue(geoPoint: GeoPoint): Value { + return Value.newBuilder() + .setGeoPointValue( + LatLng.newBuilder().setLatitude(geoPoint.latitude).setLongitude(geoPoint.longitude) + ) + .build() + } + + @JvmStatic + fun encodeValue(value: Blob): Value { + return Value.newBuilder().setBytesValue(value.toByteString()).build() + } + + @JvmStatic + fun encodeValue(docRef: DocumentReference): Value { + val databaseId = docRef.firestore.databaseId + return Value.newBuilder() + .setReferenceValue( + String.format( + "projects/%s/databases/%s/documents/%s", + databaseId.projectId, + databaseId.databaseId, + docRef.path + ) + ) + .build() + } + + @JvmStatic + fun encodeValue(vector: VectorValue): Value { + return encodeVectorValue(vector.toArray()) + } + + @JvmStatic + fun encodeVectorValue(vector: DoubleArray): Value { + val listBuilder = ArrayValue.newBuilder() + for (value in vector) { + listBuilder.addValues(encodeValue(value)) + } + return Value.newBuilder() + .setMapValue( + MapValue.newBuilder() + .putFields(TYPE_KEY, VECTOR_VALUE_TYPE) + .putFields(VECTOR_MAP_VECTORS_KEY, Value.newBuilder().setArrayValue(listBuilder).build()) + ) + .build() + } + + @JvmStatic + fun encodeValue(map: Map): Value { + return Value.newBuilder().setMapValue(MapValue.newBuilder().putAllFields(map)).build() + } + + @JvmStatic + fun encodeAnyValue(value: Any?): Value { + return when (value) { + null -> NULL_VALUE + is String -> encodeValue(value) + is Number -> encodeValue(value) + is Date -> encodeValue(value) + is com.google.firebase.Timestamp -> encodeValue(value) + is Boolean -> encodeValue(value) + is GeoPoint -> encodeValue(value) + is Blob -> encodeValue(value) + is DocumentReference -> encodeValue(value) + else -> throw IllegalArgumentException("Unexpected type: $value") + } } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt index 4ff2a25ee86..b584392fbc2 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt @@ -3,13 +3,14 @@ package com.google.firebase.firestore.pipeline import com.google.firebase.Timestamp import com.google.firebase.firestore.Blob import com.google.firebase.firestore.DocumentReference -import com.google.firebase.firestore.FieldValue import com.google.firebase.firestore.GeoPoint import com.google.firebase.firestore.VectorValue +import com.google.firebase.firestore.model.Values +import com.google.firebase.firestore.model.Values.encodeValue import com.google.firestore.v1.Value import java.util.Date -class Constant internal constructor(val value: Any?) : Expr() { +class Constant internal constructor(val value: Value) : Expr() { companion object { fun of(value: Any): Constant { @@ -23,62 +24,72 @@ class Constant internal constructor(val value: Any?) : Expr() { is Blob -> of(value) is DocumentReference -> of(value) is Value -> of(value) - is Iterable<*> -> of(value) - is Map<*, *> -> of(value) else -> throw IllegalArgumentException("Unknown type: $value") } } + @JvmStatic fun of(value: String): Constant { - return Constant(value) + return Constant(encodeValue(value)) } + @JvmStatic fun of(value: Number): Constant { - return Constant(value) + return Constant(encodeValue(value)) } + @JvmStatic fun of(value: Date): Constant { - return Constant(value) + return Constant(encodeValue(value)) } + @JvmStatic fun of(value: Timestamp): Constant { - return Constant(value) + return Constant(encodeValue(value)) } + @JvmStatic fun of(value: Boolean): Constant { - return Constant(value) + return Constant(encodeValue(value)) } + @JvmStatic fun of(value: GeoPoint): Constant { - return Constant(value) + return Constant(encodeValue(value)) } + @JvmStatic fun of(value: Blob): Constant { - return Constant(value) + return Constant(encodeValue(value)) } + @JvmStatic fun of(value: DocumentReference): Constant { - return Constant(value) - } - - fun of(value: Value): Constant { - return Constant(value) + return Constant(encodeValue(value)) } + @JvmStatic fun of(value: VectorValue): Constant { - return Constant(value) + return Constant(encodeValue(value)) } + @JvmStatic fun nullValue(): Constant { - return Constant(null) + return Constant(Values.NULL_VALUE) } + @JvmStatic fun vector(value: DoubleArray): Constant { - return of(FieldValue.vector(value)) + return Constant(Values.encodeVectorValue(value)) } + @JvmStatic fun vector(value: VectorValue): Constant { - return of(value) + return Constant(encodeValue(value)) } } + + override fun toProto(): Value { + return value + } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt new file mode 100644 index 00000000000..34bd8a9988c --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt @@ -0,0 +1,104 @@ +package com.google.firebase.firestore.pipeline + +import com.google.firestore.v1.Value + +class AccumulatorWithAlias +internal constructor(internal val alias: String, internal val accumulator: Accumulator) + +open class Accumulator +protected constructor(private val name: String, private val params: Array) { + protected constructor( + name: String, + param: Expr? + ) : this(name, if (param == null) emptyArray() else arrayOf(param)) + + companion object { + @JvmStatic + fun countAll(): Count { + return Count(null) + } + + @JvmStatic + fun count(fieldName: String): Count { + return Count(fieldName) + } + + @JvmStatic + fun count(expr: Expr): Count { + return Count(expr) + } + + @JvmStatic + fun sum(fieldName: String): Accumulator { + return Sum(fieldName) + } + + @JvmStatic + fun sum(expr: Expr): Accumulator { + return Sum(expr) + } + + @JvmStatic + fun avg(fieldName: String): Accumulator { + return Avg(fieldName) + } + + @JvmStatic + fun avg(expr: Expr): Accumulator { + return Avg(expr) + } + + @JvmStatic + fun min(fieldName: String): Accumulator { + return min(fieldName) + } + + @JvmStatic + fun min(expr: Expr): Accumulator { + return min(expr) + } + + @JvmStatic + fun max(fieldName: String): Accumulator { + return Max(fieldName) + } + + @JvmStatic + fun max(expr: Expr): Accumulator { + return Max(expr) + } + } + + fun `as`(alias: String): AccumulatorWithAlias { + return AccumulatorWithAlias(alias, this) + } + + fun toProto(): Value { + val builder = com.google.firestore.v1.Function.newBuilder() + builder.setName(name) + for (param in params) { + builder.addArgs(param.toProto()) + } + return Value.newBuilder().setFunctionValue(builder).build() + } +} + +class Count(value: Expr?) : Accumulator("count", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Sum(value: Expr) : Accumulator("sum", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Avg(value: Expr) : Accumulator("avg", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Min(value: Expr) : Accumulator("min", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} + +class Max(value: Expr) : Accumulator("max", value) { + constructor(fieldName: String) : this(Field.of(fieldName)) +} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt index b5449fc570b..3488d011a24 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt @@ -4,9 +4,14 @@ import com.google.firebase.firestore.FieldPath import com.google.firebase.firestore.VectorValue import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.FieldPath as ModelFieldPath - -open class Expr protected constructor() { - companion object { +import com.google.firebase.firestore.model.Values.encodeValue +import com.google.firestore.v1.ArrayValue +import com.google.firestore.v1.MapValue +import com.google.firestore.v1.Value +import com.google.protobuf.Timestamp + +abstract class Expr protected constructor() { + internal companion object { internal fun toExprOrConstant(other: Any): Expr { return when (other) { is Expr -> other @@ -14,15 +19,33 @@ open class Expr protected constructor() { } } - internal fun toArrayOfExprOrConstant(others: Iterable): Array { - return others.map(::toExprOrConstant).toTypedArray() - } + internal fun toArrayOfExprOrConstant(others: Iterable): Array = + others.map(::toExprOrConstant).toTypedArray() - internal fun toArrayOfExprOrConstant(others: Array): Array { - return others.map(::toExprOrConstant).toTypedArray() - } + internal fun toArrayOfExprOrConstant(others: Array): Array = + others.map(::toExprOrConstant).toTypedArray() } + /** + * Assigns an alias to this expression. + * + *

Aliases are useful for renaming fields in the output of a stage or for giving meaningful + * names to calculated values. + * + *

Example: + * + *

{@code // Calculate the total price and assign it the alias "totalPrice" and add it to the
+   * output. firestore.pipeline().collection("items")
+   * .addFields(Field.of("price").multiply(Field.of("quantity")).as("totalPrice")); }
+ * + * @param alias The alias to assign to this expression. + * @return A new {@code Selectable} (typically an {@link ExprWithAlias}) that wraps this + * ``` + * expression and associates it with the provided alias. + * ``` + */ + open fun `as`(alias: String) = ExprWithAlias(alias, this) + /** * Creates an expression that this expression to another expression. * @@ -34,9 +57,7 @@ open class Expr protected constructor() { * @param other The expression to add to this expression. * @return A new {@code Expr} representing the addition operation. */ - fun add(other: Expr): Add { - return Add(this, other) - } + fun add(other: Expr) = Add(this, other) /** * Creates an expression that this expression to another expression. @@ -49,17 +70,171 @@ open class Expr protected constructor() { * @param other The constant value to add to this expression. * @return A new {@code Expr} representing the addition operation. */ - fun add(other: Any): Add { - return Add(this, toExprOrConstant(other)) - } + fun add(other: Any) = Add(this, other) - fun subtract(other: Expr): Subtract { - return Subtract(this, other) - } + fun subtract(other: Expr) = Subtract(this, other) + + fun subtract(other: Any) = Subtract(this, other) + + fun multiply(other: Expr) = Multiply(this, other) + + fun multiply(other: Any) = Multiply(this, other) + + fun divide(other: Expr) = Divide(this, other) + + fun divide(other: Any) = Divide(this, other) + + fun mod(other: Expr) = Mod(this, other) + + fun mod(other: Any) = Mod(this, other) + + fun `in`(values: List) = In(this, values) + + fun isNan() = IsNan(this) + + fun replaceFirst(find: Expr, replace: Expr) = ReplaceFirst(this, find, replace) + + fun replaceFirst(find: String, replace: String) = ReplaceFirst(this, find, replace) + + fun replaceAll(find: Expr, replace: Expr) = ReplaceAll(this, find, replace) + + fun replaceAll(find: String, replace: String) = ReplaceAll(this, find, replace) + + fun charLength() = CharLength(this) + + fun byteLength() = ByteLength(this) + + fun like(pattern: Expr) = Like(this, pattern) + + fun like(pattern: String) = Like(this, pattern) + + fun regexContains(pattern: Expr) = RegexContains(this, pattern) + + fun regexContains(pattern: String) = RegexContains(this, pattern) + + fun regexMatch(pattern: Expr) = RegexMatch(this, pattern) + + fun regexMatch(pattern: String) = RegexMatch(this, pattern) + + fun logicalMax(other: Expr) = LogicalMax(this, other) + + fun logicalMax(other: Any) = LogicalMax(this, other) + + fun logicalMin(other: Expr) = LogicalMin(this, other) + + fun logicalMin(other: Any) = LogicalMin(this, other) + + fun reverse() = Reverse(this) + + fun strContains(substring: Expr) = StrContains(this, substring) + + fun strContains(substring: String) = StrContains(this, substring) + + fun startsWith(prefix: Expr) = StartsWith(this, prefix) + + fun startsWith(prefix: String) = StartsWith(this, prefix) + + fun endsWith(suffix: Expr) = EndsWith(this, suffix) + + fun endsWith(suffix: String) = EndsWith(this, suffix) + + fun toLower() = ToLower(this) + + fun toUpper() = ToUpper(this) + + fun trim() = Trim(this) + + fun strConcat(vararg expr: Expr) = StrConcat(this, *expr) + + fun strConcat(string: String, vararg expr: Expr) = StrConcat(this, string, *expr) + + fun mapGet(key: Expr) = MapGet(this, key) + + fun mapGet(key: String) = MapGet(this, key) + + fun cosineDistance(vector: Expr) = CosineDistance(this, vector) + + fun cosineDistance(vector: DoubleArray) = CosineDistance(this, vector) + + fun cosineDistance(vector: VectorValue) = CosineDistance(this, vector) + + fun dotProduct(vector: Expr) = DotProduct(this, vector) + + fun dotProduct(vector: DoubleArray) = DotProduct(this, vector) + + fun dotProduct(vector: VectorValue) = DotProduct(this, vector) + + fun euclideanDistance(vector: Expr) = EuclideanDistance(this, vector) + + fun euclideanDistance(vector: DoubleArray) = EuclideanDistance(this, vector) + + fun euclideanDistance(vector: VectorValue) = EuclideanDistance(this, vector) + + fun vectorLength() = VectorLength(this) + + fun unixMicrosToTimestamp() = UnixMicrosToTimestamp(this) + + fun timestampToUnixMicros() = TimestampToUnixMicros(this) + + fun unixMillisToTimestamp() = UnixMillisToTimestamp(this) + + fun timestampToUnixMillis() = TimestampToUnixMillis(this) + + fun unixSecondsToTimestamp() = UnixSecondsToTimestamp(this) + + fun timestampToUnixSeconds() = TimestampToUnixSeconds(this) + + fun timestampAdd(unit: Expr, amount: Expr) = TimestampAdd(this, unit, amount) + + fun timestampAdd(unit: String, amount: Double) = TimestampAdd(this, unit, amount) + + fun timestampSub(unit: Expr, amount: Expr) = TimestampSub(this, unit, amount) + + fun timestampSub(unit: String, amount: Double) = TimestampSub(this, unit, amount) + + fun arrayConcat(vararg arrays: Expr) = ArrayConcat(this, *arrays) + + fun arrayConcat(arrays: List) = ArrayConcat(this, arrays) + + fun arrayReverse() = ArrayReverse(this) + + fun arrayContains(value: Expr) = ArrayContains(this, value) + + fun arrayContains(value: Any) = ArrayContains(this, value) + + fun arrayContainsAll(values: List) = ArrayContainsAll(this, values) + + fun arrayContainsAny(values: List) = ArrayContainsAny(this, values) + + fun arrayLength() = ArrayLength(this) + + fun sum() = Sum(this) + + fun avg() = Avg(this) + + fun min() = Min(this) + + fun max() = Max(this) + + fun ascending() = Ordering.ascending(this) + + fun descending() = Ordering.descending(this) + + internal abstract fun toProto(): Value +} + +abstract class Selectable(internal val alias: String) : Expr() + +open class ExprWithAlias internal constructor(alias: String, internal val expr: Expr) : + Selectable(alias) { + override fun toProto(): Value = expr.toProto() } -class Field private constructor(private val fieldPath: ModelFieldPath) : Expr() { +class Field private constructor(val fieldPath: ModelFieldPath) : + Selectable(fieldPath.canonicalString()) { companion object { + + @JvmStatic fun of(name: String): Field { if (name == DocumentKey.KEY_FIELD_NAME) { return Field(ModelFieldPath.KEY_PATH) @@ -67,6 +242,7 @@ class Field private constructor(private val fieldPath: ModelFieldPath) : Expr() return Field(FieldPath.fromDotSeparatedPath(name).internalPath) } + @JvmStatic fun of(fieldPath: FieldPath): Field { if (fieldPath == FieldPath.documentId()) { return Field(FieldPath.documentId().internalPath) @@ -74,12 +250,120 @@ class Field private constructor(private val fieldPath: ModelFieldPath) : Expr() return Field(fieldPath.internalPath) } } + override fun toProto() = + Value.newBuilder().setFieldReferenceValue(fieldPath.canonicalString()).build() } -class ListOfExpr(val expressions: Array) : Expr() +class ListOfExprs(val expressions: Array) : Expr() { + override fun toProto(): Value { + val builder = ArrayValue.newBuilder() + for (expr in expressions) { + builder.addValues(expr.toProto()) + } + return Value.newBuilder().setArrayValue(builder).build() + } +} open class Function protected constructor(private val name: String, private val params: Array) : Expr() { + companion object { + @JvmStatic + fun and(condition: BooleanExpr, vararg conditions: BooleanExpr) = And(condition, *conditions) + + @JvmStatic + fun or(condition: BooleanExpr, vararg conditions: BooleanExpr) = Or(condition, *conditions) + + @JvmStatic + fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = Xor(condition, *conditions) + + @JvmStatic fun not(cond: BooleanExpr) = Not(cond) + + @JvmStatic fun eq(left: Expr, right: Expr) = Eq(left, right) + + @JvmStatic fun eq(left: Expr, right: Any) = Eq(left, right) + + @JvmStatic fun eq(fieldName: String, right: Expr) = Eq(fieldName, right) + + @JvmStatic fun eq(fieldName: String, right: Any) = Eq(fieldName, right) + + @JvmStatic fun neq(left: Expr, right: Expr) = Neq(left, right) + + @JvmStatic fun neq(left: Expr, right: Any) = Neq(left, right) + + @JvmStatic fun neq(fieldName: String, right: Expr) = Neq(fieldName, right) + + @JvmStatic fun neq(fieldName: String, right: Any) = Neq(fieldName, right) + + @JvmStatic fun gt(left: Expr, right: Expr) = Gt(left, right) + + @JvmStatic fun gt(left: Expr, right: Any) = Gt(left, right) + + @JvmStatic fun gt(fieldName: String, right: Expr) = Gt(fieldName, right) + + @JvmStatic fun gt(fieldName: String, right: Any) = Gt(fieldName, right) + + @JvmStatic fun gte(left: Expr, right: Expr) = Gte(left, right) + + @JvmStatic fun gte(left: Expr, right: Any) = Gte(left, right) + + @JvmStatic fun gte(fieldName: String, right: Expr) = Gte(fieldName, right) + + @JvmStatic fun gte(fieldName: String, right: Any) = Gte(fieldName, right) + + @JvmStatic fun lt(left: Expr, right: Expr) = Lt(left, right) + + @JvmStatic fun lt(left: Expr, right: Any) = Lt(left, right) + + @JvmStatic fun lt(fieldName: String, right: Expr) = Lt(fieldName, right) + + @JvmStatic fun lt(fieldName: String, right: Any) = Lt(fieldName, right) + + @JvmStatic fun lte(left: Expr, right: Expr) = Lte(left, right) + + @JvmStatic fun lte(left: Expr, right: Any) = Lte(left, right) + + @JvmStatic fun lte(fieldName: String, right: Expr) = Lte(fieldName, right) + + @JvmStatic fun lte(fieldName: String, right: Any) = Lte(fieldName, right) + + @JvmStatic fun arrayConcat(array: Expr, vararg arrays: Expr) = ArrayConcat(array, *arrays) + + @JvmStatic + fun arrayConcat(fieldName: String, vararg arrays: Expr) = ArrayConcat(fieldName, *arrays) + + @JvmStatic fun arrayConcat(array: Expr, arrays: List) = ArrayConcat(array, arrays) + + @JvmStatic + fun arrayConcat(fieldName: String, arrays: List) = ArrayConcat(fieldName, arrays) + + @JvmStatic fun arrayReverse(array: Expr) = ArrayReverse(array) + + @JvmStatic fun arrayReverse(fieldName: String) = ArrayReverse(fieldName) + + @JvmStatic fun arrayContains(array: Expr, value: Expr) = ArrayContains(array, value) + + @JvmStatic fun arrayContains(fieldName: String, value: Expr) = ArrayContains(fieldName, value) + + @JvmStatic fun arrayContains(array: Expr, value: Any) = ArrayContains(array, value) + + @JvmStatic fun arrayContains(fieldName: String, value: Any) = ArrayContains(fieldName, value) + + @JvmStatic + fun arrayContainsAll(array: Expr, values: List) = ArrayContainsAll(array, values) + + @JvmStatic + fun arrayContainsAll(fieldName: String, values: List) = ArrayContainsAll(fieldName, values) + + @JvmStatic + fun arrayContainsAny(array: Expr, values: List) = ArrayContainsAny(array, values) + + @JvmStatic + fun arrayContainsAny(fieldName: String, values: List) = ArrayContainsAny(fieldName, values) + + @JvmStatic fun arrayLength(array: Expr) = ArrayLength(array) + + @JvmStatic fun arrayLength(fieldName: String) = ArrayLength(fieldName) + } protected constructor(name: String, param1: Expr) : this(name, arrayOf(param1)) protected constructor( name: String, @@ -92,17 +376,56 @@ protected constructor(private val name: String, private val params: Array) : +open class BooleanExpr protected constructor(name: String, vararg params: Expr) : Function(name, params) { - protected constructor( - name: String, - param: Expr? - ) : this(name, if (param == null) emptyArray() else arrayOf(param)) + + fun and(vararg conditions: BooleanExpr): And = And(this, *conditions) + + fun or(vararg conditions: BooleanExpr): Or = Or(this, *conditions) + + fun xor(vararg conditions: BooleanExpr): Xor = Xor(this, *conditions) + + fun not(): Not = Not(this) +} + +class Ordering private constructor(private val expr: Expr, private val dir: Direction) { + companion object { + @JvmStatic fun ascending(expr: Expr): Ordering = Ordering(expr, Direction.ASCENDING) + + @JvmStatic + fun ascending(fieldName: String): Ordering = Ordering(Field.of(fieldName), Direction.ASCENDING) + + @JvmStatic fun descending(expr: Expr): Ordering = Ordering(expr, Direction.DESCENDING) + + @JvmStatic + fun descending(fieldName: String): Ordering = + Ordering(Field.of(fieldName), Direction.DESCENDING) + } + private class Direction private constructor(internal val proto: Value) { + private constructor(protoString: String) : this(encodeValue(protoString)) + companion object { + val ASCENDING = Direction("ascending") + val DESCENDING = Direction("descending") + } + } + internal fun toProto(): Value = + Value.newBuilder() + .setMapValue( + MapValue.newBuilder() + .putFields("direction", dir.proto) + .putFields("expression", expr.toProto()) + ) + .build() } class Add(left: Expr, right: Expr) : Function("add", left, right) { @@ -171,37 +494,37 @@ class Mod(left: Expr, right: Expr) : Function("mod", left, right) { // constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) // } -class Eq(left: Expr, right: Expr) : FilterCondition("eq", left, right) { +class Eq(left: Expr, right: Expr) : BooleanExpr("eq", left, right) { constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } -class Neq(left: Expr, right: Expr) : FilterCondition("neq", left, right) { +class Neq(left: Expr, right: Expr) : BooleanExpr("neq", left, right) { constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } -class Lt(left: Expr, right: Expr) : FilterCondition("lt", left, right) { +class Lt(left: Expr, right: Expr) : BooleanExpr("lt", left, right) { constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } -class Lte(left: Expr, right: Expr) : FilterCondition("lte", left, right) { +class Lte(left: Expr, right: Expr) : BooleanExpr("lte", left, right) { constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } -class Gt(left: Expr, right: Expr) : FilterCondition("gt", left, right) { +class Gt(left: Expr, right: Expr) : BooleanExpr("gt", left, right) { constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } -class Gte(left: Expr, right: Expr) : FilterCondition("gte", left, right) { +class Gte(left: Expr, right: Expr) : BooleanExpr("gte", left, right) { constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) @@ -209,7 +532,7 @@ class Gte(left: Expr, right: Expr) : FilterCondition("gte", left, right) { class ArrayConcat(array: Expr, vararg arrays: Expr) : Function("array_concat", arrayOf(array, *arrays)) { - constructor(array: Expr, arrays: List) : this(array, toExprOrConstant(arrays)) + constructor(array: Expr, arrays: List) : this(array, ListOfExprs(toArrayOfExprOrConstant(arrays))) constructor(fieldName: String, vararg arrays: Expr) : this(Field.of(fieldName), *arrays) constructor(fieldName: String, right: List) : this(Field.of(fieldName), right) } @@ -218,19 +541,19 @@ class ArrayReverse(array: Expr) : Function("array_reverse", array) { constructor(fieldName: String) : this(Field.of(fieldName)) } -class ArrayContains(array: Expr, value: Expr) : FilterCondition("array_contains", array, value) { +class ArrayContains(array: Expr, value: Expr) : BooleanExpr("array_contains", array, value) { constructor(array: Expr, right: Any) : this(array, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) } class ArrayContainsAll(array: Expr, values: List) : - FilterCondition("array_contains_all", array, ListOfExpr(toArrayOfExprOrConstant(values))) { + BooleanExpr("array_contains_all", array, ListOfExprs(toArrayOfExprOrConstant(values))) { constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) } class ArrayContainsAny(array: Expr, values: List) : - FilterCondition("array_contains_any", array, ListOfExpr(toArrayOfExprOrConstant(values))) { + BooleanExpr("array_contains_any", array, ListOfExprs(toArrayOfExprOrConstant(values))) { constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) } @@ -239,52 +562,30 @@ class ArrayLength(array: Expr) : Function("array_length", array) { } class In(array: Expr, values: List) : - FilterCondition("in", array, ListOfExpr(toArrayOfExprOrConstant(values))) { + BooleanExpr("in", array, ListOfExprs(toArrayOfExprOrConstant(values))) { constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) } -class IsNan(expr: Expr) : FilterCondition("is_nan", expr) { +class IsNan(expr: Expr) : BooleanExpr("is_nan", expr) { constructor(fieldName: String) : this(Field.of(fieldName)) } -class Exists(expr: Expr) : FilterCondition("exists", expr) { +class Exists(expr: Expr) : BooleanExpr("exists", expr) { constructor(fieldName: String) : this(Field.of(fieldName)) } -class Not(expr: Expr) : FilterCondition("not", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} +class Not(cond: BooleanExpr) : BooleanExpr("not", cond) -class And(condition: Expr, vararg conditions: Expr) : - FilterCondition("and", condition, *conditions) { - constructor( - condition: Expr, - vararg conditions: Any - ) : this(condition, *toArrayOfExprOrConstant(conditions)) - constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) - constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) -} +class And(condition: BooleanExpr, vararg conditions: BooleanExpr) : + BooleanExpr("and", condition, *conditions) -class Or(condition: Expr, vararg conditions: Expr) : FilterCondition("or", condition, *conditions) { - constructor( - condition: Expr, - vararg conditions: Any - ) : this(condition, *toArrayOfExprOrConstant(conditions)) - constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) - constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) -} +class Or(condition: BooleanExpr, vararg conditions: BooleanExpr) : + BooleanExpr("or", condition, *conditions) -class Xor(condition: Expr, vararg conditions: Expr) : - FilterCondition("xor", condition, *conditions) { - constructor( - condition: Expr, - vararg conditions: Any - ) : this(condition, *toArrayOfExprOrConstant(conditions)) - constructor(fieldName: String, vararg conditions: Expr) : this(Field.of(fieldName), *conditions) - constructor(fieldName: String, vararg conditions: Any) : this(Field.of(fieldName), *conditions) -} +class Xor(condition: BooleanExpr, vararg conditions: Expr) : + BooleanExpr("xor", condition, *conditions) -class If(condition: FilterCondition, thenExpr: Expr, elseExpr: Expr) : +class If(condition: BooleanExpr, thenExpr: Expr, elseExpr: Expr) : Function("if", condition, thenExpr, elseExpr) class LogicalMax(left: Expr, right: Expr) : Function("logical_max", left, right) { @@ -339,37 +640,37 @@ class ByteLength(value: Expr) : Function("byte_length", value) { constructor(fieldName: String) : this(Field.of(fieldName)) } -class Like(expr: Expr, pattern: Expr) : FilterCondition("like", expr, pattern) { +class Like(expr: Expr, pattern: Expr) : BooleanExpr("like", expr, pattern) { constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) } -class RegexContains(expr: Expr, pattern: Expr) : FilterCondition("regex_contains", expr, pattern) { +class RegexContains(expr: Expr, pattern: Expr) : BooleanExpr("regex_contains", expr, pattern) { constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) } -class RegexMatch(expr: Expr, pattern: Expr) : FilterCondition("regex_match", expr, pattern) { +class RegexMatch(expr: Expr, pattern: Expr) : BooleanExpr("regex_match", expr, pattern) { constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) } -class StrContains(expr: Expr, substring: Expr) : FilterCondition("str_contains", expr, substring) { +class StrContains(expr: Expr, substring: Expr) : BooleanExpr("str_contains", expr, substring) { constructor(expr: Expr, substring: String) : this(expr, Constant.of(substring)) constructor(fieldName: String, substring: Expr) : this(Field.of(fieldName), substring) constructor(fieldName: String, substring: String) : this(Field.of(fieldName), substring) } -class StartsWith(expr: Expr, prefix: Expr) : FilterCondition("starts_with", expr, prefix) { +class StartsWith(expr: Expr, prefix: Expr) : BooleanExpr("starts_with", expr, prefix) { constructor(expr: Expr, prefix: String) : this(expr, Constant.of(prefix)) constructor(fieldName: String, prefix: Expr) : this(Field.of(fieldName), prefix) constructor(fieldName: String, prefix: String) : this(Field.of(fieldName), prefix) } -class EndsWith(expr: Expr, suffix: Expr) : FilterCondition("ends_with", expr, suffix) { +class EndsWith(expr: Expr, suffix: Expr) : BooleanExpr("ends_with", expr, suffix) { constructor(expr: Expr, suffix: String) : this(expr, Constant.of(suffix)) constructor(fieldName: String, suffix: Expr) : this(Field.of(fieldName), suffix) constructor(fieldName: String, suffix: String) : this(Field.of(fieldName), suffix) @@ -391,34 +692,17 @@ class StrConcat internal constructor(first: Expr, vararg rest: Expr) : Function("str_concat", arrayOf(first, *rest)) { constructor( first: Expr, - vararg rest: String - ) : this(first, *rest.map(Constant::of).toTypedArray()) + second: String, + vararg rest: Expr + ) : this(first, Constant.of(second), *rest) constructor(fieldName: String, vararg rest: Expr) : this(Field.of(fieldName), *rest) - constructor(fieldName: String, vararg rest: String) : this(Field.of(fieldName), *rest) -} - -class MapGet(map: Expr, name: String) : Function("map_get", map, Constant.of(name)) { - constructor(fieldName: String, name: String) : this(Field.of(fieldName), name) -} - -class Count(value: Expr?) : Accumulator("count", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class Sum(value: Expr) : Accumulator("sum", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) + constructor(fieldName: String, second: String, vararg rest: Expr) : this(Field.of(fieldName), second, *rest) } -class Avg(value: Expr) : Accumulator("avg", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class Min(value: Expr) : Accumulator("min", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class Max(value: Expr) : Accumulator("max", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) +class MapGet(map: Expr, key: Expr) : Function("map_get", map, key) { + constructor(map: Expr, key: String) : this(map, Constant.of(key)) + constructor(fieldName: String, key: Expr) : this(Field.of(fieldName), key) + constructor(fieldName: String, key: String) : this(Field.of(fieldName), key) } class CosineDistance(vector1: Expr, vector2: Expr) : Function("cosine_distance", vector1, vector2) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index ce63d74389d..d1ed15d2ef7 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -1,48 +1,182 @@ package com.google.firebase.firestore.pipeline -import com.google.firebase.firestore.DocumentReference +import com.google.common.collect.ImmutableMap +import com.google.firebase.firestore.model.Values.encodeValue +import com.google.firebase.firestore.model.Values.encodeVectorValue import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value -abstract class Stage(protected val name: String) { +abstract class Stage +internal constructor(private val name: String, private val options: Map) { + internal constructor(name: String) : this(name, emptyMap()) internal fun toProtoStage(): Pipeline.Stage { val builder = Pipeline.Stage.newBuilder() builder.setName(name) args().forEach { arg -> builder.addArgs(arg) } + builder.putAllOptions(options) return builder.build() } protected abstract fun args(): Sequence } class DatabaseSource : Stage("database") { - override fun args(): Sequence { - return emptySequence() - } + override fun args(): Sequence = emptySequence() } class CollectionSource internal constructor(path: String) : Stage("collection") { private val path: String = if (path.startsWith("/")) path else "/" + path - override fun args(): Sequence { - return sequenceOf(Value.newBuilder().setReferenceValue(path).build()) - } + override fun args(): Sequence = + sequenceOf(Value.newBuilder().setReferenceValue(path).build()) } class CollectionGroupSource internal constructor(val collectionId: String) : Stage("collection_group") { - override fun args(): Sequence { - return sequenceOf( - Value.newBuilder().setReferenceValue("").build(), - Value.newBuilder().setStringValue(collectionId).build() + override fun args(): Sequence = + sequenceOf(Value.newBuilder().setReferenceValue("").build(), encodeValue(collectionId)) +} + +class DocumentsSource internal constructor(private val documents: Array) : + Stage("documents") { + override fun args(): Sequence = documents.asSequence().map(::encodeValue) +} + +class AddFieldsStage internal constructor(private val fields: Array) : + Stage("add_fields") { + override fun args(): Sequence = + sequenceOf(encodeValue(fields.associate { it.alias to it.toProto() })) +} + +class AggregateStage +internal constructor( + private val accumulators: Map, + private val groups: Map +) : Stage("aggregate") { + internal constructor(accumulators: Map) : this(accumulators, emptyMap()) + companion object { + @JvmStatic + fun withAccumulators(vararg accumulators: AccumulatorWithAlias): AggregateStage { + if (accumulators.isEmpty()) { + throw IllegalArgumentException( + "Must specify at least one accumulator for aggregate() stage. There is a distinct() stage if only distinct group values are needed." + ) + } + return AggregateStage(accumulators.associate { it.alias to it.accumulator }) + } + } + + fun withGroups(vararg selectable: Selectable) = + AggregateStage(accumulators, selectable.associateBy(Selectable::alias)) + + fun withGroups(vararg fields: String) = + AggregateStage(accumulators, fields.associateWith(Field::of)) + + override fun args(): Sequence = + sequenceOf( + encodeValue(accumulators.mapValues { entry -> entry.value.toProto() }), + encodeValue(groups.mapValues { entry -> entry.value.toProto() }) ) +} + +class WhereStage internal constructor(private val condition: BooleanExpr) : Stage("where") { + override fun args(): Sequence = sequenceOf(condition.toProto()) +} + +class FindNearestStage +internal constructor( + private val property: Expr, + private val vector: DoubleArray, + private val distanceMeasure: DistanceMeasure, + private val options: FindNearestOptions +) : Stage("find_nearest", options.toProto()) { + + class DistanceMeasure private constructor(internal val proto: Value) { + private constructor(protoString: String) : this(encodeValue(protoString)) + companion object { + val EUCLIDEAN = DistanceMeasure("euclidean") + val COSINE = DistanceMeasure("cosine") + val DOT_PRODUCT = DistanceMeasure("dot_product") + } } + + override fun args(): Sequence = + sequenceOf(property.toProto(), encodeVectorValue(vector), distanceMeasure.proto) } -class DocumentsSource private constructor(private val documents: List) : - Stage("documents") { - internal constructor( - documents: Array - ) : this(documents.map { docRef -> "/" + docRef.path }) - override fun args(): Sequence { - return documents.asSequence().map { doc -> Value.newBuilder().setStringValue(doc).build() } +class FindNearestOptions +internal constructor(private val limit: Long?, private val distanceField: Field?) { + fun toProto(): Map { + val builder = ImmutableMap.builder() + if (limit != null) { + builder.put("limit", encodeValue(limit)) + } + if (distanceField != null) { + builder.put("distance_field", distanceField.toProto()) + } + return builder.build() } } + +class LimitStage internal constructor(private val limit: Long) : Stage("limit") { + override fun args(): Sequence = sequenceOf(encodeValue(limit)) +} + +class OffsetStage internal constructor(private val offset: Long) : Stage("offset") { + override fun args(): Sequence = sequenceOf(encodeValue(offset)) +} + +class SelectStage internal constructor(private val fields: Array) : + Stage("select") { + override fun args(): Sequence = + sequenceOf(encodeValue(fields.associate { it.alias to it.toProto() })) +} + +class SortStage internal constructor(private val orders: Array) : Stage("sort") { + override fun args(): Sequence = orders.asSequence().map(Ordering::toProto) +} + +class DistinctStage internal constructor(private val groups: Array) : + Stage("distinct") { + override fun args(): Sequence = + sequenceOf(encodeValue(groups.associate { it.alias to it.toProto() })) +} + +class RemoveFieldsStage internal constructor(private val fields: Array) : + Stage("remove_fields") { + override fun args(): Sequence = fields.asSequence().map(Field::toProto) +} + +class ReplaceStage internal constructor(private val field: Selectable, private val mode: Mode) : + Stage("replace") { + class Mode private constructor(internal val proto: Value) { + private constructor(protoString: String) : this(encodeValue(protoString)) + companion object { + val FULL_REPLACE = Mode("full_replace") + val MERGE_PREFER_NEXT = Mode("merge_prefer_nest") + val MERGE_PREFER_PARENT = Mode("merge_prefer_parent") + } + } + override fun args(): Sequence = sequenceOf(field.toProto(), mode.proto) +} + +class SampleStage internal constructor(private val size: Number, private val mode: Mode) : + Stage("sample") { + class Mode private constructor(internal val proto: Value) { + private constructor(protoString: String) : this(encodeValue(protoString)) + companion object { + val DOCUMENTS = Mode("documents") + val PERCENT = Mode("percent") + } + } + override fun args(): Sequence = sequenceOf(encodeValue(size), mode.proto) +} + +class UnionStage internal constructor(private val other: com.google.firebase.firestore.Pipeline) : + Stage("union") { + override fun args(): Sequence = + sequenceOf(Value.newBuilder().setPipelineValue(other.toPipelineProto()).build()) +} + +class UnnestStage internal constructor(private val selectable: Selectable) : Stage("unnest") { + override fun args(): Sequence = + sequenceOf(encodeValue(selectable.alias), selectable.toProto()) +} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java index 8e7aab83565..91086531db1 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java @@ -21,6 +21,7 @@ import androidx.annotation.VisibleForTesting; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; +import com.google.common.base.Strings; import com.google.firebase.firestore.AggregateField; import com.google.firebase.firestore.FirebaseFirestoreException; import com.google.firebase.firestore.PipelineResultObserver; @@ -255,7 +256,7 @@ public void onMessage(ExecutePipelineResponse message) { for (Document document : message.getResultsList()) { String documentName = document.getName(); observer.onDocument( - documentName == null ? null : serializer.decodeKey(documentName), + Strings.isNullOrEmpty(documentName) ? null : serializer.decodeKey(documentName), document.getFieldsMap(), serializer.decodeVersion(document.getUpdateTime())); } diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/TestAccessHelper.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/TestAccessHelper.java index bab88979493..2ace80dacef 100644 --- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/TestAccessHelper.java +++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/TestAccessHelper.java @@ -14,14 +14,16 @@ package com.google.firebase.firestore; +import static org.mockito.Mockito.mock; + import com.google.firebase.firestore.model.DocumentKey; public final class TestAccessHelper { /** Makes the DocumentReference constructor accessible. */ public static DocumentReference createDocumentReference(DocumentKey documentKey) { - // We can use null here because the tests only use this as a wrapper for documentKeys. - return new DocumentReference(documentKey, null); + // We can use mock here because the tests only use this as a wrapper for documentKeys. + return new DocumentReference(documentKey, mock(FirebaseFirestore.class)); } /** Makes the getKey() method accessible. */ From e5734cd7f04034ed88a6273e9702c7361cf1aed3 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 14 Feb 2025 20:31:08 -0500 Subject: [PATCH 12/77] Copyright --- .../google/firebase/firestore/PipelineTest.java | 14 ++++++++++++++ .../java/com/google/firebase/firestore/Pipeline.kt | 14 ++++++++++++++ .../google/firebase/firestore/pipeline/Constant.kt | 14 ++++++++++++++ .../firebase/firestore/pipeline/accumulators.kt | 14 ++++++++++++++ .../firebase/firestore/pipeline/expression.kt | 14 ++++++++++++++ .../google/firebase/firestore/pipeline/stage.kt | 14 ++++++++++++++ .../firebase/firestore/pipeline/ExprTest.java | 14 -------------- .../firebase/firestore/pipeline/StageTest.java | 14 -------------- 8 files changed, 84 insertions(+), 28 deletions(-) delete mode 100644 firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java delete mode 100644 firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index a88959dd930..ce701cd1167 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -1,3 +1,17 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.google.firebase.firestore; import static com.google.common.truth.Truth.assertThat; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 4eb6ba5d1d6..941690eb372 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -1,3 +1,17 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.google.firebase.firestore import com.google.android.gms.tasks.Task diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt index b584392fbc2..fdcac5c59c3 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt @@ -1,3 +1,17 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.google.firebase.firestore.pipeline import com.google.firebase.Timestamp diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt index 34bd8a9988c..8098183c1c2 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt @@ -1,3 +1,17 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.google.firebase.firestore.pipeline import com.google.firestore.v1.Value diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt index 3488d011a24..875a952e9a7 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt @@ -1,3 +1,17 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.google.firebase.firestore.pipeline import com.google.firebase.firestore.FieldPath diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index d1ed15d2ef7..dd9c48ab5bf 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -1,3 +1,17 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.google.firebase.firestore.pipeline import com.google.common.collect.ImmutableMap diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java deleted file mode 100644 index 4468151e344..00000000000 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/ExprTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.google.firebase.firestore.pipeline; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -@RunWith(RobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class ExprTest { - - @Test - public void test() {} -} diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java deleted file mode 100644 index eb1b03119f4..00000000000 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/pipeline/StageTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.google.firebase.firestore.pipeline; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -@RunWith(RobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class StageTest { - - @Test - public void test() {} -} From 70bdf626e6de82d09c388dbb84719007dfa19b06 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 14 Feb 2025 20:45:13 -0500 Subject: [PATCH 13/77] spotless --- .../firebase/firestore/PipelineTest.java | 55 ++++++++++++------- .../firebase/firestore/pipeline/expression.kt | 12 +++- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index ce701cd1167..128ae39da02 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -37,7 +37,6 @@ import com.google.firebase.firestore.testutil.IntegrationTestUtil; import java.util.Map; import java.util.Objects; - import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -47,22 +46,26 @@ @RunWith(AndroidJUnit4.class) public class PipelineTest { - private static final Correspondence> DATA_CORRESPONDENCE = Correspondence.from((result, expected) -> { - assertThat(result.getData()) - .comparingValuesUsing(Correspondence.from( - (x, y) -> { - if (x instanceof Long && y instanceof Integer) { - return (long) x == (long) (int) y; - } - return Objects.equals(x, y); - }, - "MapValueCompare" - )) - .containsExactlyEntriesIn(expected); - return true; - }, "GetData"); + private static final Correspondence> DATA_CORRESPONDENCE = + Correspondence.from( + (result, expected) -> { + assertThat(result.getData()) + .comparingValuesUsing( + Correspondence.from( + (x, y) -> { + if (x instanceof Long && y instanceof Integer) { + return (long) x == (long) (int) y; + } + return Objects.equals(x, y); + }, + "MapValueCompare")) + .containsExactlyEntriesIn(expected); + return true; + }, + "GetData"); - private static final Correspondence ID_CORRESPONDENCE = Correspondence.transforming(x -> x.getRef().getId(), "GetRefId"); + private static final Correspondence ID_CORRESPONDENCE = + Correspondence.transforming(x -> x.getRef().getId(), "GetRefId"); private CollectionReference randomCol; private FirebaseFirestore firestore; @@ -277,7 +280,12 @@ public void minAndMaxAccumulations() { @Test public void canSelectFields() { Task execute = - firestore.pipeline().collection(randomCol).select("title", "author").sort(Field.of("author").ascending()).execute(); + firestore + .pipeline() + .collection(randomCol) + .select("title", "author") + .sort(Field.of("author").ascending()) + .execute(); PipelineSnapshot snapshot = waitFor(execute); assertThat(snapshot.getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -426,13 +434,19 @@ public void arrayConcatWorks() { .pipeline() .collection(randomCol) .where(eq("title", "The Hitchhiker's Guide to the Galaxy")) - .select(Field.of("tags").arrayConcat(ImmutableList.of("newTag1", "newTag2")).as("modifiedTags")) + .select( + Field.of("tags") + .arrayConcat(ImmutableList.of("newTag1", "newTag2")) + .as("modifiedTags")) .limit(1) .execute(); PipelineSnapshot snapshot = waitFor(execute); assertThat(snapshot.getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) - .containsExactly(ImmutableMap.of("modifiedTags", ImmutableList.of("comedy", "space", "adventure", "newTag1", "newTag2"))); + .containsExactly( + ImmutableMap.of( + "modifiedTags", + ImmutableList.of("comedy", "space", "adventure", "newTag1", "newTag2"))); } @Test @@ -446,6 +460,7 @@ public void testStrConcat() { PipelineSnapshot snapshot = waitFor(execute); assertThat(snapshot.getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) - .containsExactly(ImmutableMap.of("bookInfo", "Douglas Adams - The Hitchhiker's Guide to the Galaxy")); + .containsExactly( + ImmutableMap.of("bookInfo", "Douglas Adams - The Hitchhiker's Guide to the Galaxy")); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt index 875a952e9a7..f0e473dabfc 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt @@ -22,7 +22,6 @@ import com.google.firebase.firestore.model.Values.encodeValue import com.google.firestore.v1.ArrayValue import com.google.firestore.v1.MapValue import com.google.firestore.v1.Value -import com.google.protobuf.Timestamp abstract class Expr protected constructor() { internal companion object { @@ -546,7 +545,10 @@ class Gte(left: Expr, right: Expr) : BooleanExpr("gte", left, right) { class ArrayConcat(array: Expr, vararg arrays: Expr) : Function("array_concat", arrayOf(array, *arrays)) { - constructor(array: Expr, arrays: List) : this(array, ListOfExprs(toArrayOfExprOrConstant(arrays))) + constructor( + array: Expr, + arrays: List + ) : this(array, ListOfExprs(toArrayOfExprOrConstant(arrays))) constructor(fieldName: String, vararg arrays: Expr) : this(Field.of(fieldName), *arrays) constructor(fieldName: String, right: List) : this(Field.of(fieldName), right) } @@ -710,7 +712,11 @@ class StrConcat internal constructor(first: Expr, vararg rest: Expr) : vararg rest: Expr ) : this(first, Constant.of(second), *rest) constructor(fieldName: String, vararg rest: Expr) : this(Field.of(fieldName), *rest) - constructor(fieldName: String, second: String, vararg rest: Expr) : this(Field.of(fieldName), second, *rest) + constructor( + fieldName: String, + second: String, + vararg rest: Expr + ) : this(Field.of(fieldName), second, *rest) } class MapGet(map: Expr, key: Expr) : Function("map_get", map, key) { From fc8b2d10d0ca2152abca91e859be5a4c157ce06e Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 14 Feb 2025 21:09:58 -0500 Subject: [PATCH 14/77] docStubs fix --- .../google/firebase/firestore/DocumentReference.java | 11 +++++++++++ .../google/firebase/firestore/FirebaseFirestore.java | 4 +--- .../com/google/firebase/firestore/model/Values.kt | 12 +----------- .../google/firebase/firestore/pipeline/expression.kt | 4 ++-- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentReference.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentReference.java index 0161432843f..f31e3103060 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentReference.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/DocumentReference.java @@ -22,6 +22,7 @@ import android.app.Activity; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; import com.google.android.gms.tasks.Tasks; @@ -33,6 +34,7 @@ import com.google.firebase.firestore.core.UserData.ParsedSetData; import com.google.firebase.firestore.core.UserData.ParsedUpdateData; import com.google.firebase.firestore.core.ViewSnapshot; +import com.google.firebase.firestore.model.DatabaseId; import com.google.firebase.firestore.model.Document; import com.google.firebase.firestore.model.DocumentKey; import com.google.firebase.firestore.model.ResourcePath; @@ -118,6 +120,15 @@ public String getPath() { return key.getPath().canonicalString(); } + @RestrictTo(RestrictTo.Scope.LIBRARY) + @NonNull + public String getFullPath() { + DatabaseId databaseId = firestore.getDatabaseId(); + return String.format( + "projects/%s/databases/%s/documents/%s", + databaseId.getProjectId(), databaseId.getDatabaseId(), getPath()); + } + /** * Gets a {@code CollectionReference} instance that refers to the subcollection at the specified * path relative to this document. diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java index 557471c9b3d..114fc18da95 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java @@ -23,7 +23,6 @@ import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RestrictTo; import androidx.annotation.VisibleForTesting; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; @@ -851,9 +850,8 @@ T callClient(Function call) { return clientProvider.call(call); } - @RestrictTo(RestrictTo.Scope.LIBRARY) @NonNull - public DatabaseId getDatabaseId() { + DatabaseId getDatabaseId() { return databaseId; } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt index 6504208f082..603c8004422 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt @@ -637,17 +637,7 @@ internal object Values { @JvmStatic fun encodeValue(docRef: DocumentReference): Value { - val databaseId = docRef.firestore.databaseId - return Value.newBuilder() - .setReferenceValue( - String.format( - "projects/%s/databases/%s/documents/%s", - databaseId.projectId, - databaseId.databaseId, - docRef.path - ) - ) - .build() + return Value.newBuilder().setReferenceValue(docRef.fullPath).build() } @JvmStatic diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt index f0e473dabfc..e727576dbf2 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt @@ -238,12 +238,12 @@ abstract class Expr protected constructor() { abstract class Selectable(internal val alias: String) : Expr() -open class ExprWithAlias internal constructor(alias: String, internal val expr: Expr) : +open class ExprWithAlias internal constructor(alias: String, private val expr: Expr) : Selectable(alias) { override fun toProto(): Value = expr.toProto() } -class Field private constructor(val fieldPath: ModelFieldPath) : +class Field private constructor(private val fieldPath: ModelFieldPath) : Selectable(fieldPath.canonicalString()) { companion object { From 1e7e72e5644022358ffe973dd2813741c2f1d462 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 17 Feb 2025 15:29:53 -0500 Subject: [PATCH 15/77] fix --- .../java/com/google/firebase/firestore/UserDataReader.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java index 8079a30cf57..b1462ed9f74 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java @@ -385,7 +385,9 @@ private void parseSentinelFieldValue( * not be included in the resulting parsed data. */ public Value parseScalarValue(Object input, ParseContext context) { - if (input.getClass().isArray()) { + if (input == null) { + return Values.NULL_VALUE; + } else if (input.getClass().isArray()) { throw context.createError("Arrays are not supported; use a List instead"); } else { try { From 35bcff7dd2c8a6063ad79769fbba0579b55adc4b Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 17 Feb 2025 16:16:37 -0500 Subject: [PATCH 16/77] fix --- .../main/java/com/google/firebase/firestore/model/Values.kt | 1 + .../com/google/firebase/firestore/TestAccessHelper.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt index 603c8004422..3b9701bc4ec 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt @@ -677,6 +677,7 @@ internal object Values { is GeoPoint -> encodeValue(value) is Blob -> encodeValue(value) is DocumentReference -> encodeValue(value) + is VectorValue -> encodeValue(value) else -> throw IllegalArgumentException("Unexpected type: $value") } } diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/TestAccessHelper.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/TestAccessHelper.java index 2ace80dacef..b62ec1b9933 100644 --- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/TestAccessHelper.java +++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/TestAccessHelper.java @@ -15,7 +15,9 @@ package com.google.firebase.firestore; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import com.google.firebase.firestore.model.DatabaseId; import com.google.firebase.firestore.model.DocumentKey; public final class TestAccessHelper { @@ -23,7 +25,9 @@ public final class TestAccessHelper { /** Makes the DocumentReference constructor accessible. */ public static DocumentReference createDocumentReference(DocumentKey documentKey) { // We can use mock here because the tests only use this as a wrapper for documentKeys. - return new DocumentReference(documentKey, mock(FirebaseFirestore.class)); + FirebaseFirestore mock = mock(FirebaseFirestore.class); + when(mock.getDatabaseId()).thenReturn(DatabaseId.forProject("project")); + return new DocumentReference(documentKey, mock); } /** Makes the getKey() method accessible. */ From 3cb1886ab8fc56cee11cbc737aaf72dc72e45b74 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 18 Feb 2025 11:54:49 -0500 Subject: [PATCH 17/77] More tests --- .../firebase/firestore/PipelineTest.java | 286 ++++++++++-- .../firebase/firestore/pipeline/expression.kt | 407 ++++++++++++++++-- 2 files changed, 612 insertions(+), 81 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 128ae39da02..04e71d64068 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -15,12 +15,21 @@ package com.google.firebase.firestore; import static com.google.common.truth.Truth.assertThat; +import static com.google.firebase.firestore.pipeline.Function.add; import static com.google.firebase.firestore.pipeline.Function.and; import static com.google.firebase.firestore.pipeline.Function.arrayContains; import static com.google.firebase.firestore.pipeline.Function.arrayContainsAny; +import static com.google.firebase.firestore.pipeline.Function.endsWith; import static com.google.firebase.firestore.pipeline.Function.eq; import static com.google.firebase.firestore.pipeline.Function.gt; +import static com.google.firebase.firestore.pipeline.Function.lt; +import static com.google.firebase.firestore.pipeline.Function.lte; +import static com.google.firebase.firestore.pipeline.Function.neq; +import static com.google.firebase.firestore.pipeline.Function.not; import static com.google.firebase.firestore.pipeline.Function.or; +import static com.google.firebase.firestore.pipeline.Function.startsWith; +import static com.google.firebase.firestore.pipeline.Function.strConcat; +import static com.google.firebase.firestore.pipeline.Function.subtract; import static com.google.firebase.firestore.pipeline.Ordering.ascending; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.waitFor; import static java.util.Map.entry; @@ -56,6 +65,9 @@ public class PipelineTest { if (x instanceof Long && y instanceof Integer) { return (long) x == (long) (int) y; } + if (x instanceof Double && y instanceof Integer) { + return (double) x == (double) (int) y; + } return Objects.equals(x, y); }, "MapValueCompare")) @@ -189,15 +201,13 @@ public void setup() { public void emptyResults() { Task execute = firestore.pipeline().collection(randomCol.getPath()).limit(0).execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()).isEmpty(); + assertThat(waitFor(execute).getResults()).isEmpty(); } @Test public void fullResults() { Task execute = firestore.pipeline().collection(randomCol.getPath()).execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()).hasSize(10); + assertThat(waitFor(execute).getResults()).hasSize(10); } @Test @@ -208,8 +218,7 @@ public void aggregateResultsCountAll() { .collection(randomCol) .aggregate(Accumulator.countAll().as("count")) .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly(ImmutableMap.of("count", 10)); } @@ -227,8 +236,7 @@ public void aggregateResultsMany() { Accumulator.avg("rating").as("avgRating"), Field.of("rating").max().as("maxRating")) .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( ImmutableMap.ofEntries( @@ -241,15 +249,14 @@ public void groupAndAccumulateResults() { firestore .pipeline() .collection(randomCol) - .where(Function.lt(Field.of("published"), 1984)) + .where(lt(Field.of("published"), 1984)) .aggregate( AggregateStage.withAccumulators(Accumulator.avg("rating").as("avgRating")) .withGroups("genre")) - .where(Function.gt("avgRating", 4.3)) + .where(gt("avgRating", 4.3)) .sort(Field.of("avgRating").descending()) .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( ImmutableMap.ofEntries(entry("avgRating", 4.7), entry("genre", "Fantasy")), @@ -269,8 +276,7 @@ public void minAndMaxAccumulations() { Field.of("rating").max().as("maxRating"), Field.of("published").min().as("minPublished")) .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( ImmutableMap.ofEntries( @@ -286,8 +292,7 @@ public void canSelectFields() { .select("title", "author") .sort(Field.of("author").ascending()) .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( ImmutableMap.ofEntries( @@ -321,8 +326,7 @@ public void whereWithAnd() { .collection(randomCol) .where(and(gt("rating", 4.5), eq("genre", "Science Fiction"))) .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(ID_CORRESPONDENCE) .containsExactly("book10"); } @@ -336,8 +340,7 @@ public void whereWithOr() { .where(or(eq("genre", "Romance"), eq("genre", "Dystopian"))) .select("title") .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( ImmutableMap.of("title", "Pride and Prejudice"), @@ -356,8 +359,7 @@ public void offsetAndLimits() { .limit(3) .select("title", "author") .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( ImmutableMap.ofEntries(entry("title", "1984"), entry("author", "George Orwell")), @@ -376,8 +378,7 @@ public void arrayContainsWorks() { .where(arrayContains("tags", "comedy")) .select("title") .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly(ImmutableMap.of("title", "The Hitchhiker's Guide to the Galaxy")); } @@ -391,8 +392,7 @@ public void arrayContainsAnyWorks() { .where(arrayContainsAny("tags", ImmutableList.of("comedy", "classic"))) .select("title") .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( ImmutableMap.of("title", "The Hitchhiker's Guide to the Galaxy"), @@ -408,8 +408,7 @@ public void arrayContainsAllWorks() { .where(Field.of("tags").arrayContainsAll(ImmutableList.of("adventure", "magic"))) .select("title") .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly(ImmutableMap.of("title", "The Lord of the Rings")); } @@ -422,8 +421,7 @@ public void arrayLengthWorks() { .select(Field.of("tags").arrayLength().as("tagsCount")) .where(eq("tagsCount", 3)) .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()).hasSize(10); + assertThat(waitFor(execute).getResults()).hasSize(10); } @Test @@ -440,8 +438,7 @@ public void arrayConcatWorks() { .as("modifiedTags")) .limit(1) .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( ImmutableMap.of( @@ -457,10 +454,231 @@ public void testStrConcat() { .select(Field.of("author").strConcat(" - ", Field.of("title")).as("bookInfo")) .limit(1) .execute(); - PipelineSnapshot snapshot = waitFor(execute); - assertThat(snapshot.getResults()) + assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( ImmutableMap.of("bookInfo", "Douglas Adams - The Hitchhiker's Guide to the Galaxy")); } + + @Test + public void testStartsWith() { + Task execute = + randomCol + .pipeline() + .where(startsWith("title", "The")) + .select("title") + .sort(Field.of("title").ascending()) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("title", "The Great Gatsby"), + ImmutableMap.of("title", "The Handmaid's Tale"), + ImmutableMap.of("title", "The Hitchhiker's Guide to the Galaxy"), + ImmutableMap.of("title", "The Lord of the Rings")); + } + + @Test + public void testEndsWith() { + Task execute = + randomCol + .pipeline() + .where(endsWith("title", "y")) + .select("title") + .sort(Field.of("title").descending()) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("title", "The Hitchhiker's Guide to the Galaxy"), + ImmutableMap.of("title", "The Great Gatsby")); + } + + @Test + public void testLength() { + Task execute = + randomCol + .pipeline() + .select(Field.of("title").charLength().as("titleLength"), Field.of("title")) + .where(gt("titleLength", 20)) + .sort(Field.of("title").ascending()) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("titleLength", 29, "title", "One Hundred Years of Solitude"), + ImmutableMap.of("titleLength", 36, "title", "The Hitchhiker's Guide to the Galaxy"), + ImmutableMap.of("titleLength", 21, "title", "The Lord of the Rings"), + ImmutableMap.of("titleLength", 21, "title", "To Kill a Mockingbird")); + } + + @Test + @Ignore("Not supported yet") + public void testToLowercase() { + Task execute = + randomCol + .pipeline() + .select(Field.of("title").toLower().as("lowercaseTitle")) + .limit(1) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("lowercaseTitle", "the hitchhiker's guide to the galaxy")); + } + + @Test + @Ignore("Not supported yet") + public void testToUppercase() { + Task execute = + randomCol + .pipeline() + .select(Field.of("author").toLower().as("uppercaseAuthor")) + .limit(1) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("uppercaseAuthor", "DOUGLAS ADAMS")); + } + + @Test + @Ignore("Not supported yet") + public void testTrim() { + Task execute = + randomCol + .pipeline() + .addFields(strConcat(" ", Field.of("title"), " ").as("spacedTitle")) + .select(Field.of("spacedTitle").trim().as("trimmedTitle")) + .limit(1) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of( + "spacedTitle", + " The Hitchhiker's Guide to the Galaxy ", + "trimmedTitle", + "The Hitchhiker's Guide to the Galaxy")); + } + + @Test + public void testLike() { + Task execute = + randomCol.pipeline().where(Function.like("title", "%Guide%")).select("title").execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("title", "The Hitchhiker's Guide to the Galaxy")); + } + + @Test + public void testRegexContains() { + Task execute = + randomCol.pipeline().where(Function.regexContains("title", "(?i)(the|of)")).execute(); + assertThat(waitFor(execute).getResults()).hasSize(5); + } + + @Test + public void testRegexMatches() { + Task execute = + randomCol.pipeline().where(Function.regexContains("title", ".*(?i)(the|of).*")).execute(); + assertThat(waitFor(execute).getResults()).hasSize(5); + } + + @Test + public void testArithmeticOperations() { + Task execute = + randomCol + .pipeline() + .select( + add(Field.of("rating"), 1).as("ratingPlusOne"), + subtract(Field.of("published"), 1900).as("yearsSince1900"), + Field.of("rating").multiply(10).as("ratingTimesTen"), + Field.of("rating").divide(2).as("ratingDividedByTwo")) + .limit(1) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.ofEntries( + entry("ratingPlusOne", 5.2), + entry("yearsSince1900", 79), + entry("ratingTimesTen", 42), + entry("ratingDividedByTwo", 2.1))); + } + + @Test + public void testComparisonOperators() { + Task execute = + randomCol + .pipeline() + .where( + and( + gt("rating", 4.2), + lte(Field.of("rating"), 4.5), + neq("genre", "Science Function"))) + .select("rating", "title") + .sort(Field.of("title").ascending()) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("rating", 4.3, "title", "Crime and Punishment"), + ImmutableMap.of("rating", 4.3, "title", "One Hundred Years of Solitude"), + ImmutableMap.of("rating", 4.5, "title", "Pride and Prejudice")); + } + + @Test + public void testLogicalOperators() { + Task execute = + randomCol + .pipeline() + .where( + or( + and(gt("rating", 4.5), eq("genre", "Science Fiction")), + lt(Field.of("published"), 1900))) + .select("title") + .sort(Field.of("title").ascending()) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("title", "Crime and Punishment"), + ImmutableMap.of("title", "Dune"), + ImmutableMap.of("title", "Pride and Prejudice")); + } + + @Test + public void testChecks() { + Task execute = + randomCol + .pipeline() + .where(not(Field.of("rating").isNan())) + .select(Field.of("rating").eq(null).as("ratingIsNull")) + .select("title") + .sort(Field.of("title").ascending()) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("title", "Crime and Punishment"), + ImmutableMap.of("title", "Dune"), + ImmutableMap.of("title", "Pride and Prejudice")); + } + + @Test + public void testMapGet() {} + + @Test + public void testParent() {} + + @Test + public void testCollectionId() {} + + @Test + public void testDistanceFunctions() {} + + @Test + public void testNestedFields() {} + + @Test + public void testMapGetWithFieldNameIncludingNotation() {} } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt index e727576dbf2..fa6bdda4b97 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt @@ -25,7 +25,10 @@ import com.google.firestore.v1.Value abstract class Expr protected constructor() { internal companion object { - internal fun toExprOrConstant(other: Any): Expr { + internal fun toExprOrConstant(other: Any?): Expr { + if (other == null) { + return Constant.nullValue() + } return when (other) { is Expr -> other else -> Constant.of(other) @@ -131,11 +134,11 @@ abstract class Expr protected constructor() { fun logicalMax(other: Expr) = LogicalMax(this, other) - fun logicalMax(other: Any) = LogicalMax(this, other) + fun logicalMax(other: Any?) = LogicalMax(this, other) fun logicalMin(other: Expr) = LogicalMin(this, other) - fun logicalMin(other: Any) = LogicalMin(this, other) + fun logicalMin(other: Any?) = LogicalMin(this, other) fun reverse() = Reverse(this) @@ -159,7 +162,9 @@ abstract class Expr protected constructor() { fun strConcat(vararg expr: Expr) = StrConcat(this, *expr) - fun strConcat(string: String, vararg expr: Expr) = StrConcat(this, string, *expr) + fun strConcat(vararg string: String) = StrConcat(this, *string) + + fun strConcat(vararg string: Any) = StrConcat(this, *string) fun mapGet(key: Expr) = MapGet(this, key) @@ -213,7 +218,7 @@ abstract class Expr protected constructor() { fun arrayContains(value: Expr) = ArrayContains(this, value) - fun arrayContains(value: Any) = ArrayContains(this, value) + fun arrayContains(value: Any?) = ArrayContains(this, value) fun arrayContainsAll(values: List) = ArrayContainsAll(this, values) @@ -233,6 +238,30 @@ abstract class Expr protected constructor() { fun descending() = Ordering.descending(this) + fun eq(other: Expr) = Eq(this, other) + + fun eq(other: Any?) = Eq(this, other) + + fun neq(other: Expr) = Neq(this, other) + + fun neq(other: Any?) = Neq(this, other) + + fun gt(other: Expr) = Gt(this, other) + + fun gt(other: Any?) = Gt(this, other) + + fun gte(other: Expr) = Gte(this, other) + + fun gte(other: Any?) = Gte(this, other) + + fun lt(other: Expr) = Lt(this, other) + + fun lt(other: Any?) = Lt(this, other) + + fun lte(other: Expr) = Lte(this, other) + + fun lte(other: Any?) = Lte(this, other) + internal abstract fun toProto(): Value } @@ -291,53 +320,343 @@ protected constructor(private val name: String, private val params: Array) = In(array, values) + + @JvmStatic fun `in`(fieldName: String, values: List) = In(fieldName, values) + + @JvmStatic fun isNan(expr: Expr) = IsNan(expr) + + @JvmStatic fun isNan(fieldName: String) = IsNan(fieldName) + + @JvmStatic + fun replaceFirst(value: Expr, find: Expr, replace: Expr) = ReplaceFirst(value, find, replace) + + @JvmStatic + fun replaceFirst(value: Expr, find: String, replace: String) = + ReplaceFirst(value, find, replace) + + @JvmStatic + fun replaceFirst(fieldName: String, find: String, replace: String) = + ReplaceFirst(fieldName, find, replace) + + @JvmStatic + fun replaceAll(value: Expr, find: Expr, replace: Expr) = ReplaceAll(value, find, replace) + + @JvmStatic + fun replaceAll(value: Expr, find: String, replace: String) = ReplaceAll(value, find, replace) + + @JvmStatic + fun replaceAll(fieldName: String, find: String, replace: String) = + ReplaceAll(fieldName, find, replace) + + @JvmStatic fun charLength(value: Expr) = CharLength(value) + + @JvmStatic fun charLength(fieldName: String) = CharLength(fieldName) + + @JvmStatic fun byteLength(value: Expr) = ByteLength(value) + + @JvmStatic fun byteLength(fieldName: String) = ByteLength(fieldName) + + @JvmStatic fun like(expr: Expr, pattern: Expr) = Like(expr, pattern) + + @JvmStatic fun like(fieldName: String, pattern: String) = Like(fieldName, pattern) + + @JvmStatic fun regexContains(expr: Expr, pattern: Expr) = RegexContains(expr, pattern) + + @JvmStatic fun regexContains(expr: Expr, pattern: String) = RegexContains(expr, pattern) + + @JvmStatic + fun regexContains(fieldName: String, pattern: Expr) = RegexContains(fieldName, pattern) + + @JvmStatic + fun regexContains(fieldName: String, pattern: String) = RegexContains(fieldName, pattern) + + @JvmStatic fun regexMatch(expr: Expr, pattern: Expr) = RegexMatch(expr, pattern) + + @JvmStatic fun regexMatch(expr: Expr, pattern: String) = RegexMatch(expr, pattern) + + @JvmStatic fun regexMatch(fieldName: String, pattern: Expr) = RegexMatch(fieldName, pattern) + + @JvmStatic fun regexMatch(fieldName: String, pattern: String) = RegexMatch(fieldName, pattern) + + @JvmStatic fun logicalMax(left: Expr, right: Expr) = LogicalMax(left, right) + + @JvmStatic fun logicalMax(left: Expr, right: Any?) = LogicalMax(left, right) + + @JvmStatic fun logicalMax(fieldName: String, other: Expr) = LogicalMax(fieldName, other) + + @JvmStatic fun logicalMax(fieldName: String, other: Any?) = LogicalMax(fieldName, other) + + @JvmStatic fun logicalMin(left: Expr, right: Expr) = LogicalMin(left, right) + + @JvmStatic fun logicalMin(left: Expr, right: Any?) = LogicalMin(left, right) + + @JvmStatic fun logicalMin(fieldName: String, other: Expr) = LogicalMin(fieldName, other) + + @JvmStatic fun logicalMin(fieldName: String, other: Any?) = LogicalMin(fieldName, other) + + @JvmStatic fun reverse(expr: Expr) = Reverse(expr) + + @JvmStatic fun reverse(fieldName: String) = Reverse(fieldName) + + @JvmStatic fun strContains(expr: Expr, substring: Expr) = StrContains(expr, substring) + + @JvmStatic fun strContains(expr: Expr, substring: String) = StrContains(expr, substring) + + @JvmStatic + fun strContains(fieldName: String, substring: Expr) = StrContains(fieldName, substring) + + @JvmStatic + fun strContains(fieldName: String, substring: String) = StrContains(fieldName, substring) + + @JvmStatic fun startsWith(expr: Expr, prefix: Expr) = StartsWith(expr, prefix) + + @JvmStatic fun startsWith(expr: Expr, prefix: String) = StartsWith(expr, prefix) + + @JvmStatic fun startsWith(fieldName: String, prefix: Expr) = StartsWith(fieldName, prefix) + + @JvmStatic fun startsWith(fieldName: String, prefix: String) = StartsWith(fieldName, prefix) + + @JvmStatic fun endsWith(expr: Expr, suffix: Expr) = EndsWith(expr, suffix) + + @JvmStatic fun endsWith(expr: Expr, suffix: String) = EndsWith(expr, suffix) + + @JvmStatic fun endsWith(fieldName: String, suffix: Expr) = EndsWith(fieldName, suffix) + + @JvmStatic fun endsWith(fieldName: String, suffix: String) = EndsWith(fieldName, suffix) + + @JvmStatic fun toLower(expr: Expr) = ToLower(expr) + + @JvmStatic + fun toLower( + fieldName: String, + ) = ToLower(fieldName) + + @JvmStatic fun toUpper(expr: Expr) = ToUpper(expr) + + @JvmStatic + fun toUpper( + fieldName: String, + ) = ToUpper(fieldName) + + @JvmStatic fun trim(expr: Expr) = Trim(expr) + + @JvmStatic fun trim(fieldName: String) = Trim(fieldName) + + @JvmStatic fun strConcat(first: Expr, vararg rest: Expr) = StrConcat(first, *rest) + + @JvmStatic fun strConcat(first: Expr, vararg rest: Any) = StrConcat(first, *rest) + + @JvmStatic fun strConcat(fieldName: String, vararg rest: Expr) = StrConcat(fieldName, *rest) + + @JvmStatic fun strConcat(fieldName: String, vararg rest: Any) = StrConcat(fieldName, *rest) + + @JvmStatic fun mapGet(map: Expr, key: Expr) = MapGet(map, key) + + @JvmStatic fun mapGet(map: Expr, key: String) = MapGet(map, key) + + @JvmStatic fun mapGet(fieldName: String, key: Expr) = MapGet(fieldName, key) + + @JvmStatic fun mapGet(fieldName: String, key: String) = MapGet(fieldName, key) + + @JvmStatic fun cosineDistance(vector1: Expr, vector2: Expr) = CosineDistance(vector1, vector2) + + @JvmStatic + fun cosineDistance(vector1: Expr, vector2: DoubleArray) = CosineDistance(vector1, vector2) + + @JvmStatic + fun cosineDistance(vector1: Expr, vector2: VectorValue) = CosineDistance(vector1, vector2) + + @JvmStatic + fun cosineDistance(fieldName: String, vector: Expr) = CosineDistance(fieldName, vector) + + @JvmStatic + fun cosineDistance(fieldName: String, vector: DoubleArray) = CosineDistance(fieldName, vector) + + @JvmStatic + fun cosineDistance(fieldName: String, vector: VectorValue) = CosineDistance(fieldName, vector) + + @JvmStatic fun dotProduct(vector1: Expr, vector2: Expr) = DotProduct(vector1, vector2) + + @JvmStatic fun dotProduct(vector1: Expr, vector2: DoubleArray) = DotProduct(vector1, vector2) + + @JvmStatic fun dotProduct(vector1: Expr, vector2: VectorValue) = DotProduct(vector1, vector2) + + @JvmStatic fun dotProduct(fieldName: String, vector: Expr) = DotProduct(fieldName, vector) + + @JvmStatic + fun dotProduct(fieldName: String, vector: DoubleArray) = DotProduct(fieldName, vector) + + @JvmStatic + fun dotProduct(fieldName: String, vector: VectorValue) = DotProduct(fieldName, vector) + + @JvmStatic + fun euclideanDistance(vector1: Expr, vector2: Expr) = EuclideanDistance(vector1, vector2) + + @JvmStatic + fun euclideanDistance(vector1: Expr, vector2: DoubleArray) = EuclideanDistance(vector1, vector2) + + @JvmStatic + fun euclideanDistance(vector1: Expr, vector2: VectorValue) = EuclideanDistance(vector1, vector2) + + @JvmStatic + fun euclideanDistance(fieldName: String, vector: Expr) = EuclideanDistance(fieldName, vector) + + @JvmStatic + fun euclideanDistance(fieldName: String, vector: DoubleArray) = + EuclideanDistance(fieldName, vector) + + @JvmStatic + fun euclideanDistance(fieldName: String, vector: VectorValue) = + EuclideanDistance(fieldName, vector) + + @JvmStatic fun vectorLength(vector: Expr) = VectorLength(vector) + + @JvmStatic fun vectorLength(fieldName: String) = VectorLength(fieldName) + + @JvmStatic fun unixMicrosToTimestamp(input: Expr) = UnixMicrosToTimestamp(input) + + @JvmStatic fun unixMicrosToTimestamp(fieldName: String) = UnixMicrosToTimestamp(fieldName) + + @JvmStatic fun timestampToUnixMicros(input: Expr) = TimestampToUnixMicros(input) + + @JvmStatic fun timestampToUnixMicros(fieldName: String) = TimestampToUnixMicros(fieldName) + + @JvmStatic fun unixMillisToTimestamp(input: Expr) = UnixMillisToTimestamp(input) + + @JvmStatic fun unixMillisToTimestamp(fieldName: String) = UnixMillisToTimestamp(fieldName) + + @JvmStatic fun timestampToUnixMillis(input: Expr) = TimestampToUnixMillis(input) + + @JvmStatic fun timestampToUnixMillis(fieldName: String) = TimestampToUnixMillis(fieldName) + + @JvmStatic fun unixSecondsToTimestamp(input: Expr) = UnixSecondsToTimestamp(input) + + @JvmStatic fun unixSecondsToTimestamp(fieldName: String) = UnixSecondsToTimestamp(fieldName) + + @JvmStatic fun timestampToUnixSeconds(input: Expr) = TimestampToUnixSeconds(input) + + @JvmStatic fun timestampToUnixSeconds(fieldName: String) = TimestampToUnixSeconds(fieldName) + + @JvmStatic + fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr) = + TimestampAdd(timestamp, unit, amount) + + @JvmStatic + fun timestampAdd(timestamp: Expr, unit: String, amount: Double) = + TimestampAdd(timestamp, unit, amount) + + @JvmStatic + fun timestampAdd(fieldName: String, unit: Expr, amount: Expr) = + TimestampAdd(fieldName, unit, amount) + + @JvmStatic + fun timestampAdd(fieldName: String, unit: String, amount: Double) = + TimestampAdd(fieldName, unit, amount) + + @JvmStatic + fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr) = + TimestampSub(timestamp, unit, amount) + + @JvmStatic + fun timestampSub(timestamp: Expr, unit: String, amount: Double) = + TimestampSub(timestamp, unit, amount) + + @JvmStatic + fun timestampSub(fieldName: String, unit: Expr, amount: Expr) = + TimestampSub(fieldName, unit, amount) + + @JvmStatic + fun timestampSub(fieldName: String, unit: String, amount: Double) = + TimestampSub(fieldName, unit, amount) + @JvmStatic fun eq(left: Expr, right: Expr) = Eq(left, right) - @JvmStatic fun eq(left: Expr, right: Any) = Eq(left, right) + @JvmStatic fun eq(left: Expr, right: Any?) = Eq(left, right) @JvmStatic fun eq(fieldName: String, right: Expr) = Eq(fieldName, right) - @JvmStatic fun eq(fieldName: String, right: Any) = Eq(fieldName, right) + @JvmStatic fun eq(fieldName: String, right: Any?) = Eq(fieldName, right) @JvmStatic fun neq(left: Expr, right: Expr) = Neq(left, right) - @JvmStatic fun neq(left: Expr, right: Any) = Neq(left, right) + @JvmStatic fun neq(left: Expr, right: Any?) = Neq(left, right) @JvmStatic fun neq(fieldName: String, right: Expr) = Neq(fieldName, right) - @JvmStatic fun neq(fieldName: String, right: Any) = Neq(fieldName, right) + @JvmStatic fun neq(fieldName: String, right: Any?) = Neq(fieldName, right) @JvmStatic fun gt(left: Expr, right: Expr) = Gt(left, right) - @JvmStatic fun gt(left: Expr, right: Any) = Gt(left, right) + @JvmStatic fun gt(left: Expr, right: Any?) = Gt(left, right) @JvmStatic fun gt(fieldName: String, right: Expr) = Gt(fieldName, right) - @JvmStatic fun gt(fieldName: String, right: Any) = Gt(fieldName, right) + @JvmStatic fun gt(fieldName: String, right: Any?) = Gt(fieldName, right) @JvmStatic fun gte(left: Expr, right: Expr) = Gte(left, right) - @JvmStatic fun gte(left: Expr, right: Any) = Gte(left, right) + @JvmStatic fun gte(left: Expr, right: Any?) = Gte(left, right) @JvmStatic fun gte(fieldName: String, right: Expr) = Gte(fieldName, right) - @JvmStatic fun gte(fieldName: String, right: Any) = Gte(fieldName, right) + @JvmStatic fun gte(fieldName: String, right: Any?) = Gte(fieldName, right) @JvmStatic fun lt(left: Expr, right: Expr) = Lt(left, right) - @JvmStatic fun lt(left: Expr, right: Any) = Lt(left, right) + @JvmStatic fun lt(left: Expr, right: Any?) = Lt(left, right) @JvmStatic fun lt(fieldName: String, right: Expr) = Lt(fieldName, right) - @JvmStatic fun lt(fieldName: String, right: Any) = Lt(fieldName, right) + @JvmStatic fun lt(fieldName: String, right: Any?) = Lt(fieldName, right) @JvmStatic fun lte(left: Expr, right: Expr) = Lte(left, right) - @JvmStatic fun lte(left: Expr, right: Any) = Lte(left, right) + @JvmStatic fun lte(left: Expr, right: Any?) = Lte(left, right) @JvmStatic fun lte(fieldName: String, right: Expr) = Lte(fieldName, right) - @JvmStatic fun lte(fieldName: String, right: Any) = Lte(fieldName, right) + @JvmStatic fun lte(fieldName: String, right: Any?) = Lte(fieldName, right) @JvmStatic fun arrayConcat(array: Expr, vararg arrays: Expr) = ArrayConcat(array, *arrays) @@ -357,9 +676,9 @@ protected constructor(private val name: String, private val params: Array) = ArrayContainsAll(array, values) @@ -508,39 +827,39 @@ class Mod(left: Expr, right: Expr) : Function("mod", left, right) { // } class Eq(left: Expr, right: Expr) : BooleanExpr("eq", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) } class Neq(left: Expr, right: Expr) : BooleanExpr("neq", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) } class Lt(left: Expr, right: Expr) : BooleanExpr("lt", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) } class Lte(left: Expr, right: Expr) : BooleanExpr("lte", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) } class Gt(left: Expr, right: Expr) : BooleanExpr("gt", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) } class Gte(left: Expr, right: Expr) : BooleanExpr("gte", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) } class ArrayConcat(array: Expr, vararg arrays: Expr) : @@ -558,9 +877,9 @@ class ArrayReverse(array: Expr) : Function("array_reverse", array) { } class ArrayContains(array: Expr, value: Expr) : BooleanExpr("array_contains", array, value) { - constructor(array: Expr, right: Any) : this(array, toExprOrConstant(right)) + constructor(array: Expr, right: Any?) : this(array, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) } class ArrayContainsAll(array: Expr, values: List) : @@ -605,15 +924,15 @@ class If(condition: BooleanExpr, thenExpr: Expr, elseExpr: Expr) : Function("if", condition, thenExpr, elseExpr) class LogicalMax(left: Expr, right: Expr) : Function("logical_max", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) } class LogicalMin(left: Expr, right: Expr) : Function("logical_min", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) + constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) + constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) } class Reverse(expr: Expr) : Function("reverse", expr) { @@ -706,17 +1025,11 @@ class Trim(expr: Expr) : Function("trim", expr) { class StrConcat internal constructor(first: Expr, vararg rest: Expr) : Function("str_concat", arrayOf(first, *rest)) { - constructor( - first: Expr, - second: String, - vararg rest: Expr - ) : this(first, Constant.of(second), *rest) + constructor(first: Expr, vararg rest: String) : this(first, *toArrayOfExprOrConstant(rest)) + constructor(first: Expr, vararg rest: Any) : this(first, *toArrayOfExprOrConstant(rest)) constructor(fieldName: String, vararg rest: Expr) : this(Field.of(fieldName), *rest) - constructor( - fieldName: String, - second: String, - vararg rest: Expr - ) : this(Field.of(fieldName), second, *rest) + constructor(fieldName: String, vararg rest: Any) : this(Field.of(fieldName), *rest) + constructor(fieldName: String, vararg rest: String) : this(Field.of(fieldName), *rest) } class MapGet(map: Expr, key: Expr) : Function("map_get", map, key) { From 5abf13ff9781ee657433f2953570c3adfca6fce1 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Wed, 19 Feb 2025 13:29:57 -0500 Subject: [PATCH 18/77] Refactor and more tests. --- .../firebase/firestore/PipelineTest.java | 207 +++- .../com/google/firebase/firestore/Pipeline.kt | 2 +- .../firebase/firestore/pipeline/Constant.kt | 5 +- .../firestore/pipeline/accumulators.kt | 64 +- .../firebase/firestore/pipeline/expression.kt | 895 ++++++------------ 5 files changed, 486 insertions(+), 687 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 04e71d64068..94842ba009d 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -19,9 +19,13 @@ import static com.google.firebase.firestore.pipeline.Function.and; import static com.google.firebase.firestore.pipeline.Function.arrayContains; import static com.google.firebase.firestore.pipeline.Function.arrayContainsAny; +import static com.google.firebase.firestore.pipeline.Function.cosineDistance; import static com.google.firebase.firestore.pipeline.Function.endsWith; import static com.google.firebase.firestore.pipeline.Function.eq; +import static com.google.firebase.firestore.pipeline.Function.euclideanDistance; import static com.google.firebase.firestore.pipeline.Function.gt; +import static com.google.firebase.firestore.pipeline.Function.logicalMax; +import static com.google.firebase.firestore.pipeline.Function.logicalMin; import static com.google.firebase.firestore.pipeline.Function.lt; import static com.google.firebase.firestore.pipeline.Function.lte; import static com.google.firebase.firestore.pipeline.Function.neq; @@ -41,9 +45,12 @@ import com.google.common.truth.Correspondence; import com.google.firebase.firestore.pipeline.Accumulator; import com.google.firebase.firestore.pipeline.AggregateStage; +import com.google.firebase.firestore.pipeline.Constant; import com.google.firebase.firestore.pipeline.Field; import com.google.firebase.firestore.pipeline.Function; import com.google.firebase.firestore.testutil.IntegrationTestUtil; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; import org.junit.After; @@ -87,11 +94,11 @@ public void tearDown() { IntegrationTestUtil.tearDown(); } - private Map> bookDocs = - ImmutableMap.ofEntries( + private final Map> bookDocs = + mapOfEntries( entry( "book1", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "The Hitchhiker's Guide to the Galaxy"), entry("author", "Douglas Adams"), entry("genre", "Science Fiction"), @@ -101,7 +108,7 @@ public void tearDown() { entry("awards", ImmutableMap.of("hugo", true, "nebula", false)))), entry( "book2", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "Pride and Prejudice"), entry("author", "Jane Austen"), entry("genre", "Romance"), @@ -111,7 +118,7 @@ public void tearDown() { entry("awards", ImmutableMap.of("none", true)))), entry( "book3", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "One Hundred Years of Solitude"), entry("author", "Gabriel García Márquez"), entry("genre", "Magical Realism"), @@ -121,7 +128,7 @@ public void tearDown() { entry("awards", ImmutableMap.of("nobel", true, "nebula", false)))), entry( "book4", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "The Lord of the Rings"), entry("author", "J.R.R. Tolkien"), entry("genre", "Fantasy"), @@ -131,7 +138,7 @@ public void tearDown() { entry("awards", ImmutableMap.of("hugo", false, "nebula", false)))), entry( "book5", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "The Handmaid's Tale"), entry("author", "Margaret Atwood"), entry("genre", "Dystopian"), @@ -142,7 +149,7 @@ public void tearDown() { "awards", ImmutableMap.of("arthur c. clarke", true, "booker prize", false)))), entry( "book6", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "Crime and Punishment"), entry("author", "Fyodor Dostoevsky"), entry("genre", "Psychological Thriller"), @@ -152,7 +159,7 @@ public void tearDown() { entry("awards", ImmutableMap.of("none", true)))), entry( "book7", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "To Kill a Mockingbird"), entry("author", "Harper Lee"), entry("genre", "Southern Gothic"), @@ -162,7 +169,7 @@ public void tearDown() { entry("awards", ImmutableMap.of("pulitzer", true)))), entry( "book8", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "1984"), entry("author", "George Orwell"), entry("genre", "Dystopian"), @@ -172,7 +179,7 @@ public void tearDown() { entry("awards", ImmutableMap.of("prometheus", true)))), entry( "book9", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "The Great Gatsby"), entry("author", "F. Scott Fitzgerald"), entry("genre", "Modernist"), @@ -182,7 +189,7 @@ public void tearDown() { entry("awards", ImmutableMap.of("none", true)))), entry( "book10", - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "Dune"), entry("author", "Frank Herbert"), entry("genre", "Science Fiction"), @@ -239,8 +246,7 @@ public void aggregateResultsMany() { assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( - ImmutableMap.ofEntries( - entry("count", 10), entry("avgRating", 4.4), entry("maxRating", 4.6))); + mapOfEntries(entry("count", 10), entry("avgRating", 4.4), entry("maxRating", 4.6))); } @Test @@ -259,9 +265,9 @@ public void groupAndAccumulateResults() { assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( - ImmutableMap.ofEntries(entry("avgRating", 4.7), entry("genre", "Fantasy")), - ImmutableMap.ofEntries(entry("avgRating", 4.5), entry("genre", "Romance")), - ImmutableMap.ofEntries(entry("avgRating", 4.4), entry("genre", "Science Fiction"))); + mapOfEntries(entry("avgRating", 4.7), entry("genre", "Fantasy")), + mapOfEntries(entry("avgRating", 4.5), entry("genre", "Romance")), + mapOfEntries(entry("avgRating", 4.4), entry("genre", "Science Fiction"))); } @Test @@ -279,8 +285,7 @@ public void minAndMaxAccumulations() { assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( - ImmutableMap.ofEntries( - entry("count", 10), entry("maxRating", 4.7), entry("minPublished", 1813))); + mapOfEntries(entry("count", 10), entry("maxRating", 4.7), entry("minPublished", 1813))); } @Test @@ -295,26 +300,23 @@ public void canSelectFields() { assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "The Hitchhiker's Guide to the Galaxy"), entry("author", "Douglas Adams")), - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "The Great Gatsby"), entry("author", "F. Scott Fitzgerald")), - ImmutableMap.ofEntries(entry("title", "Dune"), entry("author", "Frank Herbert")), - ImmutableMap.ofEntries( + mapOfEntries(entry("title", "Dune"), entry("author", "Frank Herbert")), + mapOfEntries( entry("title", "Crime and Punishment"), entry("author", "Fyodor Dostoevsky")), - ImmutableMap.ofEntries( + mapOfEntries( entry("title", "One Hundred Years of Solitude"), entry("author", "Gabriel García Márquez")), - ImmutableMap.ofEntries(entry("title", "1984"), entry("author", "George Orwell")), - ImmutableMap.ofEntries( - entry("title", "To Kill a Mockingbird"), entry("author", "Harper Lee")), - ImmutableMap.ofEntries( + mapOfEntries(entry("title", "1984"), entry("author", "George Orwell")), + mapOfEntries(entry("title", "To Kill a Mockingbird"), entry("author", "Harper Lee")), + mapOfEntries( entry("title", "The Lord of the Rings"), entry("author", "J.R.R. Tolkien")), - ImmutableMap.ofEntries( - entry("title", "Pride and Prejudice"), entry("author", "Jane Austen")), - ImmutableMap.ofEntries( - entry("title", "The Handmaid's Tale"), entry("author", "Margaret Atwood"))) + mapOfEntries(entry("title", "Pride and Prejudice"), entry("author", "Jane Austen")), + mapOfEntries(entry("title", "The Handmaid's Tale"), entry("author", "Margaret Atwood"))) .inOrder(); } @@ -362,10 +364,9 @@ public void offsetAndLimits() { assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( - ImmutableMap.ofEntries(entry("title", "1984"), entry("author", "George Orwell")), - ImmutableMap.ofEntries( - entry("title", "To Kill a Mockingbird"), entry("author", "Harper Lee")), - ImmutableMap.ofEntries( + mapOfEntries(entry("title", "1984"), entry("author", "George Orwell")), + mapOfEntries(entry("title", "To Kill a Mockingbird"), entry("author", "Harper Lee")), + mapOfEntries( entry("title", "The Lord of the Rings"), entry("author", "J.R.R. Tolkien"))); } @@ -598,7 +599,7 @@ public void testArithmeticOperations() { assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( - ImmutableMap.ofEntries( + mapOfEntries( entry("ratingPlusOne", 5.2), entry("yearsSince1900", 79), entry("ratingTimesTen", 42), @@ -652,20 +653,66 @@ public void testChecks() { randomCol .pipeline() .where(not(Field.of("rating").isNan())) - .select(Field.of("rating").eq(null).as("ratingIsNull")) - .select("title") - .sort(Field.of("title").ascending()) + .select( + Field.of("rating").isNull().as("ratingIsNull"), + Field.of("rating").eq(Constant.nullValue()).as("ratingEqNull"), + not(Field.of("rating").isNan()).as("ratingIsNotNan")) + .limit(1) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly( - ImmutableMap.of("title", "Crime and Punishment"), - ImmutableMap.of("title", "Dune"), - ImmutableMap.of("title", "Pride and Prejudice")); + mapOfEntries( + entry("ratingIsNull", false), + entry("ratingEqNull", null), + entry("ratingIsNotNan", true))); + } + + @Test + @Ignore("Not supported yet") + public void testLogicalMax() { + Task execute = + randomCol + .pipeline() + .where(Field.of("author").eq("Douglas Adams")) + .select( + Field.of("rating").logicalMax(4.5).as("max_rating"), + logicalMax(Field.of("published"), 1900).as("max_published")) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("max_rating", 4.5, "max_published", 1979)); + } + + @Test + @Ignore("Not supported yet") + public void testLogicalMin() { + Task execute = + randomCol + .pipeline() + .select( + Field.of("rating").logicalMin(4.5).as("min_rating"), + logicalMin(Field.of("published"), 1900).as("min_published")) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly(ImmutableMap.of("min_rating", 4.2, "min_published", 1900)); } @Test - public void testMapGet() {} + public void testMapGet() { + Task execute = + randomCol + .pipeline() + .select(Field.of("awards").mapGet("hugo").as("hugoAward"), Field.of("title")) + .where(eq("hugoAward", true)) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("hugoAward", true, "title", "The Hitchhiker's Guide to the Galaxy"), + ImmutableMap.of("hugoAward", true, "title", "Dune")); + } @Test public void testParent() {} @@ -674,11 +721,81 @@ public void testParent() {} public void testCollectionId() {} @Test - public void testDistanceFunctions() {} + public void testDistanceFunctions() { + double[] sourceVector = {0.1, 0.1}; + double[] targetVector = {0.5, 0.8}; + Task execute = + randomCol + .pipeline() + .select( + cosineDistance(Constant.vector(sourceVector), targetVector).as("cosineDistance"), + Function.dotProduct(Constant.vector(sourceVector), targetVector) + .as("dotProductDistance"), + euclideanDistance(Constant.vector(sourceVector), targetVector) + .as("euclideanDistance")) + .limit(1) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of( + "cosineDistance", 0.02560880430538015, + "dotProductDistance", 0.13, + "euclideanDistance", 0.806225774829855)); + } @Test public void testNestedFields() {} @Test public void testMapGetWithFieldNameIncludingNotation() {} + + static Map.Entry entry(String key, T value) { + return new Map.Entry() { + private String k = key; + private T v = value; + + @Override + public String getKey() { + return k; + } + + @Override + public T getValue() { + return v; + } + + @Override + public T setValue(T value) { + T old = v; + v = value; + return old; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) { + return false; + } + + Map.Entry that = (Map.Entry) o; + return com.google.common.base.Objects.equal(k, that.getKey()) + && com.google.common.base.Objects.equal(v, that.getValue()); + } + + @Override + public int hashCode() { + return com.google.common.base.Objects.hashCode(k, v); + } + }; + } + + @SafeVarargs + static Map mapOfEntries(Map.Entry... entries) { + Map res = new LinkedHashMap<>(); + for (Map.Entry entry : entries) { + res.put(entry.getKey(), entry.getValue()); + } + return Collections.unmodifiableMap(res); + } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 941690eb372..75825ad2cec 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -225,7 +225,7 @@ internal constructor( private val version: SnapshotVersion, ) { - fun getData(): Map { + fun getData(): Map { return userDataWriter().convertObject(fields) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt index fdcac5c59c3..bc9a39a50d4 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt @@ -27,6 +27,8 @@ import java.util.Date class Constant internal constructor(val value: Value) : Expr() { companion object { + internal val NULL = Constant(Values.NULL_VALUE) + fun of(value: Any): Constant { return when (value) { is String -> of(value) @@ -38,6 +40,7 @@ class Constant internal constructor(val value: Value) : Expr() { is Blob -> of(value) is DocumentReference -> of(value) is Value -> of(value) + is VectorValue -> of(value) else -> throw IllegalArgumentException("Unknown type: $value") } } @@ -89,7 +92,7 @@ class Constant internal constructor(val value: Value) : Expr() { @JvmStatic fun nullValue(): Constant { - return Constant(Values.NULL_VALUE) + return NULL } @JvmStatic diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt index 8098183c1c2..b89c318636a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt @@ -19,67 +19,71 @@ import com.google.firestore.v1.Value class AccumulatorWithAlias internal constructor(internal val alias: String, internal val accumulator: Accumulator) -open class Accumulator -protected constructor(private val name: String, private val params: Array) { - protected constructor( - name: String, - param: Expr? - ) : this(name, if (param == null) emptyArray() else arrayOf(param)) +class Accumulator +private constructor(private val name: String, private val params: Array) { + private constructor(name: String) : this(name, emptyArray()) + private constructor(name: String, expr: Expr) : this(name, arrayOf(expr)) + private constructor(name: String, fieldName: String) : this(name, Field.of(fieldName)) companion object { @JvmStatic - fun countAll(): Count { - return Count(null) + fun countAll(): Accumulator { + return Accumulator("count") } @JvmStatic - fun count(fieldName: String): Count { - return Count(fieldName) + fun count(fieldName: String): Accumulator { + return Accumulator("count", fieldName) } @JvmStatic - fun count(expr: Expr): Count { - return Count(expr) + fun count(expr: Expr): Accumulator { + return Accumulator("count", expr) + } + + @JvmStatic + fun countIf(condition: BooleanExpr): Accumulator { + return Accumulator("countIf", condition) } @JvmStatic fun sum(fieldName: String): Accumulator { - return Sum(fieldName) + return Accumulator("sum", fieldName) } @JvmStatic fun sum(expr: Expr): Accumulator { - return Sum(expr) + return Accumulator("sum", expr) } @JvmStatic fun avg(fieldName: String): Accumulator { - return Avg(fieldName) + return Accumulator("avg", fieldName) } @JvmStatic fun avg(expr: Expr): Accumulator { - return Avg(expr) + return Accumulator("avg", expr) } @JvmStatic fun min(fieldName: String): Accumulator { - return min(fieldName) + return Accumulator("min", fieldName) } @JvmStatic fun min(expr: Expr): Accumulator { - return min(expr) + return Accumulator("min", expr) } @JvmStatic fun max(fieldName: String): Accumulator { - return Max(fieldName) + return Accumulator("max", fieldName) } @JvmStatic fun max(expr: Expr): Accumulator { - return Max(expr) + return Accumulator("max", expr) } } @@ -96,23 +100,3 @@ protected constructor(private val name: String, private val params: Array other - else -> Constant.of(other) + internal fun toExprOrConstant(value: Any): Expr { + return when (value) { + is Expr -> value + else -> Constant.of(value) } } @@ -73,7 +70,7 @@ abstract class Expr protected constructor() { * @param other The expression to add to this expression. * @return A new {@code Expr} representing the addition operation. */ - fun add(other: Expr) = Add(this, other) + fun add(other: Expr) = Function.add(this, other) /** * Creates an expression that this expression to another expression. @@ -86,181 +83,185 @@ abstract class Expr protected constructor() { * @param other The constant value to add to this expression. * @return A new {@code Expr} representing the addition operation. */ - fun add(other: Any) = Add(this, other) + fun add(other: Any) = Function.add(this, other) + + fun subtract(other: Expr) = Function.subtract(this, other) - fun subtract(other: Expr) = Subtract(this, other) + fun subtract(other: Any) = Function.subtract(this, other) - fun subtract(other: Any) = Subtract(this, other) + fun multiply(other: Expr) = Function.multiply(this, other) - fun multiply(other: Expr) = Multiply(this, other) + fun multiply(other: Any) = Function.multiply(this, other) - fun multiply(other: Any) = Multiply(this, other) + fun divide(other: Expr) = Function.divide(this, other) - fun divide(other: Expr) = Divide(this, other) + fun divide(other: Any) = Function.divide(this, other) - fun divide(other: Any) = Divide(this, other) + fun mod(other: Expr) = Function.mod(this, other) - fun mod(other: Expr) = Mod(this, other) + fun mod(other: Any) = Function.mod(this, other) - fun mod(other: Any) = Mod(this, other) + fun inAny(values: List) = Function.inAny(this, values) - fun `in`(values: List) = In(this, values) + fun notInAny(values: List) = Function.notInAny(this, values) - fun isNan() = IsNan(this) + fun isNan() = Function.isNan(this) - fun replaceFirst(find: Expr, replace: Expr) = ReplaceFirst(this, find, replace) + fun isNull() = Function.isNull(this) - fun replaceFirst(find: String, replace: String) = ReplaceFirst(this, find, replace) + fun replaceFirst(find: Expr, replace: Expr) = Function.replaceFirst(this, find, replace) - fun replaceAll(find: Expr, replace: Expr) = ReplaceAll(this, find, replace) + fun replaceFirst(find: String, replace: String) = Function.replaceFirst(this, find, replace) - fun replaceAll(find: String, replace: String) = ReplaceAll(this, find, replace) + fun replaceAll(find: Expr, replace: Expr) = Function.replaceAll(this, find, replace) - fun charLength() = CharLength(this) + fun replaceAll(find: String, replace: String) = Function.replaceAll(this, find, replace) - fun byteLength() = ByteLength(this) + fun charLength() = Function.charLength(this) - fun like(pattern: Expr) = Like(this, pattern) + fun byteLength() = Function.byteLength(this) - fun like(pattern: String) = Like(this, pattern) + fun like(pattern: Expr) = Function.like(this, pattern) - fun regexContains(pattern: Expr) = RegexContains(this, pattern) + fun like(pattern: String) = Function.like(this, pattern) - fun regexContains(pattern: String) = RegexContains(this, pattern) + fun regexContains(pattern: Expr) = Function.regexContains(this, pattern) - fun regexMatch(pattern: Expr) = RegexMatch(this, pattern) + fun regexContains(pattern: String) = Function.regexContains(this, pattern) - fun regexMatch(pattern: String) = RegexMatch(this, pattern) + fun regexMatch(pattern: Expr) = Function.regexMatch(this, pattern) - fun logicalMax(other: Expr) = LogicalMax(this, other) + fun regexMatch(pattern: String) = Function.regexMatch(this, pattern) - fun logicalMax(other: Any?) = LogicalMax(this, other) + fun logicalMax(other: Expr) = Function.logicalMax(this, other) - fun logicalMin(other: Expr) = LogicalMin(this, other) + fun logicalMax(other: Any) = Function.logicalMax(this, other) - fun logicalMin(other: Any?) = LogicalMin(this, other) + fun logicalMin(other: Expr) = Function.logicalMin(this, other) - fun reverse() = Reverse(this) + fun logicalMin(other: Any) = Function.logicalMin(this, other) - fun strContains(substring: Expr) = StrContains(this, substring) + fun reverse() = Function.reverse(this) - fun strContains(substring: String) = StrContains(this, substring) + fun strContains(substring: Expr) = Function.strContains(this, substring) - fun startsWith(prefix: Expr) = StartsWith(this, prefix) + fun strContains(substring: String) = Function.strContains(this, substring) - fun startsWith(prefix: String) = StartsWith(this, prefix) + fun startsWith(prefix: Expr) = Function.startsWith(this, prefix) - fun endsWith(suffix: Expr) = EndsWith(this, suffix) + fun startsWith(prefix: String) = Function.startsWith(this, prefix) - fun endsWith(suffix: String) = EndsWith(this, suffix) + fun endsWith(suffix: Expr) = Function.endsWith(this, suffix) - fun toLower() = ToLower(this) + fun endsWith(suffix: String) = Function.endsWith(this, suffix) - fun toUpper() = ToUpper(this) + fun toLower() = Function.toLower(this) - fun trim() = Trim(this) + fun toUpper() = Function.toUpper(this) - fun strConcat(vararg expr: Expr) = StrConcat(this, *expr) + fun trim() = Function.trim(this) - fun strConcat(vararg string: String) = StrConcat(this, *string) + fun strConcat(vararg expr: Expr) = Function.strConcat(this, *expr) - fun strConcat(vararg string: Any) = StrConcat(this, *string) + fun strConcat(vararg string: String) = Function.strConcat(this, *string) - fun mapGet(key: Expr) = MapGet(this, key) + fun strConcat(vararg string: Any) = Function.strConcat(this, *string) - fun mapGet(key: String) = MapGet(this, key) + fun mapGet(key: Expr) = Function.mapGet(this, key) - fun cosineDistance(vector: Expr) = CosineDistance(this, vector) + fun mapGet(key: String) = Function.mapGet(this, key) - fun cosineDistance(vector: DoubleArray) = CosineDistance(this, vector) + fun cosineDistance(vector: Expr) = Function.cosineDistance(this, vector) - fun cosineDistance(vector: VectorValue) = CosineDistance(this, vector) + fun cosineDistance(vector: DoubleArray) = Function.cosineDistance(this, vector) - fun dotProduct(vector: Expr) = DotProduct(this, vector) + fun cosineDistance(vector: VectorValue) = Function.cosineDistance(this, vector) - fun dotProduct(vector: DoubleArray) = DotProduct(this, vector) + fun dotProduct(vector: Expr) = Function.dotProduct(this, vector) - fun dotProduct(vector: VectorValue) = DotProduct(this, vector) + fun dotProduct(vector: DoubleArray) = Function.dotProduct(this, vector) - fun euclideanDistance(vector: Expr) = EuclideanDistance(this, vector) + fun dotProduct(vector: VectorValue) = Function.dotProduct(this, vector) - fun euclideanDistance(vector: DoubleArray) = EuclideanDistance(this, vector) + fun euclideanDistance(vector: Expr) = Function.euclideanDistance(this, vector) - fun euclideanDistance(vector: VectorValue) = EuclideanDistance(this, vector) + fun euclideanDistance(vector: DoubleArray) = Function.euclideanDistance(this, vector) - fun vectorLength() = VectorLength(this) + fun euclideanDistance(vector: VectorValue) = Function.euclideanDistance(this, vector) - fun unixMicrosToTimestamp() = UnixMicrosToTimestamp(this) + fun vectorLength() = Function.vectorLength(this) - fun timestampToUnixMicros() = TimestampToUnixMicros(this) + fun unixMicrosToTimestamp() = Function.unixMicrosToTimestamp(this) - fun unixMillisToTimestamp() = UnixMillisToTimestamp(this) + fun timestampToUnixMicros() = Function.timestampToUnixMicros(this) - fun timestampToUnixMillis() = TimestampToUnixMillis(this) + fun unixMillisToTimestamp() = Function.unixMillisToTimestamp(this) - fun unixSecondsToTimestamp() = UnixSecondsToTimestamp(this) + fun timestampToUnixMillis() = Function.timestampToUnixMillis(this) - fun timestampToUnixSeconds() = TimestampToUnixSeconds(this) + fun unixSecondsToTimestamp() = Function.unixSecondsToTimestamp(this) - fun timestampAdd(unit: Expr, amount: Expr) = TimestampAdd(this, unit, amount) + fun timestampToUnixSeconds() = Function.timestampToUnixSeconds(this) - fun timestampAdd(unit: String, amount: Double) = TimestampAdd(this, unit, amount) + fun timestampAdd(unit: Expr, amount: Expr) = Function.timestampAdd(this, unit, amount) - fun timestampSub(unit: Expr, amount: Expr) = TimestampSub(this, unit, amount) + fun timestampAdd(unit: String, amount: Double) = Function.timestampAdd(this, unit, amount) - fun timestampSub(unit: String, amount: Double) = TimestampSub(this, unit, amount) + fun timestampSub(unit: Expr, amount: Expr) = Function.timestampSub(this, unit, amount) - fun arrayConcat(vararg arrays: Expr) = ArrayConcat(this, *arrays) + fun timestampSub(unit: String, amount: Double) = Function.timestampSub(this, unit, amount) - fun arrayConcat(arrays: List) = ArrayConcat(this, arrays) + fun arrayConcat(vararg arrays: Expr) = Function.arrayConcat(this, *arrays) - fun arrayReverse() = ArrayReverse(this) + fun arrayConcat(arrays: List) = Function.arrayConcat(this, arrays) - fun arrayContains(value: Expr) = ArrayContains(this, value) + fun arrayReverse() = Function.arrayReverse(this) - fun arrayContains(value: Any?) = ArrayContains(this, value) + fun arrayContains(value: Expr) = Function.arrayContains(this, value) - fun arrayContainsAll(values: List) = ArrayContainsAll(this, values) + fun arrayContains(value: Any) = Function.arrayContains(this, value) - fun arrayContainsAny(values: List) = ArrayContainsAny(this, values) + fun arrayContainsAll(values: List) = Function.arrayContainsAll(this, values) - fun arrayLength() = ArrayLength(this) + fun arrayContainsAny(values: List) = Function.arrayContainsAny(this, values) - fun sum() = Sum(this) + fun arrayLength() = Function.arrayLength(this) - fun avg() = Avg(this) + fun sum() = Accumulator.sum(this) - fun min() = Min(this) + fun avg() = Accumulator.avg(this) - fun max() = Max(this) + fun min() = Accumulator.min(this) + + fun max() = Accumulator.max(this) fun ascending() = Ordering.ascending(this) fun descending() = Ordering.descending(this) - fun eq(other: Expr) = Eq(this, other) + fun eq(other: Expr) = Function.eq(this, other) - fun eq(other: Any?) = Eq(this, other) + fun eq(other: Any) = Function.eq(this, other) - fun neq(other: Expr) = Neq(this, other) + fun neq(other: Expr) = Function.neq(this, other) - fun neq(other: Any?) = Neq(this, other) + fun neq(other: Any) = Function.neq(this, other) - fun gt(other: Expr) = Gt(this, other) + fun gt(other: Expr) = Function.gt(this, other) - fun gt(other: Any?) = Gt(this, other) + fun gt(other: Any) = Function.gt(this, other) - fun gte(other: Expr) = Gte(this, other) + fun gte(other: Expr) = Function.gte(this, other) - fun gte(other: Any?) = Gte(this, other) + fun gte(other: Any) = Function.gte(this, other) - fun lt(other: Expr) = Lt(this, other) + fun lt(other: Expr) = Function.lt(this, other) - fun lt(other: Any?) = Lt(this, other) + fun lt(other: Any) = Function.lt(this, other) - fun lte(other: Expr) = Lte(this, other) + fun lte(other: Expr) = Function.lte(this, other) - fun lte(other: Any?) = Lte(this, other) + fun lte(other: Any) = Function.lte(this, other) internal abstract fun toProto(): Value } @@ -308,406 +309,418 @@ class ListOfExprs(val expressions: Array) : Expr() { open class Function protected constructor(private val name: String, private val params: Array) : Expr() { + private constructor(name: String, param: Expr, vararg params: Any) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) + private constructor(name: String, fieldName: String, vararg params: Any) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) companion object { @JvmStatic - fun and(condition: BooleanExpr, vararg conditions: BooleanExpr) = And(condition, *conditions) + fun and(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("and", condition, *conditions) @JvmStatic - fun or(condition: BooleanExpr, vararg conditions: BooleanExpr) = Or(condition, *conditions) + fun or(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("or", condition, *conditions) @JvmStatic - fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = Xor(condition, *conditions) + fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("xor", condition, *conditions) + + @JvmStatic fun not(condition: BooleanExpr) = BooleanExpr("not", condition) - @JvmStatic fun not(cond: BooleanExpr) = Not(cond) + @JvmStatic fun add(left: Expr, right: Expr) = Function("add", left, right) - @JvmStatic fun add(left: Expr, right: Expr) = Add(left, right) + @JvmStatic fun add(left: Expr, right: Any) = Function("add", left, right) - @JvmStatic fun add(left: Expr, right: Any) = Add(left, right) + @JvmStatic fun add(fieldName: String, other: Expr) = Function("add", fieldName, other) - @JvmStatic fun add(fieldName: String, other: Expr) = Add(fieldName, other) + @JvmStatic fun add(fieldName: String, other: Any) = Function("add", fieldName, other) - @JvmStatic fun add(fieldName: String, other: Any) = Add(fieldName, other) + @JvmStatic fun subtract(left: Expr, right: Expr) = Function("subtract", left, right) - @JvmStatic fun subtract(left: Expr, right: Expr) = Subtract(left, right) + @JvmStatic fun subtract(left: Expr, right: Any) = Function("subtract", left, right) - @JvmStatic fun subtract(left: Expr, right: Any) = Subtract(left, right) + @JvmStatic fun subtract(fieldName: String, other: Expr) = Function("subtract", fieldName, other) - @JvmStatic fun subtract(fieldName: String, other: Expr) = Subtract(fieldName, other) + @JvmStatic fun subtract(fieldName: String, other: Any) = Function("subtract", fieldName, other) - @JvmStatic fun subtract(fieldName: String, other: Any) = Subtract(fieldName, other) + @JvmStatic fun multiply(left: Expr, right: Expr) = Function("multiply", left, right) - @JvmStatic fun multiply(left: Expr, right: Expr) = Multiply(left, right) + @JvmStatic fun multiply(left: Expr, right: Any) = Function("multiply", left, right) - @JvmStatic fun multiply(left: Expr, right: Any) = Multiply(left, right) + @JvmStatic fun multiply(fieldName: String, other: Expr) = Function("multiply", fieldName, other) - @JvmStatic fun multiply(fieldName: String, other: Expr) = Multiply(fieldName, other) + @JvmStatic fun multiply(fieldName: String, other: Any) = Function("multiply", fieldName, other) - @JvmStatic fun multiply(fieldName: String, other: Any) = Multiply(fieldName, other) + @JvmStatic fun divide(left: Expr, right: Expr) = Function("divide", left, right) - @JvmStatic fun divide(left: Expr, right: Expr) = Divide(left, right) + @JvmStatic fun divide(left: Expr, right: Any) = Function("divide", left, right) - @JvmStatic fun divide(left: Expr, right: Any) = Divide(left, right) + @JvmStatic fun divide(fieldName: String, other: Expr) = Function("divide", fieldName, other) - @JvmStatic fun divide(fieldName: String, other: Expr) = Divide(fieldName, other) + @JvmStatic fun divide(fieldName: String, other: Any) = Function("divide", fieldName, other) - @JvmStatic fun divide(fieldName: String, other: Any) = Divide(fieldName, other) + @JvmStatic fun mod(left: Expr, right: Expr) = Function("mod", left, right) - @JvmStatic fun mod(left: Expr, right: Expr) = Mod(left, right) + @JvmStatic fun mod(left: Expr, right: Any) = Function("mod", left, right) - @JvmStatic fun mod(left: Expr, right: Any) = Mod(left, right) + @JvmStatic fun mod(fieldName: String, other: Expr) = Function("mod", fieldName, other) - @JvmStatic fun mod(fieldName: String, other: Expr) = Mod(fieldName, other) + @JvmStatic fun mod(fieldName: String, other: Any) = Function("mod", fieldName, other) - @JvmStatic fun mod(fieldName: String, other: Any) = Mod(fieldName, other) + @JvmStatic fun inAny(array: Expr, values: List) = BooleanExpr("in", array, ListOfExprs(toArrayOfExprOrConstant(values))) - @JvmStatic fun `in`(array: Expr, values: List) = In(array, values) + @JvmStatic fun inAny(fieldName: String, values: List) = BooleanExpr("in", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) - @JvmStatic fun `in`(fieldName: String, values: List) = In(fieldName, values) + @JvmStatic fun notInAny(array: Expr, values: List) = not(inAny(array, values)) - @JvmStatic fun isNan(expr: Expr) = IsNan(expr) + @JvmStatic fun notInAny(fieldName: String, values: List) = not(inAny(fieldName, values)) - @JvmStatic fun isNan(fieldName: String) = IsNan(fieldName) + @JvmStatic fun isNan(expr: Expr) = BooleanExpr("is_nan", expr) + + @JvmStatic fun isNan(fieldName: String) = BooleanExpr("is_nan", fieldName) + + @JvmStatic fun isNull(expr: Expr) = BooleanExpr("is_null", expr) + + @JvmStatic fun isNull(fieldName: String) = BooleanExpr("is_null", fieldName) @JvmStatic - fun replaceFirst(value: Expr, find: Expr, replace: Expr) = ReplaceFirst(value, find, replace) + fun replaceFirst(value: Expr, find: Expr, replace: Expr) = Function("replace_first", value, find, replace) @JvmStatic fun replaceFirst(value: Expr, find: String, replace: String) = - ReplaceFirst(value, find, replace) + Function("replace_first", value, find, replace) @JvmStatic fun replaceFirst(fieldName: String, find: String, replace: String) = - ReplaceFirst(fieldName, find, replace) + Function("replace_first", fieldName, find, replace) @JvmStatic - fun replaceAll(value: Expr, find: Expr, replace: Expr) = ReplaceAll(value, find, replace) + fun replaceAll(value: Expr, find: Expr, replace: Expr) = Function("replace_all", value, find, replace) @JvmStatic - fun replaceAll(value: Expr, find: String, replace: String) = ReplaceAll(value, find, replace) + fun replaceAll(value: Expr, find: String, replace: String) = Function("replace_all", value, find, replace) @JvmStatic fun replaceAll(fieldName: String, find: String, replace: String) = - ReplaceAll(fieldName, find, replace) + Function("replace_all", fieldName, find, replace) + + @JvmStatic fun charLength(value: Expr) = Function("char_length", value) - @JvmStatic fun charLength(value: Expr) = CharLength(value) + @JvmStatic fun charLength(fieldName: String) = Function("char_length", fieldName) - @JvmStatic fun charLength(fieldName: String) = CharLength(fieldName) + @JvmStatic fun byteLength(value: Expr) = Function("byte_length", value) - @JvmStatic fun byteLength(value: Expr) = ByteLength(value) + @JvmStatic fun byteLength(fieldName: String) = Function("byte_length", fieldName) - @JvmStatic fun byteLength(fieldName: String) = ByteLength(fieldName) + @JvmStatic fun like(expr: Expr, pattern: Expr) = BooleanExpr("like", expr, pattern) - @JvmStatic fun like(expr: Expr, pattern: Expr) = Like(expr, pattern) + @JvmStatic fun like(expr: Expr, pattern: String) = BooleanExpr("like", expr, pattern) - @JvmStatic fun like(fieldName: String, pattern: String) = Like(fieldName, pattern) + @JvmStatic fun like(fieldName: String, pattern: Expr) = BooleanExpr("like", fieldName, pattern) - @JvmStatic fun regexContains(expr: Expr, pattern: Expr) = RegexContains(expr, pattern) + @JvmStatic fun like(fieldName: String, pattern: String) = BooleanExpr("like", fieldName, pattern) - @JvmStatic fun regexContains(expr: Expr, pattern: String) = RegexContains(expr, pattern) + @JvmStatic fun regexContains(expr: Expr, pattern: Expr) = BooleanExpr("regex_contains", expr, pattern) + + @JvmStatic fun regexContains(expr: Expr, pattern: String) = BooleanExpr("regex_contains", expr, pattern) @JvmStatic - fun regexContains(fieldName: String, pattern: Expr) = RegexContains(fieldName, pattern) + fun regexContains(fieldName: String, pattern: Expr) = BooleanExpr("regex_contains", fieldName, pattern) @JvmStatic - fun regexContains(fieldName: String, pattern: String) = RegexContains(fieldName, pattern) + fun regexContains(fieldName: String, pattern: String) = BooleanExpr("regex_contains", fieldName, pattern) - @JvmStatic fun regexMatch(expr: Expr, pattern: Expr) = RegexMatch(expr, pattern) + @JvmStatic fun regexMatch(expr: Expr, pattern: Expr) = BooleanExpr("regex_match", expr, pattern) - @JvmStatic fun regexMatch(expr: Expr, pattern: String) = RegexMatch(expr, pattern) + @JvmStatic fun regexMatch(expr: Expr, pattern: String) = BooleanExpr("regex_match", expr, pattern) - @JvmStatic fun regexMatch(fieldName: String, pattern: Expr) = RegexMatch(fieldName, pattern) + @JvmStatic fun regexMatch(fieldName: String, pattern: Expr) = BooleanExpr("regex_match", fieldName, pattern) - @JvmStatic fun regexMatch(fieldName: String, pattern: String) = RegexMatch(fieldName, pattern) + @JvmStatic fun regexMatch(fieldName: String, pattern: String) = BooleanExpr("regex_match", fieldName, pattern) - @JvmStatic fun logicalMax(left: Expr, right: Expr) = LogicalMax(left, right) + @JvmStatic fun logicalMax(left: Expr, right: Expr) = Function("logical_max", left, right) - @JvmStatic fun logicalMax(left: Expr, right: Any?) = LogicalMax(left, right) + @JvmStatic fun logicalMax(left: Expr, right: Any) = Function("logical_max", left, right) - @JvmStatic fun logicalMax(fieldName: String, other: Expr) = LogicalMax(fieldName, other) + @JvmStatic fun logicalMax(fieldName: String, other: Expr) = Function("logical_max", fieldName, other) - @JvmStatic fun logicalMax(fieldName: String, other: Any?) = LogicalMax(fieldName, other) + @JvmStatic fun logicalMax(fieldName: String, other: Any) = Function("logical_max", fieldName, other) - @JvmStatic fun logicalMin(left: Expr, right: Expr) = LogicalMin(left, right) + @JvmStatic fun logicalMin(left: Expr, right: Expr) = Function("logical_min", left, right) - @JvmStatic fun logicalMin(left: Expr, right: Any?) = LogicalMin(left, right) + @JvmStatic fun logicalMin(left: Expr, right: Any) = Function("logical_min", left, right) - @JvmStatic fun logicalMin(fieldName: String, other: Expr) = LogicalMin(fieldName, other) + @JvmStatic fun logicalMin(fieldName: String, other: Expr) = Function("logical_min", fieldName, other) - @JvmStatic fun logicalMin(fieldName: String, other: Any?) = LogicalMin(fieldName, other) + @JvmStatic fun logicalMin(fieldName: String, other: Any) = Function("logical_min", fieldName, other) - @JvmStatic fun reverse(expr: Expr) = Reverse(expr) + @JvmStatic fun reverse(expr: Expr) = Function("reverse", expr) - @JvmStatic fun reverse(fieldName: String) = Reverse(fieldName) + @JvmStatic fun reverse(fieldName: String) = Function("reverse", fieldName) - @JvmStatic fun strContains(expr: Expr, substring: Expr) = StrContains(expr, substring) + @JvmStatic fun strContains(expr: Expr, substring: Expr) = BooleanExpr("str_contains", expr, substring) - @JvmStatic fun strContains(expr: Expr, substring: String) = StrContains(expr, substring) + @JvmStatic fun strContains(expr: Expr, substring: String) = BooleanExpr("str_contains", expr, substring) @JvmStatic - fun strContains(fieldName: String, substring: Expr) = StrContains(fieldName, substring) + fun strContains(fieldName: String, substring: Expr) = BooleanExpr("str_contains", fieldName, substring) @JvmStatic - fun strContains(fieldName: String, substring: String) = StrContains(fieldName, substring) + fun strContains(fieldName: String, substring: String) = BooleanExpr("str_contains", fieldName, substring) - @JvmStatic fun startsWith(expr: Expr, prefix: Expr) = StartsWith(expr, prefix) + @JvmStatic fun startsWith(expr: Expr, prefix: Expr) = BooleanExpr("starts_with", expr, prefix) - @JvmStatic fun startsWith(expr: Expr, prefix: String) = StartsWith(expr, prefix) + @JvmStatic fun startsWith(expr: Expr, prefix: String) = BooleanExpr("starts_with", expr, prefix) - @JvmStatic fun startsWith(fieldName: String, prefix: Expr) = StartsWith(fieldName, prefix) + @JvmStatic fun startsWith(fieldName: String, prefix: Expr) = BooleanExpr("starts_with", fieldName, prefix) - @JvmStatic fun startsWith(fieldName: String, prefix: String) = StartsWith(fieldName, prefix) + @JvmStatic fun startsWith(fieldName: String, prefix: String) = BooleanExpr("starts_with", fieldName, prefix) - @JvmStatic fun endsWith(expr: Expr, suffix: Expr) = EndsWith(expr, suffix) + @JvmStatic fun endsWith(expr: Expr, suffix: Expr) = BooleanExpr("ends_with", expr, suffix) - @JvmStatic fun endsWith(expr: Expr, suffix: String) = EndsWith(expr, suffix) + @JvmStatic fun endsWith(expr: Expr, suffix: String) = BooleanExpr("ends_with", expr, suffix) - @JvmStatic fun endsWith(fieldName: String, suffix: Expr) = EndsWith(fieldName, suffix) + @JvmStatic fun endsWith(fieldName: String, suffix: Expr) = BooleanExpr("ends_with", fieldName, suffix) - @JvmStatic fun endsWith(fieldName: String, suffix: String) = EndsWith(fieldName, suffix) + @JvmStatic fun endsWith(fieldName: String, suffix: String) = BooleanExpr("ends_with", fieldName, suffix) - @JvmStatic fun toLower(expr: Expr) = ToLower(expr) + @JvmStatic fun toLower(expr: Expr) = Function("to_lower", expr) @JvmStatic fun toLower( fieldName: String, - ) = ToLower(fieldName) + ) = Function("to_lower", fieldName) - @JvmStatic fun toUpper(expr: Expr) = ToUpper(expr) + @JvmStatic fun toUpper(expr: Expr) = Function("to_upper", expr) @JvmStatic fun toUpper( fieldName: String, - ) = ToUpper(fieldName) + ) = Function("to_upper", fieldName) - @JvmStatic fun trim(expr: Expr) = Trim(expr) + @JvmStatic fun trim(expr: Expr) = Function("trim", expr) - @JvmStatic fun trim(fieldName: String) = Trim(fieldName) + @JvmStatic fun trim(fieldName: String) = Function("trim", fieldName) - @JvmStatic fun strConcat(first: Expr, vararg rest: Expr) = StrConcat(first, *rest) + @JvmStatic fun strConcat(first: Expr, vararg rest: Expr) = Function("str_concat", first, *rest) - @JvmStatic fun strConcat(first: Expr, vararg rest: Any) = StrConcat(first, *rest) + @JvmStatic fun strConcat(first: Expr, vararg rest: Any) = Function("str_concat", first, *rest) - @JvmStatic fun strConcat(fieldName: String, vararg rest: Expr) = StrConcat(fieldName, *rest) + @JvmStatic fun strConcat(fieldName: String, vararg rest: Expr) = Function("str_concat", fieldName, *rest) - @JvmStatic fun strConcat(fieldName: String, vararg rest: Any) = StrConcat(fieldName, *rest) + @JvmStatic fun strConcat(fieldName: String, vararg rest: Any) = Function("str_concat", fieldName, *rest) - @JvmStatic fun mapGet(map: Expr, key: Expr) = MapGet(map, key) + @JvmStatic fun mapGet(map: Expr, key: Expr) = Function("map_get", map, key) - @JvmStatic fun mapGet(map: Expr, key: String) = MapGet(map, key) + @JvmStatic fun mapGet(map: Expr, key: String) = Function("map_get", map, key) - @JvmStatic fun mapGet(fieldName: String, key: Expr) = MapGet(fieldName, key) + @JvmStatic fun mapGet(fieldName: String, key: Expr) = Function("map_get", fieldName, key) - @JvmStatic fun mapGet(fieldName: String, key: String) = MapGet(fieldName, key) + @JvmStatic fun mapGet(fieldName: String, key: String) = Function("map_get", fieldName, key) - @JvmStatic fun cosineDistance(vector1: Expr, vector2: Expr) = CosineDistance(vector1, vector2) + @JvmStatic fun cosineDistance(vector1: Expr, vector2: Expr) = Function("cosine_distance", vector1, vector2) @JvmStatic - fun cosineDistance(vector1: Expr, vector2: DoubleArray) = CosineDistance(vector1, vector2) + fun cosineDistance(vector1: Expr, vector2: DoubleArray) = Function("cosine_distance", vector1, Constant.vector(vector2)) @JvmStatic - fun cosineDistance(vector1: Expr, vector2: VectorValue) = CosineDistance(vector1, vector2) + fun cosineDistance(vector1: Expr, vector2: VectorValue) = Function("cosine_distance", vector1, vector2) @JvmStatic - fun cosineDistance(fieldName: String, vector: Expr) = CosineDistance(fieldName, vector) + fun cosineDistance(fieldName: String, vector: Expr) = Function("cosine_distance", fieldName, vector) @JvmStatic - fun cosineDistance(fieldName: String, vector: DoubleArray) = CosineDistance(fieldName, vector) + fun cosineDistance(fieldName: String, vector: DoubleArray) = Function("cosine_distance", fieldName, Constant.vector(vector)) @JvmStatic - fun cosineDistance(fieldName: String, vector: VectorValue) = CosineDistance(fieldName, vector) + fun cosineDistance(fieldName: String, vector: VectorValue) = Function("cosine_distance", fieldName, vector) - @JvmStatic fun dotProduct(vector1: Expr, vector2: Expr) = DotProduct(vector1, vector2) + @JvmStatic fun dotProduct(vector1: Expr, vector2: Expr) = Function("dot_product", vector1, vector2) - @JvmStatic fun dotProduct(vector1: Expr, vector2: DoubleArray) = DotProduct(vector1, vector2) + @JvmStatic fun dotProduct(vector1: Expr, vector2: DoubleArray) = Function("dot_product", vector1, Constant.vector(vector2)) - @JvmStatic fun dotProduct(vector1: Expr, vector2: VectorValue) = DotProduct(vector1, vector2) + @JvmStatic fun dotProduct(vector1: Expr, vector2: VectorValue) = Function("dot_product", vector1, vector2) - @JvmStatic fun dotProduct(fieldName: String, vector: Expr) = DotProduct(fieldName, vector) + @JvmStatic fun dotProduct(fieldName: String, vector: Expr) = Function("dot_product", fieldName, vector) @JvmStatic - fun dotProduct(fieldName: String, vector: DoubleArray) = DotProduct(fieldName, vector) + fun dotProduct(fieldName: String, vector: DoubleArray) = Function("dot_product", fieldName, Constant.vector(vector)) @JvmStatic - fun dotProduct(fieldName: String, vector: VectorValue) = DotProduct(fieldName, vector) + fun dotProduct(fieldName: String, vector: VectorValue) = Function("dot_product", fieldName, vector) @JvmStatic - fun euclideanDistance(vector1: Expr, vector2: Expr) = EuclideanDistance(vector1, vector2) + fun euclideanDistance(vector1: Expr, vector2: Expr) = Function("euclidean_distance", vector1, vector2) @JvmStatic - fun euclideanDistance(vector1: Expr, vector2: DoubleArray) = EuclideanDistance(vector1, vector2) + fun euclideanDistance(vector1: Expr, vector2: DoubleArray) = Function("euclidean_distance", vector1, Constant.vector(vector2)) @JvmStatic - fun euclideanDistance(vector1: Expr, vector2: VectorValue) = EuclideanDistance(vector1, vector2) + fun euclideanDistance(vector1: Expr, vector2: VectorValue) = Function("euclidean_distance", vector1, vector2) @JvmStatic - fun euclideanDistance(fieldName: String, vector: Expr) = EuclideanDistance(fieldName, vector) + fun euclideanDistance(fieldName: String, vector: Expr) = Function("euclidean_distance", fieldName, vector) @JvmStatic fun euclideanDistance(fieldName: String, vector: DoubleArray) = - EuclideanDistance(fieldName, vector) + Function("euclidean_distance", fieldName, Constant.vector(vector)) @JvmStatic fun euclideanDistance(fieldName: String, vector: VectorValue) = - EuclideanDistance(fieldName, vector) + Function("euclidean_distance", fieldName, vector) - @JvmStatic fun vectorLength(vector: Expr) = VectorLength(vector) + @JvmStatic fun vectorLength(vector: Expr) = Function("vector_length", vector) - @JvmStatic fun vectorLength(fieldName: String) = VectorLength(fieldName) + @JvmStatic fun vectorLength(fieldName: String) = Function("vector_length", fieldName) - @JvmStatic fun unixMicrosToTimestamp(input: Expr) = UnixMicrosToTimestamp(input) + @JvmStatic fun unixMicrosToTimestamp(input: Expr) = Function("unix_micros_to_timestamp", input) - @JvmStatic fun unixMicrosToTimestamp(fieldName: String) = UnixMicrosToTimestamp(fieldName) + @JvmStatic fun unixMicrosToTimestamp(fieldName: String) = Function("unix_micros_to_timestamp", fieldName) - @JvmStatic fun timestampToUnixMicros(input: Expr) = TimestampToUnixMicros(input) + @JvmStatic fun timestampToUnixMicros(input: Expr) = Function("timestamp_to_unix_micros", input) - @JvmStatic fun timestampToUnixMicros(fieldName: String) = TimestampToUnixMicros(fieldName) + @JvmStatic fun timestampToUnixMicros(fieldName: String) = Function("timestamp_to_unix_micros", fieldName) - @JvmStatic fun unixMillisToTimestamp(input: Expr) = UnixMillisToTimestamp(input) + @JvmStatic fun unixMillisToTimestamp(input: Expr) = Function("unix_millis_to_timestamp", input) - @JvmStatic fun unixMillisToTimestamp(fieldName: String) = UnixMillisToTimestamp(fieldName) + @JvmStatic fun unixMillisToTimestamp(fieldName: String) = Function("unix_millis_to_timestamp", fieldName) - @JvmStatic fun timestampToUnixMillis(input: Expr) = TimestampToUnixMillis(input) + @JvmStatic fun timestampToUnixMillis(input: Expr) = Function("timestamp_to_unix_millis", input) - @JvmStatic fun timestampToUnixMillis(fieldName: String) = TimestampToUnixMillis(fieldName) + @JvmStatic fun timestampToUnixMillis(fieldName: String) = Function("timestamp_to_unix_millis", fieldName) - @JvmStatic fun unixSecondsToTimestamp(input: Expr) = UnixSecondsToTimestamp(input) + @JvmStatic fun unixSecondsToTimestamp(input: Expr) = Function("unix_seconds_to_timestamp", input) - @JvmStatic fun unixSecondsToTimestamp(fieldName: String) = UnixSecondsToTimestamp(fieldName) + @JvmStatic fun unixSecondsToTimestamp(fieldName: String) = Function("unix_seconds_to_timestamp", fieldName) - @JvmStatic fun timestampToUnixSeconds(input: Expr) = TimestampToUnixSeconds(input) + @JvmStatic fun timestampToUnixSeconds(input: Expr) = Function("timestamp_to_unix_seconds", input) - @JvmStatic fun timestampToUnixSeconds(fieldName: String) = TimestampToUnixSeconds(fieldName) + @JvmStatic fun timestampToUnixSeconds(fieldName: String) = Function("timestamp_to_unix_seconds", fieldName) @JvmStatic fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr) = - TimestampAdd(timestamp, unit, amount) + Function("timestamp_add", timestamp, unit, amount) @JvmStatic fun timestampAdd(timestamp: Expr, unit: String, amount: Double) = - TimestampAdd(timestamp, unit, amount) + Function("timestamp_add", timestamp, unit, amount) @JvmStatic fun timestampAdd(fieldName: String, unit: Expr, amount: Expr) = - TimestampAdd(fieldName, unit, amount) + Function("timestamp_add", fieldName, unit, amount) @JvmStatic fun timestampAdd(fieldName: String, unit: String, amount: Double) = - TimestampAdd(fieldName, unit, amount) + Function("timestamp_add", fieldName, unit, amount) @JvmStatic fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr) = - TimestampSub(timestamp, unit, amount) + Function("timestamp_sub", timestamp, unit, amount) @JvmStatic fun timestampSub(timestamp: Expr, unit: String, amount: Double) = - TimestampSub(timestamp, unit, amount) + Function("timestamp_sub", timestamp, unit, amount) @JvmStatic fun timestampSub(fieldName: String, unit: Expr, amount: Expr) = - TimestampSub(fieldName, unit, amount) + Function("timestamp_sub", fieldName, unit, amount) @JvmStatic fun timestampSub(fieldName: String, unit: String, amount: Double) = - TimestampSub(fieldName, unit, amount) + Function("timestamp_sub", fieldName, unit, amount) - @JvmStatic fun eq(left: Expr, right: Expr) = Eq(left, right) + @JvmStatic fun eq(left: Expr, right: Expr) = BooleanExpr("eq", left, right) - @JvmStatic fun eq(left: Expr, right: Any?) = Eq(left, right) + @JvmStatic fun eq(left: Expr, right: Any) = BooleanExpr("eq", left, right) - @JvmStatic fun eq(fieldName: String, right: Expr) = Eq(fieldName, right) + @JvmStatic fun eq(fieldName: String, right: Expr) = BooleanExpr("eq", fieldName, right) - @JvmStatic fun eq(fieldName: String, right: Any?) = Eq(fieldName, right) + @JvmStatic fun eq(fieldName: String, right: Any) = BooleanExpr("eq", fieldName, right) - @JvmStatic fun neq(left: Expr, right: Expr) = Neq(left, right) + @JvmStatic fun neq(left: Expr, right: Expr) = BooleanExpr("neq", left, right) - @JvmStatic fun neq(left: Expr, right: Any?) = Neq(left, right) + @JvmStatic fun neq(left: Expr, right: Any) = BooleanExpr("neq", left, right) - @JvmStatic fun neq(fieldName: String, right: Expr) = Neq(fieldName, right) + @JvmStatic fun neq(fieldName: String, right: Expr) = BooleanExpr("neq", fieldName, right) - @JvmStatic fun neq(fieldName: String, right: Any?) = Neq(fieldName, right) + @JvmStatic fun neq(fieldName: String, right: Any) = BooleanExpr("neq", fieldName, right) - @JvmStatic fun gt(left: Expr, right: Expr) = Gt(left, right) + @JvmStatic fun gt(left: Expr, right: Expr) = BooleanExpr("gt", left, right) - @JvmStatic fun gt(left: Expr, right: Any?) = Gt(left, right) + @JvmStatic fun gt(left: Expr, right: Any) = BooleanExpr("gt", left, right) - @JvmStatic fun gt(fieldName: String, right: Expr) = Gt(fieldName, right) + @JvmStatic fun gt(fieldName: String, right: Expr) = BooleanExpr("gt", fieldName, right) - @JvmStatic fun gt(fieldName: String, right: Any?) = Gt(fieldName, right) + @JvmStatic fun gt(fieldName: String, right: Any) = BooleanExpr("gt", fieldName, right) - @JvmStatic fun gte(left: Expr, right: Expr) = Gte(left, right) + @JvmStatic fun gte(left: Expr, right: Expr) = BooleanExpr("gte", left, right) - @JvmStatic fun gte(left: Expr, right: Any?) = Gte(left, right) + @JvmStatic fun gte(left: Expr, right: Any) = BooleanExpr("gte", left, right) - @JvmStatic fun gte(fieldName: String, right: Expr) = Gte(fieldName, right) + @JvmStatic fun gte(fieldName: String, right: Expr) = BooleanExpr("gte", fieldName, right) - @JvmStatic fun gte(fieldName: String, right: Any?) = Gte(fieldName, right) + @JvmStatic fun gte(fieldName: String, right: Any) = BooleanExpr("gte", fieldName, right) - @JvmStatic fun lt(left: Expr, right: Expr) = Lt(left, right) + @JvmStatic fun lt(left: Expr, right: Expr) = BooleanExpr("lt", left, right) - @JvmStatic fun lt(left: Expr, right: Any?) = Lt(left, right) + @JvmStatic fun lt(left: Expr, right: Any) = BooleanExpr("lt", left, right) - @JvmStatic fun lt(fieldName: String, right: Expr) = Lt(fieldName, right) + @JvmStatic fun lt(fieldName: String, right: Expr) = BooleanExpr("lt", fieldName, right) - @JvmStatic fun lt(fieldName: String, right: Any?) = Lt(fieldName, right) + @JvmStatic fun lt(fieldName: String, right: Any) = BooleanExpr("lt", fieldName, right) - @JvmStatic fun lte(left: Expr, right: Expr) = Lte(left, right) + @JvmStatic fun lte(left: Expr, right: Expr) = BooleanExpr("lte", left, right) - @JvmStatic fun lte(left: Expr, right: Any?) = Lte(left, right) + @JvmStatic fun lte(left: Expr, right: Any) = BooleanExpr("lte", left, right) - @JvmStatic fun lte(fieldName: String, right: Expr) = Lte(fieldName, right) + @JvmStatic fun lte(fieldName: String, right: Expr) = BooleanExpr("lte", fieldName, right) - @JvmStatic fun lte(fieldName: String, right: Any?) = Lte(fieldName, right) + @JvmStatic fun lte(fieldName: String, right: Any) = BooleanExpr("lte", fieldName, right) - @JvmStatic fun arrayConcat(array: Expr, vararg arrays: Expr) = ArrayConcat(array, *arrays) + @JvmStatic fun arrayConcat(array: Expr, vararg arrays: Expr) = Function("array_concat", array, *arrays) @JvmStatic - fun arrayConcat(fieldName: String, vararg arrays: Expr) = ArrayConcat(fieldName, *arrays) + fun arrayConcat(fieldName: String, vararg arrays: Expr) = Function("array_concat", fieldName, *arrays) - @JvmStatic fun arrayConcat(array: Expr, arrays: List) = ArrayConcat(array, arrays) + @JvmStatic fun arrayConcat(array: Expr, arrays: List) = Function("array_concat", array, ListOfExprs(toArrayOfExprOrConstant(arrays))) @JvmStatic - fun arrayConcat(fieldName: String, arrays: List) = ArrayConcat(fieldName, arrays) + fun arrayConcat(fieldName: String, arrays: List) = Function("array_concat", fieldName, ListOfExprs(toArrayOfExprOrConstant(arrays))) - @JvmStatic fun arrayReverse(array: Expr) = ArrayReverse(array) + @JvmStatic fun arrayReverse(array: Expr) = Function("array_reverse", array) - @JvmStatic fun arrayReverse(fieldName: String) = ArrayReverse(fieldName) + @JvmStatic fun arrayReverse(fieldName: String) = Function("array_reverse", fieldName) - @JvmStatic fun arrayContains(array: Expr, value: Expr) = ArrayContains(array, value) + @JvmStatic fun arrayContains(array: Expr, value: Expr) = BooleanExpr("array_contains", array, value) - @JvmStatic fun arrayContains(fieldName: String, value: Expr) = ArrayContains(fieldName, value) + @JvmStatic fun arrayContains(fieldName: String, value: Expr) = BooleanExpr("array_contains", fieldName, value) - @JvmStatic fun arrayContains(array: Expr, value: Any?) = ArrayContains(array, value) + @JvmStatic fun arrayContains(array: Expr, value: Any) = BooleanExpr("array_contains", array, value) - @JvmStatic fun arrayContains(fieldName: String, value: Any?) = ArrayContains(fieldName, value) + @JvmStatic fun arrayContains(fieldName: String, value: Any) = BooleanExpr("array_contains", fieldName, value) @JvmStatic - fun arrayContainsAll(array: Expr, values: List) = ArrayContainsAll(array, values) + fun arrayContainsAll(array: Expr, values: List) = BooleanExpr("array_contains_all", array, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic - fun arrayContainsAll(fieldName: String, values: List) = ArrayContainsAll(fieldName, values) + fun arrayContainsAll(fieldName: String, values: List) = BooleanExpr("array_contains_all", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic - fun arrayContainsAny(array: Expr, values: List) = ArrayContainsAny(array, values) + fun arrayContainsAny(array: Expr, values: List) = BooleanExpr("array_contains_any", array, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic - fun arrayContainsAny(fieldName: String, values: List) = ArrayContainsAny(fieldName, values) + fun arrayContainsAny(fieldName: String, values: List) = BooleanExpr("array_contains_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + + @JvmStatic fun arrayLength(array: Expr) = Function("array_length", array) + + @JvmStatic fun arrayLength(fieldName: String) = Function("array_length", fieldName) + + @JvmStatic fun ifThen(condition: BooleanExpr, then: Expr) = + Function("if", condition, then, Constant.NULL) - @JvmStatic fun arrayLength(array: Expr) = ArrayLength(array) + @JvmStatic fun ifThen(condition: BooleanExpr, then: Any) = Function("if", condition, then, Constant.NULL) - @JvmStatic fun arrayLength(fieldName: String) = ArrayLength(fieldName) + @JvmStatic fun ifThenElse(condition: BooleanExpr, then: Expr, `else`: Expr) = Function("if", condition, then, `else`) + + @JvmStatic fun ifThenElse(condition: BooleanExpr, then: Any, `else`: Any) = Function("if", condition, then, `else`) } - protected constructor(name: String, param1: Expr) : this(name, arrayOf(param1)) - protected constructor( - name: String, - param1: Expr, - param2: Expr - ) : this(name, arrayOf(param1, param2)) - protected constructor( - name: String, - param1: Expr, - param2: Expr, - param3: Expr - ) : this(name, arrayOf(param1, param2, param3)) + override fun toProto(): Value { val builder = com.google.firestore.v1.Function.newBuilder() builder.setName(name) @@ -718,16 +731,23 @@ protected constructor(private val name: String, private val params: Array) : Function(name, params) { + internal constructor(name: String, param: Expr, vararg params: Any) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) + internal constructor(name: String, fieldName: String, vararg params: Any) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) + + fun not() = Function.not(this) + + fun countIf(): Accumulator = Accumulator.countIf(this) - fun and(vararg conditions: BooleanExpr): And = And(this, *conditions) - fun or(vararg conditions: BooleanExpr): Or = Or(this, *conditions) + fun ifThen(then: Expr) = Function.ifThen(this, then) - fun xor(vararg conditions: BooleanExpr): Xor = Xor(this, *conditions) + fun ifThen(then: Any) = Function.ifThen(this, then) - fun not(): Not = Not(this) + fun ifThenElse(then: Expr, `else`: Expr) = Function.ifThenElse(this, then, `else`) + + fun ifThenElse(then: Any, `else`: Any) = Function.ifThenElse(this, then, `else`) } class Ordering private constructor(private val expr: Expr, private val dir: Direction) { @@ -760,36 +780,6 @@ class Ordering private constructor(private val expr: Expr, private val dir: Dire .build() } -class Add(left: Expr, right: Expr) : Function("add", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -} - -class Subtract(left: Expr, right: Expr) : Function("subtract", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -} - -class Multiply(left: Expr, right: Expr) : Function("multiply", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -} - -class Divide(left: Expr, right: Expr) : Function("divide", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -} - -class Mod(left: Expr, right: Expr) : Function("mod", left, right) { - constructor(left: Expr, right: Any) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -} - // class BitAnd(left: Expr, right: Expr) : Function("bit_and", left, right) { // constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) // constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) @@ -825,298 +815,3 @@ class Mod(left: Expr, right: Expr) : Function("mod", left, right) { // constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) // constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) // } - -class Eq(left: Expr, right: Expr) : BooleanExpr("eq", left, right) { - constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) -} - -class Neq(left: Expr, right: Expr) : BooleanExpr("neq", left, right) { - constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) -} - -class Lt(left: Expr, right: Expr) : BooleanExpr("lt", left, right) { - constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) -} - -class Lte(left: Expr, right: Expr) : BooleanExpr("lte", left, right) { - constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) -} - -class Gt(left: Expr, right: Expr) : BooleanExpr("gt", left, right) { - constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) -} - -class Gte(left: Expr, right: Expr) : BooleanExpr("gte", left, right) { - constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) -} - -class ArrayConcat(array: Expr, vararg arrays: Expr) : - Function("array_concat", arrayOf(array, *arrays)) { - constructor( - array: Expr, - arrays: List - ) : this(array, ListOfExprs(toArrayOfExprOrConstant(arrays))) - constructor(fieldName: String, vararg arrays: Expr) : this(Field.of(fieldName), *arrays) - constructor(fieldName: String, right: List) : this(Field.of(fieldName), right) -} - -class ArrayReverse(array: Expr) : Function("array_reverse", array) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class ArrayContains(array: Expr, value: Expr) : BooleanExpr("array_contains", array, value) { - constructor(array: Expr, right: Any?) : this(array, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) -} - -class ArrayContainsAll(array: Expr, values: List) : - BooleanExpr("array_contains_all", array, ListOfExprs(toArrayOfExprOrConstant(values))) { - constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) -} - -class ArrayContainsAny(array: Expr, values: List) : - BooleanExpr("array_contains_any", array, ListOfExprs(toArrayOfExprOrConstant(values))) { - constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) -} - -class ArrayLength(array: Expr) : Function("array_length", array) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class In(array: Expr, values: List) : - BooleanExpr("in", array, ListOfExprs(toArrayOfExprOrConstant(values))) { - constructor(fieldName: String, values: List) : this(Field.of(fieldName), values) -} - -class IsNan(expr: Expr) : BooleanExpr("is_nan", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class Exists(expr: Expr) : BooleanExpr("exists", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class Not(cond: BooleanExpr) : BooleanExpr("not", cond) - -class And(condition: BooleanExpr, vararg conditions: BooleanExpr) : - BooleanExpr("and", condition, *conditions) - -class Or(condition: BooleanExpr, vararg conditions: BooleanExpr) : - BooleanExpr("or", condition, *conditions) - -class Xor(condition: BooleanExpr, vararg conditions: Expr) : - BooleanExpr("xor", condition, *conditions) - -class If(condition: BooleanExpr, thenExpr: Expr, elseExpr: Expr) : - Function("if", condition, thenExpr, elseExpr) - -class LogicalMax(left: Expr, right: Expr) : Function("logical_max", left, right) { - constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) -} - -class LogicalMin(left: Expr, right: Expr) : Function("logical_min", left, right) { - constructor(left: Expr, right: Any?) : this(left, toExprOrConstant(right)) - constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) - constructor(fieldName: String, right: Any?) : this(Field.of(fieldName), right) -} - -class Reverse(expr: Expr) : Function("reverse", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class ReplaceFirst(value: Expr, find: Expr, replace: Expr) : - Function("replace_first", value, find, replace) { - constructor( - value: Expr, - find: String, - replace: String - ) : this(value, Constant.of(find), Constant.of(replace)) - constructor( - fieldName: String, - find: String, - replace: String - ) : this(Field.of(fieldName), find, replace) -} - -class ReplaceAll(value: Expr, find: Expr, replace: Expr) : - Function("replace_all", value, find, replace) { - constructor( - value: Expr, - find: String, - replace: String - ) : this(value, Constant.of(find), Constant.of(replace)) - constructor( - fieldName: String, - find: String, - replace: String - ) : this(Field.of(fieldName), find, replace) -} - -class CharLength(value: Expr) : Function("char_length", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class ByteLength(value: Expr) : Function("byte_length", value) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class Like(expr: Expr, pattern: Expr) : BooleanExpr("like", expr, pattern) { - constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) - constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) - constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) -} - -class RegexContains(expr: Expr, pattern: Expr) : BooleanExpr("regex_contains", expr, pattern) { - constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) - constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) - constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) -} - -class RegexMatch(expr: Expr, pattern: Expr) : BooleanExpr("regex_match", expr, pattern) { - constructor(expr: Expr, pattern: String) : this(expr, Constant.of(pattern)) - constructor(fieldName: String, pattern: Expr) : this(Field.of(fieldName), pattern) - constructor(fieldName: String, pattern: String) : this(Field.of(fieldName), pattern) -} - -class StrContains(expr: Expr, substring: Expr) : BooleanExpr("str_contains", expr, substring) { - constructor(expr: Expr, substring: String) : this(expr, Constant.of(substring)) - constructor(fieldName: String, substring: Expr) : this(Field.of(fieldName), substring) - constructor(fieldName: String, substring: String) : this(Field.of(fieldName), substring) -} - -class StartsWith(expr: Expr, prefix: Expr) : BooleanExpr("starts_with", expr, prefix) { - constructor(expr: Expr, prefix: String) : this(expr, Constant.of(prefix)) - constructor(fieldName: String, prefix: Expr) : this(Field.of(fieldName), prefix) - constructor(fieldName: String, prefix: String) : this(Field.of(fieldName), prefix) -} - -class EndsWith(expr: Expr, suffix: Expr) : BooleanExpr("ends_with", expr, suffix) { - constructor(expr: Expr, suffix: String) : this(expr, Constant.of(suffix)) - constructor(fieldName: String, suffix: Expr) : this(Field.of(fieldName), suffix) - constructor(fieldName: String, suffix: String) : this(Field.of(fieldName), suffix) -} - -class ToLower(expr: Expr) : Function("to_lower", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class ToUpper(expr: Expr) : Function("to_upper", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class Trim(expr: Expr) : Function("trim", expr) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class StrConcat internal constructor(first: Expr, vararg rest: Expr) : - Function("str_concat", arrayOf(first, *rest)) { - constructor(first: Expr, vararg rest: String) : this(first, *toArrayOfExprOrConstant(rest)) - constructor(first: Expr, vararg rest: Any) : this(first, *toArrayOfExprOrConstant(rest)) - constructor(fieldName: String, vararg rest: Expr) : this(Field.of(fieldName), *rest) - constructor(fieldName: String, vararg rest: Any) : this(Field.of(fieldName), *rest) - constructor(fieldName: String, vararg rest: String) : this(Field.of(fieldName), *rest) -} - -class MapGet(map: Expr, key: Expr) : Function("map_get", map, key) { - constructor(map: Expr, key: String) : this(map, Constant.of(key)) - constructor(fieldName: String, key: Expr) : this(Field.of(fieldName), key) - constructor(fieldName: String, key: String) : this(Field.of(fieldName), key) -} - -class CosineDistance(vector1: Expr, vector2: Expr) : Function("cosine_distance", vector1, vector2) { - constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) - constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) - constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) -} - -class DotProduct(vector1: Expr, vector2: Expr) : Function("dot_product", vector1, vector2) { - constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) - constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) - constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) -} - -class EuclideanDistance(vector1: Expr, vector2: Expr) : - Function("euclidean_distance", vector1, vector2) { - constructor(vector1: Expr, vector2: DoubleArray) : this(vector1, Constant.vector(vector2)) - constructor(vector1: Expr, vector2: VectorValue) : this(vector1, Constant.of(vector2)) - constructor(fieldName: String, vector2: Expr) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: DoubleArray) : this(Field.of(fieldName), vector2) - constructor(fieldName: String, vector2: VectorValue) : this(Field.of(fieldName), vector2) -} - -class VectorLength(vector: Expr) : Function("vector_length", vector) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class UnixMicrosToTimestamp(input: Expr) : Function("unix_micros_to_timestamp", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class TimestampToUnixMicros(input: Expr) : Function("timestamp_to_unix_micros", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class UnixMillisToTimestamp(input: Expr) : Function("unix_millis_to_timestamp", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class TimestampToUnixMillis(input: Expr) : Function("timestamp_to_unix_millis", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class UnixSecondsToTimestamp(input: Expr) : Function("unix_seconds_to_timestamp", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class TimestampToUnixSeconds(input: Expr) : Function("timestamp_to_unix_seconds", input) { - constructor(fieldName: String) : this(Field.of(fieldName)) -} - -class TimestampAdd(timestamp: Expr, unit: Expr, amount: Expr) : - Function("timestamp_add", timestamp, unit, amount) { - constructor( - timestamp: Expr, - unit: String, - amount: Double - ) : this(timestamp, Constant.of(unit), Constant.of(amount)) - constructor( - fieldName: String, - unit: String, - amount: Double - ) : this(Field.of(fieldName), unit, amount) - constructor(fieldName: String, unit: Expr, amount: Expr) : this(Field.of(fieldName), unit, amount) -} - -class TimestampSub(timestamp: Expr, unit: Expr, amount: Expr) : - Function("timestamp_sub", timestamp, unit, amount) { - constructor( - timestamp: Expr, - unit: String, - amount: Double - ) : this(timestamp, Constant.of(unit), Constant.of(amount)) - constructor( - fieldName: String, - unit: String, - amount: Double - ) : this(Field.of(fieldName), unit, amount) - constructor(fieldName: String, unit: Expr, amount: Expr) : this(Field.of(fieldName), unit, amount) -} From ef7cbdafdf4bcfe99bd8775635fc6dd808410f7c Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 20 Feb 2025 11:06:38 -0500 Subject: [PATCH 19/77] Add tests --- .../firebase/firestore/PipelineTest.java | 49 +++++++++++++++---- .../com/google/firebase/firestore/Pipeline.kt | 8 +++ .../firebase/firestore/pipeline/expression.kt | 28 ++++++++--- .../firebase/firestore/pipeline/stage.kt | 20 +++++--- 4 files changed, 83 insertions(+), 22 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 94842ba009d..21968864d48 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -28,6 +28,7 @@ import static com.google.firebase.firestore.pipeline.Function.logicalMin; import static com.google.firebase.firestore.pipeline.Function.lt; import static com.google.firebase.firestore.pipeline.Function.lte; +import static com.google.firebase.firestore.pipeline.Function.mapGet; import static com.google.firebase.firestore.pipeline.Function.neq; import static com.google.firebase.firestore.pipeline.Function.not; import static com.google.firebase.firestore.pipeline.Function.or; @@ -105,7 +106,10 @@ public void tearDown() { entry("published", 1979), entry("rating", 4.2), entry("tags", ImmutableList.of("comedy", "space", "adventure")), - entry("awards", ImmutableMap.of("hugo", true, "nebula", false)))), + entry("awards", ImmutableMap.of("hugo", true, "nebula", false)), + entry( + "nestedField", + ImmutableMap.of("level.1", ImmutableMap.of("level.2", true))))), entry( "book2", mapOfEntries( @@ -714,12 +718,6 @@ public void testMapGet() { ImmutableMap.of("hugoAward", true, "title", "Dune")); } - @Test - public void testParent() {} - - @Test - public void testCollectionId() {} - @Test public void testDistanceFunctions() { double[] sourceVector = {0.1, 0.1}; @@ -745,10 +743,43 @@ public void testDistanceFunctions() { } @Test - public void testNestedFields() {} + public void testNestedFields() { + Task execute = + randomCol + .pipeline() + .where(eq("awards.hugo", true)) + .select("title", "awards.hugo") + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + ImmutableMap.of("title", "The Hitchhiker's Guide to the Galaxy", "awards.hugo", true), + ImmutableMap.of("title", "Dune", "awards.hugo", true)); + } @Test - public void testMapGetWithFieldNameIncludingNotation() {} + public void testMapGetWithFieldNameIncludingNotation() { + Task execute = + randomCol + .pipeline() + .where(eq("awards.hugo", true)) + .select( + "title", + Field.of("nestedField.level.1"), + mapGet("nestedField", "level.1").mapGet("level.2").as("nested")) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + mapOfEntries( + entry("title", "The Hitchhiker's Guide to the Galaxy"), + entry("nestedField.level.`1`", null), + entry("nested", true)), + mapOfEntries( + entry("title", "Dune"), + entry("nestedField.level.`1`", null), + entry("nested", null))); + } static Map.Entry entry(String key, T value) { return new Map.Entry() { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 75825ad2cec..4840084233b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -107,6 +107,10 @@ internal constructor( return append(SelectStage(fields.map(Field::of).toTypedArray())) } + fun select(vararg fields: Any): Pipeline { + return append(SelectStage(fields.map(Selectable::toSelectable).toTypedArray())) + } + fun sort(vararg orders: Ordering): Pipeline { return append(SortStage(orders)) } @@ -131,6 +135,10 @@ internal constructor( return append(DistinctStage(groups.map(Field::of).toTypedArray())) } + fun distinct(vararg groups: Any): Pipeline { + return append(DistinctStage(groups.map(Selectable::toSelectable).toTypedArray())) + } + fun aggregate(vararg accumulators: AccumulatorWithAlias): Pipeline { return append(AggregateStage.withAccumulators(*accumulators)) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt index 88a7595cc7f..24e6e494193 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt @@ -266,15 +266,29 @@ abstract class Expr protected constructor() { internal abstract fun toProto(): Value } -abstract class Selectable(internal val alias: String) : Expr() +abstract class Selectable() : Expr() { + internal abstract fun getAlias(): String -open class ExprWithAlias internal constructor(alias: String, private val expr: Expr) : - Selectable(alias) { + internal companion object { + fun toSelectable(o: Any): Selectable { + return when (o) { + is Selectable -> o + is String -> Field.of(o) + is FieldPath -> Field.of(o) + else -> throw IllegalArgumentException("Unknown Selectable type: $o") + } + } + } +} + +open class ExprWithAlias internal constructor(private val alias: String, private val expr: Expr) : + Selectable() { + override fun getAlias() = alias override fun toProto(): Value = expr.toProto() } class Field private constructor(private val fieldPath: ModelFieldPath) : - Selectable(fieldPath.canonicalString()) { + Selectable() { companion object { @JvmStatic @@ -293,11 +307,14 @@ class Field private constructor(private val fieldPath: ModelFieldPath) : return Field(fieldPath.internalPath) } } + + override fun getAlias(): String = fieldPath.canonicalString() + override fun toProto() = Value.newBuilder().setFieldReferenceValue(fieldPath.canonicalString()).build() } -class ListOfExprs(val expressions: Array) : Expr() { +class ListOfExprs(private val expressions: Array) : Expr() { override fun toProto(): Value { val builder = ArrayValue.newBuilder() for (expr in expressions) { @@ -740,7 +757,6 @@ class BooleanExpr internal constructor(name: String, params: Array) : fun countIf(): Accumulator = Accumulator.countIf(this) - fun ifThen(then: Expr) = Function.ifThen(this, then) fun ifThen(then: Any) = Function.ifThen(this, then) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index dd9c48ab5bf..81fc2ef7499 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -57,7 +57,7 @@ class DocumentsSource internal constructor(private val documents: Array) : Stage("add_fields") { override fun args(): Sequence = - sequenceOf(encodeValue(fields.associate { it.alias to it.toProto() })) + sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto() })) } class AggregateStage @@ -65,7 +65,7 @@ internal constructor( private val accumulators: Map, private val groups: Map ) : Stage("aggregate") { - internal constructor(accumulators: Map) : this(accumulators, emptyMap()) + private constructor(accumulators: Map) : this(accumulators, emptyMap()) companion object { @JvmStatic fun withAccumulators(vararg accumulators: AccumulatorWithAlias): AggregateStage { @@ -78,12 +78,18 @@ internal constructor( } } - fun withGroups(vararg selectable: Selectable) = - AggregateStage(accumulators, selectable.associateBy(Selectable::alias)) + fun withGroups(vararg groups: Selectable) = + AggregateStage(accumulators, groups.associateBy(Selectable::getAlias)) fun withGroups(vararg fields: String) = AggregateStage(accumulators, fields.associateWith(Field::of)) + fun withGroups(vararg selectable: Any) = + AggregateStage( + accumulators, + selectable.map(Selectable::toSelectable).associateBy(Selectable::getAlias) + ) + override fun args(): Sequence = sequenceOf( encodeValue(accumulators.mapValues { entry -> entry.value.toProto() }), @@ -141,7 +147,7 @@ class OffsetStage internal constructor(private val offset: Long) : Stage("offset class SelectStage internal constructor(private val fields: Array) : Stage("select") { override fun args(): Sequence = - sequenceOf(encodeValue(fields.associate { it.alias to it.toProto() })) + sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto() })) } class SortStage internal constructor(private val orders: Array) : Stage("sort") { @@ -151,7 +157,7 @@ class SortStage internal constructor(private val orders: Array) : class DistinctStage internal constructor(private val groups: Array) : Stage("distinct") { override fun args(): Sequence = - sequenceOf(encodeValue(groups.associate { it.alias to it.toProto() })) + sequenceOf(encodeValue(groups.associate { it.getAlias() to it.toProto() })) } class RemoveFieldsStage internal constructor(private val fields: Array) : @@ -192,5 +198,5 @@ class UnionStage internal constructor(private val other: com.google.firebase.fir class UnnestStage internal constructor(private val selectable: Selectable) : Stage("unnest") { override fun args(): Sequence = - sequenceOf(encodeValue(selectable.alias), selectable.toProto()) + sequenceOf(encodeValue(selectable.getAlias()), selectable.toProto()) } From ca31612434dc1f95d75c6e2eacea155d703a5c39 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 20 Feb 2025 11:18:53 -0500 Subject: [PATCH 20/77] Cleanup --- .../google/firebase/firestore/Firestore.kt | 1 - .../com/google/firebase/firestore/Pipeline.kt | 84 ++++++------------- .../firestore/pipeline/accumulators.kt | 64 +++----------- .../firebase/firestore/pipeline/expression.kt | 14 ++-- 4 files changed, 47 insertions(+), 116 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Firestore.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Firestore.kt index 9f5027b5e29..e2ccf89637d 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Firestore.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Firestore.kt @@ -21,7 +21,6 @@ import com.google.firebase.Firebase import com.google.firebase.FirebaseApp import com.google.firebase.components.Component import com.google.firebase.components.ComponentRegistrar -import com.google.firebase.firestore.* import com.google.firebase.firestore.util.Executors.BACKGROUND_EXECUTOR import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.awaitClose diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 4840084233b..6fa92b88b8b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -47,7 +47,7 @@ import com.google.firestore.v1.Value class Pipeline internal constructor( internal val firestore: FirebaseFirestore, - internal val stages: FluentIterable + private val stages: FluentIterable ) { internal constructor( firestore: FirebaseFirestore, @@ -68,7 +68,7 @@ internal constructor( return DocumentReference(key, firestore) } - internal fun toProto(): ExecutePipelineRequest { + private fun toProto(): ExecutePipelineRequest { val database = firestore.databaseId val builder = ExecutePipelineRequest.newBuilder() builder.database = "projects/${database.projectId}/databases/${database.databaseId}" @@ -87,67 +87,43 @@ internal constructor( .addAllStages(stages.map(Stage::toProtoStage)) .build() - fun addFields(vararg fields: Selectable): Pipeline { - return append(AddFieldsStage(fields)) - } + fun addFields(vararg fields: Selectable): Pipeline = append(AddFieldsStage(fields)) - fun removeFields(vararg fields: Field): Pipeline { - return append(RemoveFieldsStage(fields)) - } + fun removeFields(vararg fields: Field): Pipeline = append(RemoveFieldsStage(fields)) - fun removeFields(vararg fields: String): Pipeline { - return append(RemoveFieldsStage(fields.map(Field::of).toTypedArray())) - } + fun removeFields(vararg fields: String): Pipeline = + append(RemoveFieldsStage(fields.map(Field::of).toTypedArray())) - fun select(vararg fields: Selectable): Pipeline { - return append(SelectStage(fields)) - } + fun select(vararg fields: Selectable): Pipeline = append(SelectStage(fields)) - fun select(vararg fields: String): Pipeline { - return append(SelectStage(fields.map(Field::of).toTypedArray())) - } + fun select(vararg fields: String): Pipeline = + append(SelectStage(fields.map(Field::of).toTypedArray())) - fun select(vararg fields: Any): Pipeline { - return append(SelectStage(fields.map(Selectable::toSelectable).toTypedArray())) - } + fun select(vararg fields: Any): Pipeline = + append(SelectStage(fields.map(Selectable::toSelectable).toTypedArray())) - fun sort(vararg orders: Ordering): Pipeline { - return append(SortStage(orders)) - } + fun sort(vararg orders: Ordering): Pipeline = append(SortStage(orders)) - fun where(condition: BooleanExpr): Pipeline { - return append(WhereStage(condition)) - } + fun where(condition: BooleanExpr): Pipeline = append(WhereStage(condition)) - fun offset(offset: Long): Pipeline { - return append(OffsetStage(offset)) - } + fun offset(offset: Long): Pipeline = append(OffsetStage(offset)) - fun limit(limit: Long): Pipeline { - return append(LimitStage(limit)) - } + fun limit(limit: Long): Pipeline = append(LimitStage(limit)) - fun distinct(vararg groups: Selectable): Pipeline { - return append(DistinctStage(groups)) - } + fun distinct(vararg groups: Selectable): Pipeline = append(DistinctStage(groups)) - fun distinct(vararg groups: String): Pipeline { - return append(DistinctStage(groups.map(Field::of).toTypedArray())) - } + fun distinct(vararg groups: String): Pipeline = + append(DistinctStage(groups.map(Field::of).toTypedArray())) - fun distinct(vararg groups: Any): Pipeline { - return append(DistinctStage(groups.map(Selectable::toSelectable).toTypedArray())) - } + fun distinct(vararg groups: Any): Pipeline = + append(DistinctStage(groups.map(Selectable::toSelectable).toTypedArray())) - fun aggregate(vararg accumulators: AccumulatorWithAlias): Pipeline { - return append(AggregateStage.withAccumulators(*accumulators)) - } + fun aggregate(vararg accumulators: AccumulatorWithAlias): Pipeline = + append(AggregateStage.withAccumulators(*accumulators)) - fun aggregate(aggregateStage: AggregateStage): Pipeline { - return append(aggregateStage) - } + fun aggregate(aggregateStage: AggregateStage): Pipeline = append(aggregateStage) - private inner class ObserverSnapshotTask() : PipelineResultObserver { + private inner class ObserverSnapshotTask : PipelineResultObserver { private val taskCompletionSource = TaskCompletionSource() private val results: ImmutableList.Builder = ImmutableList.builder() override fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) { @@ -197,9 +173,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto return Pipeline(firestore, CollectionGroupSource(collectionId)) } - fun database(): Pipeline { - return Pipeline(firestore, DatabaseSource()) - } + fun database(): Pipeline = Pipeline(firestore, DatabaseSource()) fun documents(vararg documents: String): Pipeline { // Validate document path by converting to DocumentReference @@ -233,16 +207,12 @@ internal constructor( private val version: SnapshotVersion, ) { - fun getData(): Map { - return userDataWriter().convertObject(fields) - } + fun getData(): Map = userDataWriter().convertObject(fields) private fun userDataWriter(): UserDataWriter = UserDataWriter(firestore, DocumentSnapshot.ServerTimestampBehavior.DEFAULT) - override fun toString(): String { - return "PipelineResult{ref=$ref, version=$version}, data=${getData()}" - } + override fun toString() = "PipelineResult{ref=$ref, version=$version}, data=${getData()}" } internal interface PipelineResultObserver { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt index b89c318636a..7ea8668b1b2 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt @@ -26,70 +26,32 @@ private constructor(private val name: String, private val params: Array) : internal constructor(name: String, param: Expr, vararg params: Any) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) internal constructor(name: String, fieldName: String, vararg params: Any) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) - fun not() = Function.not(this) + fun not() = not(this) fun countIf(): Accumulator = Accumulator.countIf(this) - fun ifThen(then: Expr) = Function.ifThen(this, then) + fun ifThen(then: Expr) = ifThen(this, then) - fun ifThen(then: Any) = Function.ifThen(this, then) + fun ifThen(then: Any) = ifThen(this, then) - fun ifThenElse(then: Expr, `else`: Expr) = Function.ifThenElse(this, then, `else`) + fun ifThenElse(then: Expr, `else`: Expr) = ifThenElse(this, then, `else`) - fun ifThenElse(then: Any, `else`: Any) = Function.ifThenElse(this, then, `else`) + fun ifThenElse(then: Any, `else`: Any) = ifThenElse(this, then, `else`) } class Ordering private constructor(private val expr: Expr, private val dir: Direction) { @@ -779,7 +779,7 @@ class Ordering private constructor(private val expr: Expr, private val dir: Dire fun descending(fieldName: String): Ordering = Ordering(Field.of(fieldName), Direction.DESCENDING) } - private class Direction private constructor(internal val proto: Value) { + private class Direction private constructor(val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) companion object { val ASCENDING = Direction("ascending") From c7605b653ae9a1dfb2c8ae51ddb6dd86cb5f7a4c Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 28 Feb 2025 13:11:33 -0500 Subject: [PATCH 21/77] Generic Stage and Refactor --- .../firebase/firestore/PipelineTest.java | 59 +++++++-- .../firebase/firestore/FirebaseFirestore.java | 5 +- .../com/google/firebase/firestore/Pipeline.kt | 11 +- .../firebase/firestore/UserDataReader.java | 22 ++++ .../google/firebase/firestore/model/Values.kt | 10 +- .../firebase/firestore/pipeline/Constant.kt | 58 ++++----- .../{accumulators.kt => aggregates.kt} | 37 +++--- .../{expression.kt => expressions.kt} | 78 ++++++++---- .../firebase/firestore/pipeline/stage.kt | 115 +++++++++++++----- 9 files changed, 274 insertions(+), 121 deletions(-) rename firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/{accumulators.kt => aggregates.kt} (50%) rename firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/{expression.kt => expressions.kt} (92%) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 21968864d48..50df7ef880d 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -37,14 +37,13 @@ import static com.google.firebase.firestore.pipeline.Function.subtract; import static com.google.firebase.firestore.pipeline.Ordering.ascending; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.waitFor; -import static java.util.Map.entry; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.gms.tasks.Task; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.truth.Correspondence; -import com.google.firebase.firestore.pipeline.Accumulator; +import com.google.firebase.firestore.pipeline.AggregateExpr; import com.google.firebase.firestore.pipeline.AggregateStage; import com.google.firebase.firestore.pipeline.Constant; import com.google.firebase.firestore.pipeline.Field; @@ -227,7 +226,7 @@ public void aggregateResultsCountAll() { firestore .pipeline() .collection(randomCol) - .aggregate(Accumulator.countAll().as("count")) + .aggregate(AggregateExpr.countAll().as("count")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -243,8 +242,8 @@ public void aggregateResultsMany() { .collection(randomCol) .where(Function.eq("genre", "Science Fiction")) .aggregate( - Accumulator.countAll().as("count"), - Accumulator.avg("rating").as("avgRating"), + AggregateExpr.countAll().as("count"), + AggregateExpr.avg("rating").as("avgRating"), Field.of("rating").max().as("maxRating")) .execute(); assertThat(waitFor(execute).getResults()) @@ -261,7 +260,7 @@ public void groupAndAccumulateResults() { .collection(randomCol) .where(lt(Field.of("published"), 1984)) .aggregate( - AggregateStage.withAccumulators(Accumulator.avg("rating").as("avgRating")) + AggregateStage.withAccumulators(AggregateExpr.avg("rating").as("avgRating")) .withGroups("genre")) .where(gt("avgRating", 4.3)) .sort(Field.of("avgRating").descending()) @@ -274,6 +273,28 @@ public void groupAndAccumulateResults() { mapOfEntries(entry("avgRating", 4.4), entry("genre", "Science Fiction"))); } + @Test + public void groupAndAccumulateResultsGeneric() { + Task execute = + firestore + .pipeline() + .collection(randomCol) + .genericStage("where", lt(Field.of("published"), 1984)) + .genericStage( + "aggregate", + ImmutableMap.of("avgRating", AggregateExpr.avg("rating")), + ImmutableMap.of("genre", Field.of("genre"))) + .genericStage("where", gt("avgRating", 4.3)) + .genericStage("sort", Field.of("avgRating").descending()) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(DATA_CORRESPONDENCE) + .containsExactly( + mapOfEntries(entry("avgRating", 4.7), entry("genre", "Fantasy")), + mapOfEntries(entry("avgRating", 4.5), entry("genre", "Romance")), + mapOfEntries(entry("avgRating", 4.4), entry("genre", "Science Fiction"))); + } + @Test @Ignore("Not supported yet") public void minAndMaxAccumulations() { @@ -282,7 +303,7 @@ public void minAndMaxAccumulations() { .pipeline() .collection(randomCol) .aggregate( - Accumulator.countAll().as("count"), + AggregateExpr.countAll().as("count"), Field.of("rating").max().as("maxRating"), Field.of("published").min().as("minPublished")) .execute(); @@ -781,6 +802,30 @@ public void testMapGetWithFieldNameIncludingNotation() { entry("nested", null))); } + @Test + public void testListEquals() { + Task execute = + randomCol + .pipeline() + .where(eq("tags", ImmutableList.of("philosophy", "crime", "redemption"))) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(ID_CORRESPONDENCE) + .containsExactly("book6"); + } + + @Test + public void testMapEquals() { + Task execute = + randomCol + .pipeline() + .where(eq("awards", ImmutableMap.of("nobel", true, "nebula", false))) + .execute(); + assertThat(waitFor(execute).getResults()) + .comparingElementsUsing(ID_CORRESPONDENCE) + .containsExactly("book3"); + } + static Map.Entry entry(String key, T value) { return new Map.Entry() { private String k = key; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java index 114fc18da95..932be5983f5 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java @@ -23,6 +23,7 @@ import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; import androidx.annotation.VisibleForTesting; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; @@ -855,7 +856,9 @@ DatabaseId getDatabaseId() { return databaseId; } - UserDataReader getUserDataReader() { + @NonNull + @RestrictTo(RestrictTo.Scope.LIBRARY) + public UserDataReader getUserDataReader() { return userDataReader; } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 6fa92b88b8b..6a3f765fd38 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -20,9 +20,9 @@ import com.google.common.collect.FluentIterable import com.google.common.collect.ImmutableList import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.SnapshotVersion -import com.google.firebase.firestore.pipeline.AccumulatorWithAlias import com.google.firebase.firestore.pipeline.AddFieldsStage import com.google.firebase.firestore.pipeline.AggregateStage +import com.google.firebase.firestore.pipeline.AggregateWithAlias import com.google.firebase.firestore.pipeline.BooleanExpr import com.google.firebase.firestore.pipeline.CollectionGroupSource import com.google.firebase.firestore.pipeline.CollectionSource @@ -30,6 +30,8 @@ import com.google.firebase.firestore.pipeline.DatabaseSource import com.google.firebase.firestore.pipeline.DistinctStage import com.google.firebase.firestore.pipeline.DocumentsSource import com.google.firebase.firestore.pipeline.Field +import com.google.firebase.firestore.pipeline.GenericArg +import com.google.firebase.firestore.pipeline.GenericStage import com.google.firebase.firestore.pipeline.LimitStage import com.google.firebase.firestore.pipeline.OffsetStage import com.google.firebase.firestore.pipeline.Ordering @@ -84,9 +86,12 @@ internal constructor( internal fun toPipelineProto(): com.google.firestore.v1.Pipeline = com.google.firestore.v1.Pipeline.newBuilder() - .addAllStages(stages.map(Stage::toProtoStage)) + .addAllStages(stages.map { it.toProtoStage(firestore.userDataReader) }) .build() + fun genericStage(name: String, vararg params: Any) = + append(GenericStage(name, params.map(GenericArg::from))) + fun addFields(vararg fields: Selectable): Pipeline = append(AddFieldsStage(fields)) fun removeFields(vararg fields: Field): Pipeline = append(RemoveFieldsStage(fields)) @@ -118,7 +123,7 @@ internal constructor( fun distinct(vararg groups: Any): Pipeline = append(DistinctStage(groups.map(Selectable::toSelectable).toTypedArray())) - fun aggregate(vararg accumulators: AccumulatorWithAlias): Pipeline = + fun aggregate(vararg accumulators: AggregateWithAlias): Pipeline = append(AggregateStage.withAccumulators(*accumulators)) fun aggregate(aggregateStage: AggregateStage): Pipeline = append(aggregateStage) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java index b1462ed9f74..3ce7cfec87c 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java @@ -19,6 +19,7 @@ import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; +import com.google.common.base.Function; import com.google.firebase.firestore.FieldValue.ArrayRemoveFieldValue; import com.google.firebase.firestore.FieldValue.ArrayUnionFieldValue; import com.google.firebase.firestore.FieldValue.DeleteFieldValue; @@ -36,6 +37,7 @@ import com.google.firebase.firestore.model.mutation.FieldMask; import com.google.firebase.firestore.model.mutation.NumericIncrementTransformOperation; import com.google.firebase.firestore.model.mutation.ServerTimestampOperation; +import com.google.firebase.firestore.pipeline.Expr; import com.google.firebase.firestore.util.Assert; import com.google.firebase.firestore.util.CustomClassMapper; import com.google.firebase.firestore.util.Util; @@ -389,6 +391,12 @@ public Value parseScalarValue(Object input, ParseContext context) { return Values.NULL_VALUE; } else if (input.getClass().isArray()) { throw context.createError("Arrays are not supported; use a List instead"); + } else if (input instanceof DocumentReference) { + DocumentReference ref = (DocumentReference) input; + validateDocumentReference(ref, context::createError); + return Values.encodeValue(ref); + } else if (input instanceof Expr) { + throw context.createError("Pipeline expressions are not supported user objects"); } else { try { return Values.encodeAnyValue(input); @@ -398,6 +406,20 @@ public Value parseScalarValue(Object input, ParseContext context) { } } + public void validateDocumentReference( + DocumentReference ref, Function createError) { + DatabaseId otherDb = ref.getFirestore().getDatabaseId(); + if (!otherDb.equals(databaseId)) { + throw createError.apply( + String.format( + "Document reference is for database %s/%s but should be for database %s/%s", + otherDb.getProjectId(), + otherDb.getDatabaseId(), + databaseId.getProjectId(), + databaseId.getDatabaseId())); + } + } + private List parseArrayTransformElements(List elements) { ParseAccumulator accumulator = new ParseAccumulator(UserData.Source.Argument); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt index 3b9701bc4ec..d5ae4064d95 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt @@ -609,9 +609,7 @@ internal object Values { return Value.newBuilder() .setTimestampValue( - com.google.protobuf.Timestamp.newBuilder() - .setSeconds(timestamp.seconds) - .setNanos(truncatedNanoseconds) + Timestamp.newBuilder().setSeconds(timestamp.seconds).setNanos(truncatedNanoseconds) ) .build() } @@ -665,6 +663,11 @@ internal object Values { return Value.newBuilder().setMapValue(MapValue.newBuilder().putAllFields(map)).build() } + @JvmStatic + fun encodeValue(values: Iterable): Value { + return Value.newBuilder().setArrayValue(ArrayValue.newBuilder().addAllValues(values)).build() + } + @JvmStatic fun encodeAnyValue(value: Any?): Value { return when (value) { @@ -676,7 +679,6 @@ internal object Values { is Boolean -> encodeValue(value) is GeoPoint -> encodeValue(value) is Blob -> encodeValue(value) - is DocumentReference -> encodeValue(value) is VectorValue -> encodeValue(value) else -> throw IllegalArgumentException("Unexpected type: $value") } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt index bc9a39a50d4..e9bcf7aac43 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt @@ -18,76 +18,70 @@ import com.google.firebase.Timestamp import com.google.firebase.firestore.Blob import com.google.firebase.firestore.DocumentReference import com.google.firebase.firestore.GeoPoint +import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.VectorValue import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.Values.encodeValue import com.google.firestore.v1.Value import java.util.Date -class Constant internal constructor(val value: Value) : Expr() { +abstract class Constant internal constructor() : Expr() { + + private class ValueConstant(val value: Value) : Constant() { + override fun toProto(userDataReader: UserDataReader): Value = value + } companion object { - internal val NULL = Constant(Values.NULL_VALUE) - - fun of(value: Any): Constant { - return when (value) { - is String -> of(value) - is Number -> of(value) - is Date -> of(value) - is Timestamp -> of(value) - is Boolean -> of(value) - is GeoPoint -> of(value) - is Blob -> of(value) - is DocumentReference -> of(value) - is Value -> of(value) - is VectorValue -> of(value) - else -> throw IllegalArgumentException("Unknown type: $value") - } - } + internal val NULL: Constant = ValueConstant(Values.NULL_VALUE) @JvmStatic fun of(value: String): Constant { - return Constant(encodeValue(value)) + return ValueConstant(encodeValue(value)) } @JvmStatic fun of(value: Number): Constant { - return Constant(encodeValue(value)) + return ValueConstant(encodeValue(value)) } @JvmStatic fun of(value: Date): Constant { - return Constant(encodeValue(value)) + return ValueConstant(encodeValue(value)) } @JvmStatic fun of(value: Timestamp): Constant { - return Constant(encodeValue(value)) + return ValueConstant(encodeValue(value)) } @JvmStatic fun of(value: Boolean): Constant { - return Constant(encodeValue(value)) + return ValueConstant(encodeValue(value)) } @JvmStatic fun of(value: GeoPoint): Constant { - return Constant(encodeValue(value)) + return ValueConstant(encodeValue(value)) } @JvmStatic fun of(value: Blob): Constant { - return Constant(encodeValue(value)) + return ValueConstant(encodeValue(value)) } @JvmStatic - fun of(value: DocumentReference): Constant { - return Constant(encodeValue(value)) + fun of(ref: DocumentReference): Constant { + return object : Constant() { + override fun toProto(userDataReader: UserDataReader): Value { + userDataReader.validateDocumentReference(ref, ::IllegalArgumentException) + return encodeValue(ref) + } + } } @JvmStatic fun of(value: VectorValue): Constant { - return Constant(encodeValue(value)) + return ValueConstant(encodeValue(value)) } @JvmStatic @@ -97,16 +91,12 @@ class Constant internal constructor(val value: Value) : Expr() { @JvmStatic fun vector(value: DoubleArray): Constant { - return Constant(Values.encodeVectorValue(value)) + return ValueConstant(Values.encodeVectorValue(value)) } @JvmStatic fun vector(value: VectorValue): Constant { - return Constant(encodeValue(value)) + return ValueConstant(encodeValue(value)) } } - - override fun toProto(): Value { - return value - } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt similarity index 50% rename from firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt rename to firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt index 7ea8668b1b2..c363c28be3e 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/accumulators.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt @@ -14,50 +14,51 @@ package com.google.firebase.firestore.pipeline +import com.google.firebase.firestore.UserDataReader import com.google.firestore.v1.Value -class AccumulatorWithAlias -internal constructor(internal val alias: String, internal val accumulator: Accumulator) +class AggregateWithAlias +internal constructor(internal val alias: String, internal val expr: AggregateExpr) -class Accumulator +class AggregateExpr private constructor(private val name: String, private val params: Array) { private constructor(name: String) : this(name, emptyArray()) private constructor(name: String, expr: Expr) : this(name, arrayOf(expr)) private constructor(name: String, fieldName: String) : this(name, Field.of(fieldName)) companion object { - @JvmStatic fun countAll() = Accumulator("count") + @JvmStatic fun countAll() = AggregateExpr("count") - @JvmStatic fun count(fieldName: String) = Accumulator("count", fieldName) + @JvmStatic fun count(fieldName: String) = AggregateExpr("count", fieldName) - @JvmStatic fun count(expr: Expr) = Accumulator("count", expr) + @JvmStatic fun count(expr: Expr) = AggregateExpr("count", expr) - @JvmStatic fun countIf(condition: BooleanExpr) = Accumulator("countIf", condition) + @JvmStatic fun countIf(condition: BooleanExpr) = AggregateExpr("countIf", condition) - @JvmStatic fun sum(fieldName: String) = Accumulator("sum", fieldName) + @JvmStatic fun sum(fieldName: String) = AggregateExpr("sum", fieldName) - @JvmStatic fun sum(expr: Expr) = Accumulator("sum", expr) + @JvmStatic fun sum(expr: Expr) = AggregateExpr("sum", expr) - @JvmStatic fun avg(fieldName: String) = Accumulator("avg", fieldName) + @JvmStatic fun avg(fieldName: String) = AggregateExpr("avg", fieldName) - @JvmStatic fun avg(expr: Expr) = Accumulator("avg", expr) + @JvmStatic fun avg(expr: Expr) = AggregateExpr("avg", expr) - @JvmStatic fun min(fieldName: String) = Accumulator("min", fieldName) + @JvmStatic fun min(fieldName: String) = AggregateExpr("min", fieldName) - @JvmStatic fun min(expr: Expr) = Accumulator("min", expr) + @JvmStatic fun min(expr: Expr) = AggregateExpr("min", expr) - @JvmStatic fun max(fieldName: String) = Accumulator("max", fieldName) + @JvmStatic fun max(fieldName: String) = AggregateExpr("max", fieldName) - @JvmStatic fun max(expr: Expr) = Accumulator("max", expr) + @JvmStatic fun max(expr: Expr) = AggregateExpr("max", expr) } - fun `as`(alias: String) = AccumulatorWithAlias(alias, this) + fun `as`(alias: String) = AggregateWithAlias(alias, this) - fun toProto(): Value { + internal fun toProto(userDataReader: UserDataReader): Value { val builder = com.google.firestore.v1.Function.newBuilder() builder.setName(name) for (param in params) { - builder.addArgs(param.toProto()) + builder.addArgs(param.toProto(userDataReader)) } return Value.newBuilder().setFunctionValue(builder).build() } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt similarity index 92% rename from firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt rename to firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index afc796742b0..a4a6912fbce 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expression.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -14,21 +14,49 @@ package com.google.firebase.firestore.pipeline +import com.google.firebase.Timestamp +import com.google.firebase.firestore.Blob +import com.google.firebase.firestore.DocumentReference import com.google.firebase.firestore.FieldPath +import com.google.firebase.firestore.GeoPoint +import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.VectorValue import com.google.firebase.firestore.model.DocumentKey -import com.google.firebase.firestore.model.FieldPath as ModelFieldPath import com.google.firebase.firestore.model.Values.encodeValue -import com.google.firestore.v1.ArrayValue +import com.google.firebase.firestore.pipeline.Constant.Companion.of +import com.google.firebase.firestore.util.CustomClassMapper import com.google.firestore.v1.MapValue import com.google.firestore.v1.Value +import java.util.Date +import kotlin.reflect.KFunction1 +import com.google.firebase.firestore.model.FieldPath as ModelFieldPath -abstract class Expr protected constructor() { +abstract class Expr internal constructor() { internal companion object { - internal fun toExprOrConstant(value: Any): Expr { + internal fun toExprOrConstant(value: Any?): Expr = toExpr(value, ::toExprOrConstant) ?: pojoToExprOrConstant(CustomClassMapper.convertToPlainJavaTypes(value)) + + private fun pojoToExprOrConstant(value: Any?): Expr = toExpr(value, ::pojoToExprOrConstant) ?: throw IllegalArgumentException("Unknown type: $value") + + private fun toExpr(value: Any?, toExpr: KFunction1): Expr? { + if (value == null) return Constant.nullValue() return when (value) { is Expr -> value - else -> Constant.of(value) + is String -> of(value) + is Number -> of(value) + is Date -> of(value) + is Timestamp -> of(value) + is Boolean -> of(value) + is GeoPoint -> of(value) + is Blob -> of(value) + is DocumentReference -> of(value) + is VectorValue -> of(value) + is Map<*, *> -> MapOfExpr(value.entries.associate { + val key = it.key + if (key is String) key to toExpr(it.value) else + throw IllegalArgumentException("Maps with non-string keys are not supported") + }) + is List<*> -> ListOfExprs(value.map(toExpr).toTypedArray()) + else -> null } } @@ -227,13 +255,13 @@ abstract class Expr protected constructor() { fun arrayLength() = Function.arrayLength(this) - fun sum() = Accumulator.sum(this) + fun sum() = AggregateExpr.sum(this) - fun avg() = Accumulator.avg(this) + fun avg() = AggregateExpr.avg(this) - fun min() = Accumulator.min(this) + fun min() = AggregateExpr.min(this) - fun max() = Accumulator.max(this) + fun max() = AggregateExpr.max(this) fun ascending() = Ordering.ascending(this) @@ -263,7 +291,7 @@ abstract class Expr protected constructor() { fun lte(other: Any) = Function.lte(this, other) - internal abstract fun toProto(): Value + internal abstract fun toProto(userDataReader: UserDataReader): Value } abstract class Selectable : Expr() { @@ -284,7 +312,7 @@ abstract class Selectable : Expr() { open class ExprWithAlias internal constructor(private val alias: String, private val expr: Expr) : Selectable() { override fun getAlias() = alias - override fun toProto(): Value = expr.toProto() + override fun toProto(userDataReader: UserDataReader): Value = expr.toProto(userDataReader) } class Field private constructor(private val fieldPath: ModelFieldPath) : @@ -310,20 +338,26 @@ class Field private constructor(private val fieldPath: ModelFieldPath) : override fun getAlias(): String = fieldPath.canonicalString() - override fun toProto() = + override fun toProto(userDataReader: UserDataReader) = toProto() + + internal fun toProto(): Value = Value.newBuilder().setFieldReferenceValue(fieldPath.canonicalString()).build() } -class ListOfExprs(private val expressions: Array) : Expr() { - override fun toProto(): Value { - val builder = ArrayValue.newBuilder() +class MapOfExpr(private val expressions: Map) : Expr() { + override fun toProto(userDataReader: UserDataReader): Value { + val builder = MapValue.newBuilder() for (expr in expressions) { - builder.addValues(expr.toProto()) + builder.putFields(expr.key, expr.value.toProto(userDataReader)) } - return Value.newBuilder().setArrayValue(builder).build() + return Value.newBuilder().setMapValue(builder).build() } } +class ListOfExprs(private val expressions: Array) : Expr() { + override fun toProto(userDataReader: UserDataReader): Value = encodeValue(expressions.map{it.toProto(userDataReader)}) +} + open class Function protected constructor(private val name: String, private val params: Array) : Expr() { private constructor(name: String, param: Expr, vararg params: Any) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) @@ -738,11 +772,11 @@ protected constructor(private val name: String, private val params: Array) : fun not() = not(this) - fun countIf(): Accumulator = Accumulator.countIf(this) + fun countIf(): AggregateExpr = AggregateExpr.countIf(this) fun ifThen(then: Expr) = ifThen(this, then) @@ -786,12 +820,12 @@ class Ordering private constructor(private val expr: Expr, private val dir: Dire val DESCENDING = Direction("descending") } } - internal fun toProto(): Value = + internal fun toProto(userDataReader: UserDataReader): Value = Value.newBuilder() .setMapValue( MapValue.newBuilder() .putFields("direction", dir.proto) - .putFields("expression", expr.toProto()) + .putFields("expression", expr.toProto(userDataReader)) ) .build() } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index 81fc2ef7499..fa8026fb1ad 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -15,6 +15,7 @@ package com.google.firebase.firestore.pipeline import com.google.common.collect.ImmutableMap +import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.model.Values.encodeValue import com.google.firebase.firestore.model.Values.encodeVectorValue import com.google.firestore.v1.Pipeline @@ -23,58 +24,101 @@ import com.google.firestore.v1.Value abstract class Stage internal constructor(private val name: String, private val options: Map) { internal constructor(name: String) : this(name, emptyMap()) - internal fun toProtoStage(): Pipeline.Stage { + internal fun toProtoStage(userDataReader: UserDataReader): Pipeline.Stage { val builder = Pipeline.Stage.newBuilder() builder.setName(name) - args().forEach { arg -> builder.addArgs(arg) } + args(userDataReader).forEach { arg -> builder.addArgs(arg) } builder.putAllOptions(options) return builder.build() } - protected abstract fun args(): Sequence + protected abstract fun args(userDataReader: UserDataReader): Sequence +} + +class GenericStage internal constructor(name: String, private val params: List) : + Stage(name) { + override fun args(userDataReader: UserDataReader): Sequence = + params.asSequence().map { it.toProto(userDataReader) } +} + +internal sealed class GenericArg { + companion object { + fun from(arg: Any?): GenericArg = + when (arg) { + is AggregateExpr -> AggregateArg(arg) + is Ordering -> OrderingArg(arg) + is Map<*, *> -> MapArg(arg.asIterable().associate { it.key as String to from(it.value) }) + is List<*> -> ListArg(arg.map(::from)) + else -> ExprArg(Expr.toExprOrConstant(arg)) + } + } + abstract fun toProto(userDataReader: UserDataReader): Value + + data class AggregateArg(val aggregate: AggregateExpr) : GenericArg() { + override fun toProto(userDataReader: UserDataReader) = aggregate.toProto(userDataReader) + } + + data class ExprArg(val expr: Expr) : GenericArg() { + override fun toProto(userDataReader: UserDataReader) = expr.toProto(userDataReader) + } + + data class OrderingArg(val ordering: Ordering) : GenericArg() { + override fun toProto(userDataReader: UserDataReader) = ordering.toProto(userDataReader) + } + + data class MapArg(val args: Map) : GenericArg() { + override fun toProto(userDataReader: UserDataReader) = + encodeValue(args.mapValues { it.value.toProto(userDataReader) }) + } + + data class ListArg(val args: List) : GenericArg() { + override fun toProto(userDataReader: UserDataReader) = + encodeValue(args.map { it.toProto(userDataReader) }) + } } class DatabaseSource : Stage("database") { - override fun args(): Sequence = emptySequence() + override fun args(userDataReader: UserDataReader): Sequence = emptySequence() } class CollectionSource internal constructor(path: String) : Stage("collection") { private val path: String = if (path.startsWith("/")) path else "/" + path - override fun args(): Sequence = + override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setReferenceValue(path).build()) } class CollectionGroupSource internal constructor(val collectionId: String) : Stage("collection_group") { - override fun args(): Sequence = + override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setReferenceValue("").build(), encodeValue(collectionId)) } class DocumentsSource internal constructor(private val documents: Array) : Stage("documents") { - override fun args(): Sequence = documents.asSequence().map(::encodeValue) + override fun args(userDataReader: UserDataReader): Sequence = + documents.asSequence().map(::encodeValue) } class AddFieldsStage internal constructor(private val fields: Array) : Stage("add_fields") { - override fun args(): Sequence = - sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto() })) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) } class AggregateStage internal constructor( - private val accumulators: Map, + private val accumulators: Map, private val groups: Map ) : Stage("aggregate") { - private constructor(accumulators: Map) : this(accumulators, emptyMap()) + private constructor(accumulators: Map) : this(accumulators, emptyMap()) companion object { @JvmStatic - fun withAccumulators(vararg accumulators: AccumulatorWithAlias): AggregateStage { + fun withAccumulators(vararg accumulators: AggregateWithAlias): AggregateStage { if (accumulators.isEmpty()) { throw IllegalArgumentException( "Must specify at least one accumulator for aggregate() stage. There is a distinct() stage if only distinct group values are needed." ) } - return AggregateStage(accumulators.associate { it.alias to it.accumulator }) + return AggregateStage(accumulators.associate { it.alias to it.expr }) } } @@ -90,15 +134,16 @@ internal constructor( selectable.map(Selectable::toSelectable).associateBy(Selectable::getAlias) ) - override fun args(): Sequence = + override fun args(userDataReader: UserDataReader): Sequence = sequenceOf( - encodeValue(accumulators.mapValues { entry -> entry.value.toProto() }), - encodeValue(groups.mapValues { entry -> entry.value.toProto() }) + encodeValue(accumulators.mapValues { entry -> entry.value.toProto(userDataReader) }), + encodeValue(groups.mapValues { entry -> entry.value.toProto(userDataReader) }) ) } class WhereStage internal constructor(private val condition: BooleanExpr) : Stage("where") { - override fun args(): Sequence = sequenceOf(condition.toProto()) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(condition.toProto(userDataReader)) } class FindNearestStage @@ -118,8 +163,8 @@ internal constructor( } } - override fun args(): Sequence = - sequenceOf(property.toProto(), encodeVectorValue(vector), distanceMeasure.proto) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(property.toProto(userDataReader), encodeVectorValue(vector), distanceMeasure.proto) } class FindNearestOptions @@ -137,32 +182,36 @@ internal constructor(private val limit: Long?, private val distanceField: Field? } class LimitStage internal constructor(private val limit: Long) : Stage("limit") { - override fun args(): Sequence = sequenceOf(encodeValue(limit)) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(encodeValue(limit)) } class OffsetStage internal constructor(private val offset: Long) : Stage("offset") { - override fun args(): Sequence = sequenceOf(encodeValue(offset)) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(encodeValue(offset)) } class SelectStage internal constructor(private val fields: Array) : Stage("select") { - override fun args(): Sequence = - sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto() })) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) } class SortStage internal constructor(private val orders: Array) : Stage("sort") { - override fun args(): Sequence = orders.asSequence().map(Ordering::toProto) + override fun args(userDataReader: UserDataReader): Sequence = + orders.asSequence().map { it.toProto(userDataReader) } } class DistinctStage internal constructor(private val groups: Array) : Stage("distinct") { - override fun args(): Sequence = - sequenceOf(encodeValue(groups.associate { it.getAlias() to it.toProto() })) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(encodeValue(groups.associate { it.getAlias() to it.toProto(userDataReader) })) } class RemoveFieldsStage internal constructor(private val fields: Array) : Stage("remove_fields") { - override fun args(): Sequence = fields.asSequence().map(Field::toProto) + override fun args(userDataReader: UserDataReader): Sequence = + fields.asSequence().map(Field::toProto) } class ReplaceStage internal constructor(private val field: Selectable, private val mode: Mode) : @@ -175,7 +224,8 @@ class ReplaceStage internal constructor(private val field: Selectable, private v val MERGE_PREFER_PARENT = Mode("merge_prefer_parent") } } - override fun args(): Sequence = sequenceOf(field.toProto(), mode.proto) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(field.toProto(userDataReader), mode.proto) } class SampleStage internal constructor(private val size: Number, private val mode: Mode) : @@ -187,16 +237,17 @@ class SampleStage internal constructor(private val size: Number, private val mod val PERCENT = Mode("percent") } } - override fun args(): Sequence = sequenceOf(encodeValue(size), mode.proto) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(encodeValue(size), mode.proto) } class UnionStage internal constructor(private val other: com.google.firebase.firestore.Pipeline) : Stage("union") { - override fun args(): Sequence = + override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setPipelineValue(other.toPipelineProto()).build()) } class UnnestStage internal constructor(private val selectable: Selectable) : Stage("unnest") { - override fun args(): Sequence = - sequenceOf(encodeValue(selectable.getAlias()), selectable.toProto()) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf(encodeValue(selectable.getAlias()), selectable.toProto(userDataReader)) } From 6842a83387ab4d053563a1fe1004c1772643d91b Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 28 Feb 2025 15:04:31 -0500 Subject: [PATCH 22/77] Fix docStubs task --- .../firebase/firestore/CollectionReference.java | 2 +- .../firebase/firestore/FirebaseFirestore.java | 3 +-- .../com/google/firebase/firestore/Pipeline.kt | 15 +++++++++------ .../firebase/firestore/pipeline/expressions.kt | 9 +++++++++ .../google/firebase/firestore/pipeline/stage.kt | 2 +- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java index 297d018c9d6..8f4e1a00d79 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java @@ -131,6 +131,6 @@ public Task add(@NonNull Object data) { @NonNull public Pipeline pipeline() { - return new Pipeline(firestore, new CollectionSource(getPath())); + return new Pipeline(firestore, firestore.getUserDataReader(), new CollectionSource(getPath())); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java index 932be5983f5..c2c26447ec9 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java @@ -857,8 +857,7 @@ DatabaseId getDatabaseId() { } @NonNull - @RestrictTo(RestrictTo.Scope.LIBRARY) - public UserDataReader getUserDataReader() { + UserDataReader getUserDataReader() { return userDataReader; } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 6a3f765fd38..ccb20b24d12 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -49,15 +49,17 @@ import com.google.firestore.v1.Value class Pipeline internal constructor( internal val firestore: FirebaseFirestore, + internal val userDataReader: UserDataReader, private val stages: FluentIterable ) { internal constructor( firestore: FirebaseFirestore, + userDataReader: UserDataReader, stage: Stage - ) : this(firestore, FluentIterable.of(stage)) + ) : this(firestore, userDataReader, FluentIterable.of(stage)) private fun append(stage: Stage): Pipeline { - return Pipeline(firestore, stages.append(stage)) + return Pipeline(firestore, userDataReader, stages.append(stage)) } fun execute(): Task { @@ -86,7 +88,7 @@ internal constructor( internal fun toPipelineProto(): com.google.firestore.v1.Pipeline = com.google.firestore.v1.Pipeline.newBuilder() - .addAllStages(stages.map { it.toProtoStage(firestore.userDataReader) }) + .addAllStages(stages.map { it.toProtoStage(userDataReader) }) .build() fun genericStage(name: String, vararg params: Any) = @@ -167,7 +169,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto "Provided collection reference is from a different Firestore instance." ) } - return Pipeline(firestore, CollectionSource(ref.path)) + return Pipeline(firestore, firestore.userDataReader, CollectionSource(ref.path)) } fun collectionGroup(collectionId: String): Pipeline { @@ -175,10 +177,10 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto require(!collectionId.contains("/")) { "Invalid collectionId '$collectionId'. Collection IDs must not contain '/'." } - return Pipeline(firestore, CollectionGroupSource(collectionId)) + return Pipeline(firestore, firestore.userDataReader, CollectionGroupSource(collectionId)) } - fun database(): Pipeline = Pipeline(firestore, DatabaseSource()) + fun database(): Pipeline = Pipeline(firestore, firestore.userDataReader, DatabaseSource()) fun documents(vararg documents: String): Pipeline { // Validate document path by converting to DocumentReference @@ -196,6 +198,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto } return Pipeline( firestore, + firestore.userDataReader, DocumentsSource(documents.map { docRef -> "/" + docRef.path }.toTypedArray()) ) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index a4a6912fbce..8fb82718b69 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -363,6 +363,9 @@ protected constructor(private val name: String, private val params: Array) : internal constructor(name: String, param: Expr, vararg params: Any) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) internal constructor(name: String, fieldName: String, vararg params: Any) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) + companion object { + + @JvmStatic fun generic(name: String, vararg expr: Expr) = BooleanExpr(name, expr) + + } + fun not() = not(this) fun countIf(): AggregateExpr = AggregateExpr.countIf(this) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index fa8026fb1ad..82264a39ec3 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -31,7 +31,7 @@ internal constructor(private val name: String, private val options: Map + internal abstract fun args(userDataReader: UserDataReader): Sequence } class GenericStage internal constructor(name: String, private val params: List) : From 08af748e02b4934945bc1eaa20fb2b128da82bb3 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 28 Feb 2025 15:14:45 -0500 Subject: [PATCH 23/77] Spotless fix --- .../java/com/google/firebase/firestore/FirebaseFirestore.java | 1 - 1 file changed, 1 deletion(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java index c2c26447ec9..a2797e72399 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java @@ -23,7 +23,6 @@ import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RestrictTo; import androidx.annotation.VisibleForTesting; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; From fea5b06d1f1acc6318150c94aaf3f1a298bb6299 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 28 Feb 2025 16:14:20 -0500 Subject: [PATCH 24/77] Generate api.txt --- firebase-firestore/api.txt | 744 +++++++++++++++++- .../com/google/firebase/firestore/Pipeline.kt | 26 + 2 files changed, 769 insertions(+), 1 deletion(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index e3a55cf729c..a3aa673735e 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -54,6 +54,7 @@ package com.google.firebase.firestore { method public String getId(); method public com.google.firebase.firestore.DocumentReference? getParent(); method public String getPath(); + method public com.google.firebase.firestore.Pipeline pipeline(); } public class DocumentChange { @@ -72,7 +73,7 @@ package com.google.firebase.firestore { @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface DocumentId { } - public class DocumentReference { + public final class DocumentReference { method public com.google.firebase.firestore.ListenerRegistration addSnapshotListener(android.app.Activity, com.google.firebase.firestore.EventListener); method public com.google.firebase.firestore.ListenerRegistration addSnapshotListener(android.app.Activity, com.google.firebase.firestore.MetadataChanges, com.google.firebase.firestore.EventListener); method public com.google.firebase.firestore.ListenerRegistration addSnapshotListener(com.google.firebase.firestore.EventListener); @@ -85,6 +86,7 @@ package com.google.firebase.firestore { method public com.google.android.gms.tasks.Task get(); method public com.google.android.gms.tasks.Task get(com.google.firebase.firestore.Source); method public com.google.firebase.firestore.FirebaseFirestore getFirestore(); + method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public String getFullPath(); method public String getId(); method public com.google.firebase.firestore.CollectionReference getParent(); method public String getPath(); @@ -143,6 +145,7 @@ package com.google.firebase.firestore { public final class FieldPath { method public static com.google.firebase.firestore.FieldPath documentId(); + method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public static com.google.firebase.firestore.FieldPath fromDotSeparatedPath(String); method public static com.google.firebase.firestore.FieldPath of(java.lang.String!...!); } @@ -204,6 +207,7 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.LoadBundleTask loadBundle(byte[]); method public com.google.firebase.firestore.LoadBundleTask loadBundle(java.io.InputStream); method public com.google.firebase.firestore.LoadBundleTask loadBundle(java.nio.ByteBuffer); + method public com.google.firebase.firestore.PipelineSource pipeline(); method public com.google.android.gms.tasks.Task runBatch(com.google.firebase.firestore.WriteBatch.Function); method public com.google.android.gms.tasks.Task runTransaction(com.google.firebase.firestore.Transaction.Function); method public com.google.android.gms.tasks.Task runTransaction(com.google.firebase.firestore.TransactionOptions, com.google.firebase.firestore.Transaction.Function); @@ -416,6 +420,52 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.PersistentCacheSettings.Builder setSizeBytes(long); } + public final class Pipeline { + method public com.google.firebase.firestore.Pipeline addFields(com.google.firebase.firestore.pipeline.Selectable... fields); + method public com.google.firebase.firestore.Pipeline aggregate(com.google.firebase.firestore.pipeline.AggregateStage aggregateStage); + method public com.google.firebase.firestore.Pipeline aggregate(com.google.firebase.firestore.pipeline.AggregateWithAlias... accumulators); + method public com.google.firebase.firestore.Pipeline distinct(com.google.firebase.firestore.pipeline.Selectable... groups); + method public com.google.firebase.firestore.Pipeline distinct(java.lang.Object... groups); + method public com.google.firebase.firestore.Pipeline distinct(java.lang.String... groups); + method public com.google.android.gms.tasks.Task execute(); + method public com.google.firebase.firestore.Pipeline genericStage(String name, java.lang.Object... params); + method public com.google.firebase.firestore.Pipeline limit(long limit); + method public com.google.firebase.firestore.Pipeline offset(long offset); + method public com.google.firebase.firestore.Pipeline removeFields(com.google.firebase.firestore.pipeline.Field... fields); + method public com.google.firebase.firestore.Pipeline removeFields(java.lang.String... fields); + method public com.google.firebase.firestore.Pipeline replace(com.google.firebase.firestore.pipeline.Selectable field); + method public com.google.firebase.firestore.Pipeline replace(String field); + method public com.google.firebase.firestore.Pipeline sample(int documents); + method public com.google.firebase.firestore.Pipeline select(com.google.firebase.firestore.pipeline.Selectable... fields); + method public com.google.firebase.firestore.Pipeline select(java.lang.Object... fields); + method public com.google.firebase.firestore.Pipeline select(java.lang.String... fields); + method public com.google.firebase.firestore.Pipeline sort(com.google.firebase.firestore.pipeline.Ordering... orders); + method public com.google.firebase.firestore.Pipeline union(com.google.firebase.firestore.Pipeline other); + method public com.google.firebase.firestore.Pipeline unnest(com.google.firebase.firestore.pipeline.Selectable selectable); + method public com.google.firebase.firestore.Pipeline unnest(String field); + method public com.google.firebase.firestore.Pipeline where(com.google.firebase.firestore.pipeline.BooleanExpr condition); + } + + public final class PipelineResult { + method public java.util.Map getData(); + method public com.google.firebase.firestore.DocumentReference? getRef(); + property public final com.google.firebase.firestore.DocumentReference? ref; + } + + public final class PipelineSnapshot { + method public java.util.List getResults(); + property public final java.util.List results; + } + + public final class PipelineSource { + method public com.google.firebase.firestore.Pipeline collection(com.google.firebase.firestore.CollectionReference ref); + method public com.google.firebase.firestore.Pipeline collection(String path); + method public com.google.firebase.firestore.Pipeline collectionGroup(String collectionId); + method public com.google.firebase.firestore.Pipeline database(); + method public com.google.firebase.firestore.Pipeline documents(com.google.firebase.firestore.DocumentReference... documents); + method public com.google.firebase.firestore.Pipeline documents(java.lang.String... documents); + } + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD}) public @interface PropertyName { method public abstract String value(); } @@ -606,3 +656,695 @@ package com.google.firebase.firestore.ktx { } +package com.google.firebase.firestore.pipeline { + + public final class AddFieldsStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public final class AggregateExpr { + method public com.google.firebase.firestore.pipeline.AggregateWithAlias as(String alias); + method public static com.google.firebase.firestore.pipeline.AggregateExpr avg(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateExpr avg(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateExpr count(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateExpr count(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateExpr countAll(); + method public static com.google.firebase.firestore.pipeline.AggregateExpr countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); + method public static com.google.firebase.firestore.pipeline.AggregateExpr max(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateExpr max(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateExpr min(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateExpr min(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateExpr sum(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateExpr sum(String fieldName); + field public static final com.google.firebase.firestore.pipeline.AggregateExpr.Companion Companion; + } + + public static final class AggregateExpr.Companion { + method public com.google.firebase.firestore.pipeline.AggregateExpr avg(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateExpr avg(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateExpr count(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateExpr count(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateExpr countAll(); + method public com.google.firebase.firestore.pipeline.AggregateExpr countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); + method public com.google.firebase.firestore.pipeline.AggregateExpr max(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateExpr max(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateExpr min(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateExpr min(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateExpr sum(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateExpr sum(String fieldName); + } + + public final class AggregateStage extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.AggregateStage withAccumulators(com.google.firebase.firestore.pipeline.AggregateWithAlias... accumulators); + method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(com.google.firebase.firestore.pipeline.Selectable... groups); + method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(java.lang.Object... selectable); + method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(java.lang.String... fields); + field public static final com.google.firebase.firestore.pipeline.AggregateStage.Companion Companion; + } + + public static final class AggregateStage.Companion { + method public com.google.firebase.firestore.pipeline.AggregateStage withAccumulators(com.google.firebase.firestore.pipeline.AggregateWithAlias... accumulators); + } + + public final class AggregateWithAlias { + } + + public final class BooleanExpr extends com.google.firebase.firestore.pipeline.Function { + method public com.google.firebase.firestore.pipeline.AggregateExpr countIf(); + method public static com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.Expr then); + method public com.google.firebase.firestore.pipeline.Function ifThen(Object then); + method public com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr else); + method public com.google.firebase.firestore.pipeline.Function ifThenElse(Object then, Object else); + method public com.google.firebase.firestore.pipeline.BooleanExpr not(); + field public static final com.google.firebase.firestore.pipeline.BooleanExpr.Companion Companion; + } + + public static final class BooleanExpr.Companion { + method public com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + } + + public final class CollectionGroupSource extends com.google.firebase.firestore.pipeline.Stage { + method public String getCollectionId(); + property public final String collectionId; + } + + public final class CollectionSource extends com.google.firebase.firestore.pipeline.Stage { + } + + public abstract class Constant extends com.google.firebase.firestore.pipeline.Expr { + method public static final com.google.firebase.firestore.pipeline.Constant nullValue(); + method public static final com.google.firebase.firestore.pipeline.Constant of(boolean value); + method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.Blob value); + method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.DocumentReference ref); + method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.GeoPoint value); + method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.VectorValue value); + method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.Timestamp value); + method public static final com.google.firebase.firestore.pipeline.Constant of(Number value); + method public static final com.google.firebase.firestore.pipeline.Constant of(String value); + method public static final com.google.firebase.firestore.pipeline.Constant of(java.util.Date value); + method public static final com.google.firebase.firestore.pipeline.Constant vector(com.google.firebase.firestore.VectorValue value); + method public static final com.google.firebase.firestore.pipeline.Constant vector(double[] value); + field public static final com.google.firebase.firestore.pipeline.Constant.Companion Companion; + } + + public static final class Constant.Companion { + method public com.google.firebase.firestore.pipeline.Constant nullValue(); + method public com.google.firebase.firestore.pipeline.Constant of(boolean value); + method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.Blob value); + method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.DocumentReference ref); + method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.GeoPoint value); + method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.VectorValue value); + method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.Timestamp value); + method public com.google.firebase.firestore.pipeline.Constant of(Number value); + method public com.google.firebase.firestore.pipeline.Constant of(String value); + method public com.google.firebase.firestore.pipeline.Constant of(java.util.Date value); + method public com.google.firebase.firestore.pipeline.Constant vector(com.google.firebase.firestore.VectorValue value); + method public com.google.firebase.firestore.pipeline.Constant vector(double[] value); + } + + public final class DatabaseSource extends com.google.firebase.firestore.pipeline.Stage { + ctor public DatabaseSource(); + } + + public final class DistinctStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public final class DocumentsSource extends com.google.firebase.firestore.pipeline.Stage { + } + + public abstract class Expr { + method public final com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.Function add(Object other); + method public final com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr... arrays); + method public final com.google.firebase.firestore.pipeline.Function arrayConcat(java.util.List arrays); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr value); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(Object value); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(java.util.List values); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(java.util.List values); + method public final com.google.firebase.firestore.pipeline.Function arrayLength(); + method public final com.google.firebase.firestore.pipeline.Function arrayReverse(); + method public com.google.firebase.firestore.pipeline.ExprWithAlias as(String alias); + method public final com.google.firebase.firestore.pipeline.Ordering ascending(); + method public final com.google.firebase.firestore.pipeline.AggregateExpr avg(); + method public final com.google.firebase.firestore.pipeline.Function byteLength(); + method public final com.google.firebase.firestore.pipeline.Function charLength(); + method public final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector); + method public final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.VectorValue vector); + method public final com.google.firebase.firestore.pipeline.Function cosineDistance(double[] vector); + method public final com.google.firebase.firestore.pipeline.Ordering descending(); + method public final com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.Function divide(Object other); + method public final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector); + method public final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.VectorValue vector); + method public final com.google.firebase.firestore.pipeline.Function dotProduct(double[] vector); + method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr suffix); + method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String suffix); + method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(Object other); + method public final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector); + method public final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.VectorValue vector); + method public final com.google.firebase.firestore.pipeline.Function euclideanDistance(double[] vector); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(Object other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(Object other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr inAny(java.util.List values); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isNan(); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isNull(); + method public final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr pattern); + method public final com.google.firebase.firestore.pipeline.BooleanExpr like(String pattern); + method public final com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.Function logicalMax(Object other); + method public final com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.Function logicalMin(Object other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(Object other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(Object other); + method public final com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr key); + method public final com.google.firebase.firestore.pipeline.Function mapGet(String key); + method public final com.google.firebase.firestore.pipeline.AggregateExpr max(); + method public final com.google.firebase.firestore.pipeline.AggregateExpr min(); + method public final com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.Function mod(Object other); + method public final com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.Function multiply(Object other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(Object other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr notInAny(java.util.List values); + method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr pattern); + method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String pattern); + method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr pattern); + method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String pattern); + method public final com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public final com.google.firebase.firestore.pipeline.Function replaceAll(String find, String replace); + method public final com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public final com.google.firebase.firestore.pipeline.Function replaceFirst(String find, String replace); + method public final com.google.firebase.firestore.pipeline.Function reverse(); + method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr prefix); + method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String prefix); + method public final com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr... expr); + method public final com.google.firebase.firestore.pipeline.Function strConcat(java.lang.Object... string); + method public final com.google.firebase.firestore.pipeline.Function strConcat(java.lang.String... string); + method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr substring); + method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String substring); + method public final com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.Function subtract(Object other); + method public final com.google.firebase.firestore.pipeline.AggregateExpr sum(); + method public final com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public final com.google.firebase.firestore.pipeline.Function timestampAdd(String unit, double amount); + method public final com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public final com.google.firebase.firestore.pipeline.Function timestampSub(String unit, double amount); + method public final com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(); + method public final com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(); + method public final com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(); + method public final com.google.firebase.firestore.pipeline.Function toLower(); + method public final com.google.firebase.firestore.pipeline.Function toUpper(); + method public final com.google.firebase.firestore.pipeline.Function trim(); + method public final com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(); + method public final com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(); + method public final com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(); + method public final com.google.firebase.firestore.pipeline.Function vectorLength(); + } + + public class ExprWithAlias extends com.google.firebase.firestore.pipeline.Selectable { + } + + public final class Field extends com.google.firebase.firestore.pipeline.Selectable { + method public static com.google.firebase.firestore.pipeline.Field of(com.google.firebase.firestore.FieldPath fieldPath); + method public static com.google.firebase.firestore.pipeline.Field of(String name); + field public static final com.google.firebase.firestore.pipeline.Field.Companion Companion; + } + + public static final class Field.Companion { + method public com.google.firebase.firestore.pipeline.Field of(com.google.firebase.firestore.FieldPath fieldPath); + method public com.google.firebase.firestore.pipeline.Field of(String name); + } + + public final class FindNearestOptions { + method public java.util.Map toProto(); + } + + public final class FindNearestStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public static final class FindNearestStage.DistanceMeasure { + field public static final com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure.Companion Companion; + } + + public static final class FindNearestStage.DistanceMeasure.Companion { + method public error.NonExistentClass getCOSINE(); + method public error.NonExistentClass getDOT_PRODUCT(); + method public error.NonExistentClass getEUCLIDEAN(); + property public final error.NonExistentClass COSINE; + property public final error.NonExistentClass DOT_PRODUCT; + property public final error.NonExistentClass EUCLIDEAN; + } + + public class Function extends com.google.firebase.firestore.pipeline.Expr { + ctor protected Function(String name, com.google.firebase.firestore.pipeline.Expr[] params); + method public static final com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Function add(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + method public static final com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); + method public static final com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); + method public static final com.google.firebase.firestore.pipeline.Function arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); + method public static final com.google.firebase.firestore.pipeline.Function arrayConcat(String fieldName, java.util.List arrays); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, Object value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String fieldName, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String fieldName, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.Function arrayLength(com.google.firebase.firestore.pipeline.Expr array); + method public static final com.google.firebase.firestore.pipeline.Function arrayLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function arrayReverse(com.google.firebase.firestore.pipeline.Expr array); + method public static final com.google.firebase.firestore.pipeline.Function arrayReverse(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function byteLength(com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.Function byteLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function charLength(com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.Function charLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Function divide(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public static final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public static final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public static final com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr suffix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, String suffix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr suffix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, String suffix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.Function generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then); + method public static final com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then); + method public static final com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr else); + method public static final com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object else); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr inAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr inAny(String fieldName, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNull(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNull(String fieldName); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, String pattern); + method public static final com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Function logicalMax(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Function logicalMin(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); + method public static final com.google.firebase.firestore.pipeline.Function mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.Function mapGet(String fieldName, String key); + method public static final com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Function mod(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Function multiply(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr not(com.google.firebase.firestore.pipeline.BooleanExpr condition); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr notInAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr notInAny(String fieldName, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr or(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, String pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, String pattern); + method public static final com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Function replaceAll(String fieldName, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Function replaceFirst(String fieldName, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Function reverse(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Function reverse(String fieldName); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr prefix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, String prefix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); + method public static final com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); + method public static final com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); + method public static final com.google.firebase.firestore.pipeline.Function strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); + method public static final com.google.firebase.firestore.pipeline.Function strConcat(String fieldName, java.lang.Object... rest); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr substring); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, String substring); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); + method public static final com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Function subtract(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.Function timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.Function timestampAdd(String fieldName, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.Function timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.Function timestampSub(String fieldName, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function toLower(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Function toLower(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function toUpper(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Function toUpper(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function trim(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Function trim(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function vectorLength(com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Function vectorLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + field public static final com.google.firebase.firestore.pipeline.Function.Companion Companion; + } + + public static final class Function.Companion { + method public com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Function add(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + method public com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); + method public com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); + method public com.google.firebase.firestore.pipeline.Function arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); + method public com.google.firebase.firestore.pipeline.Function arrayConcat(String fieldName, java.util.List arrays); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object value); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, Object value); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String fieldName, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String fieldName, java.util.List values); + method public com.google.firebase.firestore.pipeline.Function arrayLength(com.google.firebase.firestore.pipeline.Expr array); + method public com.google.firebase.firestore.pipeline.Function arrayLength(String fieldName); + method public com.google.firebase.firestore.pipeline.Function arrayReverse(com.google.firebase.firestore.pipeline.Expr array); + method public com.google.firebase.firestore.pipeline.Function arrayReverse(String fieldName); + method public com.google.firebase.firestore.pipeline.Function byteLength(com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.Function byteLength(String fieldName); + method public com.google.firebase.firestore.pipeline.Function charLength(com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.Function charLength(String fieldName); + method public com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Function divide(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr suffix); + method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, String suffix); + method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr suffix); + method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, String suffix); + method public com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.Function generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then); + method public com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then); + method public com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr else); + method public com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object else); + method public com.google.firebase.firestore.pipeline.BooleanExpr inAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr inAny(String fieldName, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); + method public com.google.firebase.firestore.pipeline.BooleanExpr isNull(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.BooleanExpr isNull(String fieldName); + method public com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, String pattern); + method public com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Function logicalMax(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Function logicalMin(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); + method public com.google.firebase.firestore.pipeline.Function mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.Function mapGet(String fieldName, String key); + method public com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Function mod(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Function multiply(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr not(com.google.firebase.firestore.pipeline.BooleanExpr condition); + method public com.google.firebase.firestore.pipeline.BooleanExpr notInAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr notInAny(String fieldName, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr or(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, String pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, String pattern); + method public com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public com.google.firebase.firestore.pipeline.Function replaceAll(String fieldName, String find, String replace); + method public com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public com.google.firebase.firestore.pipeline.Function replaceFirst(String fieldName, String find, String replace); + method public com.google.firebase.firestore.pipeline.Function reverse(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Function reverse(String fieldName); + method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr prefix); + method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, String prefix); + method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); + method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); + method public com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); + method public com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); + method public com.google.firebase.firestore.pipeline.Function strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); + method public com.google.firebase.firestore.pipeline.Function strConcat(String fieldName, java.lang.Object... rest); + method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr substring); + method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, String substring); + method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); + method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); + method public com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Function subtract(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public com.google.firebase.firestore.pipeline.Function timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.Function timestampAdd(String fieldName, String unit, double amount); + method public com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public com.google.firebase.firestore.pipeline.Function timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.Function timestampSub(String fieldName, String unit, double amount); + method public com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(String fieldName); + method public com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(String fieldName); + method public com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(String fieldName); + method public com.google.firebase.firestore.pipeline.Function toLower(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Function toLower(String fieldName); + method public com.google.firebase.firestore.pipeline.Function toUpper(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Function toUpper(String fieldName); + method public com.google.firebase.firestore.pipeline.Function trim(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Function trim(String fieldName); + method public com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(String fieldName); + method public com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(String fieldName); + method public com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(String fieldName); + method public com.google.firebase.firestore.pipeline.Function vectorLength(com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Function vectorLength(String fieldName); + method public com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + } + + public final class GenericStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public final class LimitStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public final class ListOfExprs extends com.google.firebase.firestore.pipeline.Expr { + ctor public ListOfExprs(com.google.firebase.firestore.pipeline.Expr[] expressions); + } + + public final class MapOfExpr extends com.google.firebase.firestore.pipeline.Expr { + ctor public MapOfExpr(java.util.Map expressions); + } + + public final class OffsetStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public final class Ordering { + method public static com.google.firebase.firestore.pipeline.Ordering ascending(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.Ordering ascending(String fieldName); + method public static com.google.firebase.firestore.pipeline.Ordering descending(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.Ordering descending(String fieldName); + field public static final com.google.firebase.firestore.pipeline.Ordering.Companion Companion; + } + + public static final class Ordering.Companion { + method public com.google.firebase.firestore.pipeline.Ordering ascending(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Ordering ascending(String fieldName); + method public com.google.firebase.firestore.pipeline.Ordering descending(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Ordering descending(String fieldName); + } + + public final class RemoveFieldsStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public final class ReplaceStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public static final class ReplaceStage.Mode { + field public static final com.google.firebase.firestore.pipeline.ReplaceStage.Mode.Companion Companion; + } + + public static final class ReplaceStage.Mode.Companion { + method public error.NonExistentClass getFULL_REPLACE(); + method public error.NonExistentClass getMERGE_PREFER_NEXT(); + method public error.NonExistentClass getMERGE_PREFER_PARENT(); + property public final error.NonExistentClass FULL_REPLACE; + property public final error.NonExistentClass MERGE_PREFER_NEXT; + property public final error.NonExistentClass MERGE_PREFER_PARENT; + } + + public final class SampleStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public static final class SampleStage.Mode { + field public static final com.google.firebase.firestore.pipeline.SampleStage.Mode.Companion Companion; + } + + public static final class SampleStage.Mode.Companion { + method public error.NonExistentClass getDOCUMENTS(); + method public error.NonExistentClass getPERCENT(); + property public final error.NonExistentClass DOCUMENTS; + property public final error.NonExistentClass PERCENT; + } + + public final class SelectStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public abstract class Selectable extends com.google.firebase.firestore.pipeline.Expr { + ctor public Selectable(); + } + + public final class SortStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public abstract class Stage { + } + + public final class UnionStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public final class UnnestStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public final class WhereStage extends com.google.firebase.firestore.pipeline.Stage { + } + +} + diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index ccb20b24d12..662563488fa 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -36,10 +36,14 @@ import com.google.firebase.firestore.pipeline.LimitStage import com.google.firebase.firestore.pipeline.OffsetStage import com.google.firebase.firestore.pipeline.Ordering import com.google.firebase.firestore.pipeline.RemoveFieldsStage +import com.google.firebase.firestore.pipeline.ReplaceStage +import com.google.firebase.firestore.pipeline.SampleStage import com.google.firebase.firestore.pipeline.SelectStage import com.google.firebase.firestore.pipeline.Selectable import com.google.firebase.firestore.pipeline.SortStage import com.google.firebase.firestore.pipeline.Stage +import com.google.firebase.firestore.pipeline.UnionStage +import com.google.firebase.firestore.pipeline.UnnestStage import com.google.firebase.firestore.pipeline.WhereStage import com.google.firebase.firestore.util.Preconditions import com.google.firestore.v1.ExecutePipelineRequest @@ -130,6 +134,28 @@ internal constructor( fun aggregate(aggregateStage: AggregateStage): Pipeline = append(aggregateStage) + // fun findNearest() + + fun replace(field: String): Pipeline = replace(Field.of(field)) + + fun replace(field: Selectable): Pipeline = + append(ReplaceStage(field, ReplaceStage.Mode.FULL_REPLACE)) + + fun sample(documents: Int): Pipeline = append(SampleStage(documents, SampleStage.Mode.DOCUMENTS)) + + // fun sample(options: SampleOptions): Pipeline + + fun union(other: Pipeline): Pipeline = append(UnionStage(other)) + + fun unnest(field: String): Pipeline = unnest(Field.of(field)) + + // fun unnest(field: String, options: UnnestOptions): Pipeline = unnest(Field.of(field), options) + + fun unnest(selectable: Selectable): Pipeline = append(UnnestStage(selectable)) + + // fun unnest(selectable: Selectable, options: UnnestOptions): Pipeline = + // append(UnnestStage(selectable)) + private inner class ObserverSnapshotTask : PipelineResultObserver { private val taskCompletionSource = TaskCompletionSource() private val results: ImmutableList.Builder = ImmutableList.builder() From 711b852d3258598ec55010884bab89d90f0a642e Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 28 Feb 2025 16:52:14 -0500 Subject: [PATCH 25/77] Make more of the API internal --- firebase-firestore/api.txt | 94 ------------------- .../firebase/firestore/pipeline/stage.kt | 45 ++++----- 2 files changed, 24 insertions(+), 115 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index a3aa673735e..6b9af468a9e 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -658,9 +658,6 @@ package com.google.firebase.firestore.ktx { package com.google.firebase.firestore.pipeline { - public final class AddFieldsStage extends com.google.firebase.firestore.pipeline.Stage { - } - public final class AggregateExpr { method public com.google.firebase.firestore.pipeline.AggregateWithAlias as(String alias); method public static com.google.firebase.firestore.pipeline.AggregateExpr avg(com.google.firebase.firestore.pipeline.Expr expr); @@ -723,14 +720,6 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); } - public final class CollectionGroupSource extends com.google.firebase.firestore.pipeline.Stage { - method public String getCollectionId(); - property public final String collectionId; - } - - public final class CollectionSource extends com.google.firebase.firestore.pipeline.Stage { - } - public abstract class Constant extends com.google.firebase.firestore.pipeline.Expr { method public static final com.google.firebase.firestore.pipeline.Constant nullValue(); method public static final com.google.firebase.firestore.pipeline.Constant of(boolean value); @@ -762,16 +751,6 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Constant vector(double[] value); } - public final class DatabaseSource extends com.google.firebase.firestore.pipeline.Stage { - ctor public DatabaseSource(); - } - - public final class DistinctStage extends com.google.firebase.firestore.pipeline.Stage { - } - - public final class DocumentsSource extends com.google.firebase.firestore.pipeline.Stage { - } - public abstract class Expr { method public final com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.Function add(Object other); @@ -885,22 +864,6 @@ package com.google.firebase.firestore.pipeline { method public java.util.Map toProto(); } - public final class FindNearestStage extends com.google.firebase.firestore.pipeline.Stage { - } - - public static final class FindNearestStage.DistanceMeasure { - field public static final com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure.Companion Companion; - } - - public static final class FindNearestStage.DistanceMeasure.Companion { - method public error.NonExistentClass getCOSINE(); - method public error.NonExistentClass getDOT_PRODUCT(); - method public error.NonExistentClass getEUCLIDEAN(); - property public final error.NonExistentClass COSINE; - property public final error.NonExistentClass DOT_PRODUCT; - property public final error.NonExistentClass EUCLIDEAN; - } - public class Function extends com.google.firebase.firestore.pipeline.Expr { ctor protected Function(String name, com.google.firebase.firestore.pipeline.Expr[] params); method public static final com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); @@ -1259,12 +1222,6 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); } - public final class GenericStage extends com.google.firebase.firestore.pipeline.Stage { - } - - public final class LimitStage extends com.google.firebase.firestore.pipeline.Stage { - } - public final class ListOfExprs extends com.google.firebase.firestore.pipeline.Expr { ctor public ListOfExprs(com.google.firebase.firestore.pipeline.Expr[] expressions); } @@ -1273,9 +1230,6 @@ package com.google.firebase.firestore.pipeline { ctor public MapOfExpr(java.util.Map expressions); } - public final class OffsetStage extends com.google.firebase.firestore.pipeline.Stage { - } - public final class Ordering { method public static com.google.firebase.firestore.pipeline.Ordering ascending(com.google.firebase.firestore.pipeline.Expr expr); method public static com.google.firebase.firestore.pipeline.Ordering ascending(String fieldName); @@ -1291,60 +1245,12 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Ordering descending(String fieldName); } - public final class RemoveFieldsStage extends com.google.firebase.firestore.pipeline.Stage { - } - - public final class ReplaceStage extends com.google.firebase.firestore.pipeline.Stage { - } - - public static final class ReplaceStage.Mode { - field public static final com.google.firebase.firestore.pipeline.ReplaceStage.Mode.Companion Companion; - } - - public static final class ReplaceStage.Mode.Companion { - method public error.NonExistentClass getFULL_REPLACE(); - method public error.NonExistentClass getMERGE_PREFER_NEXT(); - method public error.NonExistentClass getMERGE_PREFER_PARENT(); - property public final error.NonExistentClass FULL_REPLACE; - property public final error.NonExistentClass MERGE_PREFER_NEXT; - property public final error.NonExistentClass MERGE_PREFER_PARENT; - } - - public final class SampleStage extends com.google.firebase.firestore.pipeline.Stage { - } - - public static final class SampleStage.Mode { - field public static final com.google.firebase.firestore.pipeline.SampleStage.Mode.Companion Companion; - } - - public static final class SampleStage.Mode.Companion { - method public error.NonExistentClass getDOCUMENTS(); - method public error.NonExistentClass getPERCENT(); - property public final error.NonExistentClass DOCUMENTS; - property public final error.NonExistentClass PERCENT; - } - - public final class SelectStage extends com.google.firebase.firestore.pipeline.Stage { - } - public abstract class Selectable extends com.google.firebase.firestore.pipeline.Expr { ctor public Selectable(); } - public final class SortStage extends com.google.firebase.firestore.pipeline.Stage { - } - public abstract class Stage { } - public final class UnionStage extends com.google.firebase.firestore.pipeline.Stage { - } - - public final class UnnestStage extends com.google.firebase.firestore.pipeline.Stage { - } - - public final class WhereStage extends com.google.firebase.firestore.pipeline.Stage { - } - } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index 82264a39ec3..7e8ab87ee1b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -34,8 +34,8 @@ internal constructor(private val name: String, private val options: Map } -class GenericStage internal constructor(name: String, private val params: List) : - Stage(name) { +internal class GenericStage +internal constructor(name: String, private val params: List) : Stage(name) { override fun args(userDataReader: UserDataReader): Sequence = params.asSequence().map { it.toProto(userDataReader) } } @@ -76,29 +76,29 @@ internal sealed class GenericArg { } } -class DatabaseSource : Stage("database") { +internal class DatabaseSource : Stage("database") { override fun args(userDataReader: UserDataReader): Sequence = emptySequence() } -class CollectionSource internal constructor(path: String) : Stage("collection") { +internal class CollectionSource internal constructor(path: String) : Stage("collection") { private val path: String = if (path.startsWith("/")) path else "/" + path override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setReferenceValue(path).build()) } -class CollectionGroupSource internal constructor(val collectionId: String) : +internal class CollectionGroupSource internal constructor(val collectionId: String) : Stage("collection_group") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setReferenceValue("").build(), encodeValue(collectionId)) } -class DocumentsSource internal constructor(private val documents: Array) : +internal class DocumentsSource internal constructor(private val documents: Array) : Stage("documents") { override fun args(userDataReader: UserDataReader): Sequence = documents.asSequence().map(::encodeValue) } -class AddFieldsStage internal constructor(private val fields: Array) : +internal class AddFieldsStage internal constructor(private val fields: Array) : Stage("add_fields") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) @@ -141,12 +141,13 @@ internal constructor( ) } -class WhereStage internal constructor(private val condition: BooleanExpr) : Stage("where") { +internal class WhereStage internal constructor(private val condition: BooleanExpr) : + Stage("where") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(condition.toProto(userDataReader)) } -class FindNearestStage +internal class FindNearestStage internal constructor( private val property: Expr, private val vector: DoubleArray, @@ -181,41 +182,42 @@ internal constructor(private val limit: Long?, private val distanceField: Field? } } -class LimitStage internal constructor(private val limit: Long) : Stage("limit") { +internal class LimitStage internal constructor(private val limit: Long) : Stage("limit") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(limit)) } -class OffsetStage internal constructor(private val offset: Long) : Stage("offset") { +internal class OffsetStage internal constructor(private val offset: Long) : Stage("offset") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(offset)) } -class SelectStage internal constructor(private val fields: Array) : +internal class SelectStage internal constructor(private val fields: Array) : Stage("select") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) } -class SortStage internal constructor(private val orders: Array) : Stage("sort") { +internal class SortStage internal constructor(private val orders: Array) : + Stage("sort") { override fun args(userDataReader: UserDataReader): Sequence = orders.asSequence().map { it.toProto(userDataReader) } } -class DistinctStage internal constructor(private val groups: Array) : +internal class DistinctStage internal constructor(private val groups: Array) : Stage("distinct") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(groups.associate { it.getAlias() to it.toProto(userDataReader) })) } -class RemoveFieldsStage internal constructor(private val fields: Array) : +internal class RemoveFieldsStage internal constructor(private val fields: Array) : Stage("remove_fields") { override fun args(userDataReader: UserDataReader): Sequence = fields.asSequence().map(Field::toProto) } -class ReplaceStage internal constructor(private val field: Selectable, private val mode: Mode) : - Stage("replace") { +internal class ReplaceStage +internal constructor(private val field: Selectable, private val mode: Mode) : Stage("replace") { class Mode private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) companion object { @@ -228,7 +230,7 @@ class ReplaceStage internal constructor(private val field: Selectable, private v sequenceOf(field.toProto(userDataReader), mode.proto) } -class SampleStage internal constructor(private val size: Number, private val mode: Mode) : +internal class SampleStage internal constructor(private val size: Number, private val mode: Mode) : Stage("sample") { class Mode private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) @@ -241,13 +243,14 @@ class SampleStage internal constructor(private val size: Number, private val mod sequenceOf(encodeValue(size), mode.proto) } -class UnionStage internal constructor(private val other: com.google.firebase.firestore.Pipeline) : - Stage("union") { +internal class UnionStage +internal constructor(private val other: com.google.firebase.firestore.Pipeline) : Stage("union") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setPipelineValue(other.toPipelineProto()).build()) } -class UnnestStage internal constructor(private val selectable: Selectable) : Stage("unnest") { +internal class UnnestStage internal constructor(private val selectable: Selectable) : + Stage("unnest") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(selectable.getAlias()), selectable.toProto(userDataReader)) } From 1ccea4d91682e0c3a8c21285657d64ef727c20dd Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 28 Feb 2025 17:15:16 -0500 Subject: [PATCH 26/77] Make more of the API internal --- firebase-firestore/api.txt | 10 +--------- .../google/firebase/firestore/pipeline/expressions.kt | 6 +++--- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 6b9af468a9e..63d017b6288 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -846,7 +846,7 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Function vectorLength(); } - public class ExprWithAlias extends com.google.firebase.firestore.pipeline.Selectable { + public final class ExprWithAlias extends com.google.firebase.firestore.pipeline.Selectable { } public final class Field extends com.google.firebase.firestore.pipeline.Selectable { @@ -1222,14 +1222,6 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); } - public final class ListOfExprs extends com.google.firebase.firestore.pipeline.Expr { - ctor public ListOfExprs(com.google.firebase.firestore.pipeline.Expr[] expressions); - } - - public final class MapOfExpr extends com.google.firebase.firestore.pipeline.Expr { - ctor public MapOfExpr(java.util.Map expressions); - } - public final class Ordering { method public static com.google.firebase.firestore.pipeline.Ordering ascending(com.google.firebase.firestore.pipeline.Expr expr); method public static com.google.firebase.firestore.pipeline.Ordering ascending(String fieldName); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 8fb82718b69..cfe0d810454 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -309,7 +309,7 @@ abstract class Selectable : Expr() { } } -open class ExprWithAlias internal constructor(private val alias: String, private val expr: Expr) : +class ExprWithAlias internal constructor(private val alias: String, private val expr: Expr) : Selectable() { override fun getAlias() = alias override fun toProto(userDataReader: UserDataReader): Value = expr.toProto(userDataReader) @@ -344,7 +344,7 @@ class Field private constructor(private val fieldPath: ModelFieldPath) : Value.newBuilder().setFieldReferenceValue(fieldPath.canonicalString()).build() } -class MapOfExpr(private val expressions: Map) : Expr() { +internal class MapOfExpr(private val expressions: Map) : Expr() { override fun toProto(userDataReader: UserDataReader): Value { val builder = MapValue.newBuilder() for (expr in expressions) { @@ -354,7 +354,7 @@ class MapOfExpr(private val expressions: Map) : Expr() { } } -class ListOfExprs(private val expressions: Array) : Expr() { +internal class ListOfExprs(private val expressions: Array) : Expr() { override fun toProto(userDataReader: UserDataReader): Value = encodeValue(expressions.map{it.toProto(userDataReader)}) } From 9553abcacf2df421efa6f74b6bbfc5b20cfdb9d9 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 3 Mar 2025 12:19:16 -0500 Subject: [PATCH 27/77] Add options --- firebase-firestore/api.txt | 74 ++++++++++++++++- .../com/google/firebase/firestore/Pipeline.kt | 30 +++++-- .../firebase/firestore/pipeline/options.kt | 81 +++++++++++++++++++ .../firebase/firestore/pipeline/stage.kt | 65 ++++++++++----- 4 files changed, 219 insertions(+), 31 deletions(-) create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 63d017b6288..7a960e3061f 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -428,6 +428,8 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline distinct(java.lang.Object... groups); method public com.google.firebase.firestore.Pipeline distinct(java.lang.String... groups); method public com.google.android.gms.tasks.Task execute(); + method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Expr property, double[] vector, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Expr property, double[] vector, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure, com.google.firebase.firestore.pipeline.FindNearestOptions options); method public com.google.firebase.firestore.Pipeline genericStage(String name, java.lang.Object... params); method public com.google.firebase.firestore.Pipeline limit(long limit); method public com.google.firebase.firestore.Pipeline offset(long offset); @@ -435,6 +437,7 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline removeFields(java.lang.String... fields); method public com.google.firebase.firestore.Pipeline replace(com.google.firebase.firestore.pipeline.Selectable field); method public com.google.firebase.firestore.Pipeline replace(String field); + method public com.google.firebase.firestore.Pipeline sample(com.google.firebase.firestore.pipeline.SampleStage sample); method public com.google.firebase.firestore.Pipeline sample(int documents); method public com.google.firebase.firestore.Pipeline select(com.google.firebase.firestore.pipeline.Selectable... fields); method public com.google.firebase.firestore.Pipeline select(java.lang.Object... fields); @@ -442,7 +445,9 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline sort(com.google.firebase.firestore.pipeline.Ordering... orders); method public com.google.firebase.firestore.Pipeline union(com.google.firebase.firestore.Pipeline other); method public com.google.firebase.firestore.Pipeline unnest(com.google.firebase.firestore.pipeline.Selectable selectable); - method public com.google.firebase.firestore.Pipeline unnest(String field); + method public com.google.firebase.firestore.Pipeline unnest(com.google.firebase.firestore.pipeline.Selectable selectable, com.google.firebase.firestore.pipeline.UnnestOptions options); + method public com.google.firebase.firestore.Pipeline unnest(String field, String alias); + method public com.google.firebase.firestore.Pipeline unnest(String field, String alias, com.google.firebase.firestore.pipeline.UnnestOptions options); method public com.google.firebase.firestore.Pipeline where(com.google.firebase.firestore.pipeline.BooleanExpr condition); } @@ -658,6 +663,15 @@ package com.google.firebase.firestore.ktx { package com.google.firebase.firestore.pipeline { + public abstract class AbstractOptions> { + method public final T with(String key, boolean value); + method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); + method public final T with(String key, double value); + method protected final T with(String key, error.NonExistentClass value); + method public final T with(String key, String value); + method public final T with(String key, long value); + } + public final class AggregateExpr { method public com.google.firebase.firestore.pipeline.AggregateWithAlias as(String alias); method public static com.google.firebase.firestore.pipeline.AggregateExpr avg(com.google.firebase.firestore.pipeline.Expr expr); @@ -860,8 +874,31 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Field of(String name); } - public final class FindNearestOptions { - method public java.util.Map toProto(); + public final class FindNearestOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { + method public com.google.firebase.firestore.pipeline.FindNearestOptions withDistanceField(com.google.firebase.firestore.pipeline.Field distanceField); + method public com.google.firebase.firestore.pipeline.FindNearestOptions withDistanceField(String distanceField); + method public com.google.firebase.firestore.pipeline.FindNearestOptions withLimit(long limit); + field public static final com.google.firebase.firestore.pipeline.FindNearestOptions.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.FindNearestOptions DEFAULT; + } + + public static final class FindNearestOptions.Companion { + } + + public final class FindNearestStage extends com.google.firebase.firestore.pipeline.Stage { + } + + public static final class FindNearestStage.DistanceMeasure { + field public static final com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure.Companion Companion; + } + + public static final class FindNearestStage.DistanceMeasure.Companion { + method public error.NonExistentClass getCOSINE(); + method public error.NonExistentClass getDOT_PRODUCT(); + method public error.NonExistentClass getEUCLIDEAN(); + property public final error.NonExistentClass COSINE; + property public final error.NonExistentClass DOT_PRODUCT; + property public final error.NonExistentClass EUCLIDEAN; } public class Function extends com.google.firebase.firestore.pipeline.Expr { @@ -1237,6 +1274,28 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Ordering descending(String fieldName); } + public final class SampleStage extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.SampleStage withDocLimit(int documents); + method public static com.google.firebase.firestore.pipeline.SampleStage withPercentage(double percentage); + field public static final com.google.firebase.firestore.pipeline.SampleStage.Companion Companion; + } + + public static final class SampleStage.Companion { + method public com.google.firebase.firestore.pipeline.SampleStage withDocLimit(int documents); + method public com.google.firebase.firestore.pipeline.SampleStage withPercentage(double percentage); + } + + public static final class SampleStage.Mode { + field public static final com.google.firebase.firestore.pipeline.SampleStage.Mode.Companion Companion; + } + + public static final class SampleStage.Mode.Companion { + method public error.NonExistentClass getDOCUMENTS(); + method public error.NonExistentClass getPERCENT(); + property public final error.NonExistentClass DOCUMENTS; + property public final error.NonExistentClass PERCENT; + } + public abstract class Selectable extends com.google.firebase.firestore.pipeline.Expr { ctor public Selectable(); } @@ -1244,5 +1303,14 @@ package com.google.firebase.firestore.pipeline { public abstract class Stage { } + public final class UnnestOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { + method public com.google.firebase.firestore.pipeline.UnnestOptions withIndexField(String indexField); + field public static final com.google.firebase.firestore.pipeline.UnnestOptions.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.UnnestOptions DEFAULT; + } + + public static final class UnnestOptions.Companion { + } + } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 662563488fa..e88fc324c0d 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -29,7 +29,10 @@ import com.google.firebase.firestore.pipeline.CollectionSource import com.google.firebase.firestore.pipeline.DatabaseSource import com.google.firebase.firestore.pipeline.DistinctStage import com.google.firebase.firestore.pipeline.DocumentsSource +import com.google.firebase.firestore.pipeline.Expr import com.google.firebase.firestore.pipeline.Field +import com.google.firebase.firestore.pipeline.FindNearestOptions +import com.google.firebase.firestore.pipeline.FindNearestStage import com.google.firebase.firestore.pipeline.GenericArg import com.google.firebase.firestore.pipeline.GenericStage import com.google.firebase.firestore.pipeline.LimitStage @@ -43,6 +46,7 @@ import com.google.firebase.firestore.pipeline.Selectable import com.google.firebase.firestore.pipeline.SortStage import com.google.firebase.firestore.pipeline.Stage import com.google.firebase.firestore.pipeline.UnionStage +import com.google.firebase.firestore.pipeline.UnnestOptions import com.google.firebase.firestore.pipeline.UnnestStage import com.google.firebase.firestore.pipeline.WhereStage import com.google.firebase.firestore.util.Preconditions @@ -134,27 +138,39 @@ internal constructor( fun aggregate(aggregateStage: AggregateStage): Pipeline = append(aggregateStage) - // fun findNearest() + fun findNearest( + property: Expr, + vector: DoubleArray, + distanceMeasure: FindNearestStage.DistanceMeasure + ) = append(FindNearestStage(property, vector, distanceMeasure, FindNearestOptions.DEFAULT)) + + fun findNearest( + property: Expr, + vector: DoubleArray, + distanceMeasure: FindNearestStage.DistanceMeasure, + options: FindNearestOptions + ) = append(FindNearestStage(property, vector, distanceMeasure, options)) fun replace(field: String): Pipeline = replace(Field.of(field)) fun replace(field: Selectable): Pipeline = append(ReplaceStage(field, ReplaceStage.Mode.FULL_REPLACE)) - fun sample(documents: Int): Pipeline = append(SampleStage(documents, SampleStage.Mode.DOCUMENTS)) + fun sample(documents: Int): Pipeline = append(SampleStage.withDocLimit(documents)) - // fun sample(options: SampleOptions): Pipeline + fun sample(sample: SampleStage): Pipeline = append(sample) fun union(other: Pipeline): Pipeline = append(UnionStage(other)) - fun unnest(field: String): Pipeline = unnest(Field.of(field)) + fun unnest(field: String, alias: String): Pipeline = unnest(Field.of(field).`as`(alias)) - // fun unnest(field: String, options: UnnestOptions): Pipeline = unnest(Field.of(field), options) + fun unnest(field: String, alias: String, options: UnnestOptions): Pipeline = + unnest(Field.of(field).`as`(alias), options) fun unnest(selectable: Selectable): Pipeline = append(UnnestStage(selectable)) - // fun unnest(selectable: Selectable, options: UnnestOptions): Pipeline = - // append(UnnestStage(selectable)) + fun unnest(selectable: Selectable, options: UnnestOptions): Pipeline = + append(UnnestStage(selectable)) private inner class ObserverSnapshotTask : PipelineResultObserver { private val taskCompletionSource = TaskCompletionSource() diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt new file mode 100644 index 00000000000..5695a9dff91 --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt @@ -0,0 +1,81 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.firestore.pipeline + +import com.google.common.collect.ImmutableMap +import com.google.firebase.firestore.model.Values +import com.google.firestore.v1.ArrayValue +import com.google.firestore.v1.MapValue +import com.google.firestore.v1.Value + +/** + * Wither style Key/Value options object. + * + * Basic `wither` functionality built upon `ImmutableMap, Value>`. Exposes methods + * to construct, augment, and encode Kay/Value pairs. The wrapped collection + * `ImmutableMap, Value>` is an implementation detail, not to be exposed, since + * more efficient implementations are possible. + */ +internal class InternalOptions +internal constructor(private val options: ImmutableMap) { + internal fun with(key: String, value: Value): InternalOptions { + val builder = ImmutableMap.builderWithExpectedSize(options.size + 1) + builder.putAll(options) + builder.put(key, value) + return InternalOptions(builder.buildKeepingLast()) + } + + internal fun with(key: String, values: Iterable): InternalOptions { + val arrayValue = ArrayValue.newBuilder().addAllValues(values).build() + return with(key, Value.newBuilder().setArrayValue(arrayValue).build()) + } + + internal fun with(key: String, value: InternalOptions): InternalOptions { + return with(key, value.toValue()) + } + + internal fun forEach(f: (String, Value) -> Unit) = options.forEach(f) + + private fun toValue(): Value { + val mapValue = MapValue.newBuilder().putAllFields(options).build() + return Value.newBuilder().setMapValue(mapValue).build() + } + + internal companion object { + internal val EMPTY: InternalOptions = InternalOptions(ImmutableMap.of()) + + internal fun of(key: String, value: Value): InternalOptions { + return InternalOptions(ImmutableMap.of(key, value)) + } + } +} + +abstract class AbstractOptions> +internal constructor(internal val options: InternalOptions) { + + internal abstract fun self(options: InternalOptions): T + + protected fun with(key: String, value: Value): T = self(options.with(key, value)) + + fun with(key: String, value: String): T = with(key, Values.encodeValue(value)) + + fun with(key: String, value: Boolean): T = with(key, Values.encodeValue(value)) + + fun with(key: String, value: Long): T = with(key, Values.encodeValue(value)) + + fun with(key: String, value: Double): T = with(key, Values.encodeValue(value)) + + fun with(key: String, value: Field): T = with(key, value.toProto()) +} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index 7e8ab87ee1b..b1477409eda 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -14,21 +14,22 @@ package com.google.firebase.firestore.pipeline -import com.google.common.collect.ImmutableMap import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.model.Values.encodeValue import com.google.firebase.firestore.model.Values.encodeVectorValue +import com.google.firebase.firestore.pipeline.Field.Companion.of import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value abstract class Stage -internal constructor(private val name: String, private val options: Map) { - internal constructor(name: String) : this(name, emptyMap()) +private constructor(private val name: String, private val options: InternalOptions) { + internal constructor(name: String) : this(name, InternalOptions.EMPTY) + internal constructor(name: String, options: AbstractOptions<*>) : this(name, options.options) internal fun toProtoStage(userDataReader: UserDataReader): Pipeline.Stage { val builder = Pipeline.Stage.newBuilder() builder.setName(name) args(userDataReader).forEach { arg -> builder.addArgs(arg) } - builder.putAllOptions(options) + options.forEach(builder::putOptions) return builder.build() } internal abstract fun args(userDataReader: UserDataReader): Sequence @@ -147,13 +148,13 @@ internal class WhereStage internal constructor(private val condition: BooleanExp sequenceOf(condition.toProto(userDataReader)) } -internal class FindNearestStage +class FindNearestStage internal constructor( private val property: Expr, private val vector: DoubleArray, private val distanceMeasure: DistanceMeasure, - private val options: FindNearestOptions -) : Stage("find_nearest", options.toProto()) { + options: FindNearestOptions +) : Stage("find_nearest", options) { class DistanceMeasure private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) @@ -168,18 +169,21 @@ internal constructor( sequenceOf(property.toProto(userDataReader), encodeVectorValue(vector), distanceMeasure.proto) } -class FindNearestOptions -internal constructor(private val limit: Long?, private val distanceField: Field?) { - fun toProto(): Map { - val builder = ImmutableMap.builder() - if (limit != null) { - builder.put("limit", encodeValue(limit)) - } - if (distanceField != null) { - builder.put("distance_field", distanceField.toProto()) - } - return builder.build() +class FindNearestOptions private constructor(options: InternalOptions) : + AbstractOptions(options) { + companion object { + @JvmField val DEFAULT = FindNearestOptions(InternalOptions.EMPTY) } + + override fun self(options: InternalOptions): FindNearestOptions = FindNearestOptions(options) + + fun withLimit(limit: Long): FindNearestOptions = with("limit", limit) + + fun withDistanceField(distanceField: Field): FindNearestOptions = + with("distance_field", distanceField) + + fun withDistanceField(distanceField: String): FindNearestOptions = + withDistanceField(of(distanceField)) } internal class LimitStage internal constructor(private val limit: Long) : Stage("limit") { @@ -230,7 +234,7 @@ internal constructor(private val field: Selectable, private val mode: Mode) : St sequenceOf(field.toProto(userDataReader), mode.proto) } -internal class SampleStage internal constructor(private val size: Number, private val mode: Mode) : +class SampleStage private constructor(private val size: Number, private val mode: Mode) : Stage("sample") { class Mode private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) @@ -239,6 +243,11 @@ internal class SampleStage internal constructor(private val size: Number, privat val PERCENT = Mode("percent") } } + companion object { + @JvmStatic fun withPercentage(percentage: Double) = SampleStage(percentage, Mode.PERCENT) + + @JvmStatic fun withDocLimit(documents: Int) = SampleStage(documents, Mode.DOCUMENTS) + } override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(size), mode.proto) } @@ -249,8 +258,22 @@ internal constructor(private val other: com.google.firebase.firestore.Pipeline) sequenceOf(Value.newBuilder().setPipelineValue(other.toPipelineProto()).build()) } -internal class UnnestStage internal constructor(private val selectable: Selectable) : - Stage("unnest") { +internal class UnnestStage +internal constructor(private val selectable: Selectable, options: UnnestOptions) : + Stage("unnest", options) { + internal constructor(selectable: Selectable) : this(selectable, UnnestOptions.DEFAULT) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(selectable.getAlias()), selectable.toProto(userDataReader)) } + +class UnnestOptions private constructor(options: InternalOptions) : + AbstractOptions(options) { + + fun withIndexField(indexField: String): UnnestOptions = with("index_field", indexField) + + override fun self(options: InternalOptions) = UnnestOptions(options) + + companion object { + @JvmField val DEFAULT: UnnestOptions = UnnestOptions(InternalOptions.EMPTY) + } +} From b2f0b3f8d6432dcc915138ed48575617d22272a3 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 3 Mar 2025 15:09:27 -0500 Subject: [PATCH 28/77] GenericOptions --- .../firebase/firestore/PipelineTest.java | 3 ++- .../com/google/firebase/firestore/Pipeline.kt | 6 +++-- .../firebase/firestore/pipeline/stage.kt | 26 ++++++++++++++++--- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 50df7ef880d..7498bfccff2 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -48,6 +48,7 @@ import com.google.firebase.firestore.pipeline.Constant; import com.google.firebase.firestore.pipeline.Field; import com.google.firebase.firestore.pipeline.Function; +import com.google.firebase.firestore.pipeline.GenericStage; import com.google.firebase.firestore.testutil.IntegrationTestUtil; import java.util.Collections; import java.util.LinkedHashMap; @@ -284,7 +285,7 @@ public void groupAndAccumulateResultsGeneric() { "aggregate", ImmutableMap.of("avgRating", AggregateExpr.avg("rating")), ImmutableMap.of("genre", Field.of("genre"))) - .genericStage("where", gt("avgRating", 4.3)) + .genericStage(GenericStage.of("where").withArguments(gt("avgRating", 4.3))) .genericStage("sort", Field.of("avgRating").descending()) .execute(); assertThat(waitFor(execute).getResults()) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index e88fc324c0d..29b81683b61 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -99,8 +99,10 @@ internal constructor( .addAllStages(stages.map { it.toProtoStage(userDataReader) }) .build() - fun genericStage(name: String, vararg params: Any) = - append(GenericStage(name, params.map(GenericArg::from))) + fun genericStage(name: String, vararg arguments: Any): Pipeline = + append(GenericStage(name, arguments.map(GenericArg::from))) + + fun genericStage(stage: GenericStage): Pipeline = append(stage) fun addFields(vararg fields: Selectable): Pipeline = append(AddFieldsStage(fields)) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index b1477409eda..7ab8ec02b07 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -22,7 +22,7 @@ import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value abstract class Stage -private constructor(private val name: String, private val options: InternalOptions) { +private constructor(protected val name: String, private val options: InternalOptions) { internal constructor(name: String) : this(name, InternalOptions.EMPTY) internal constructor(name: String, options: AbstractOptions<*>) : this(name, options.options) internal fun toProtoStage(userDataReader: UserDataReader): Pipeline.Stage { @@ -35,10 +35,20 @@ private constructor(private val name: String, private val options: InternalOptio internal abstract fun args(userDataReader: UserDataReader): Sequence } -internal class GenericStage -internal constructor(name: String, private val params: List) : Stage(name) { +class GenericStage +private constructor(name: String, private val arguments: List, private val options: GenericOptions) : Stage(name, options) { + internal constructor(name: String, arguments: List) : this(name, arguments, GenericOptions.DEFAULT) + companion object { + @JvmStatic + fun of(name: String) = GenericStage(name, emptyList()) + } + + fun withArguments(vararg arguments: Any): GenericStage = GenericStage(name, arguments.map(GenericArg::from), options) + + fun withOptions(options: GenericOptions): GenericStage = GenericStage(name, arguments, options) + override fun args(userDataReader: UserDataReader): Sequence = - params.asSequence().map { it.toProto(userDataReader) } + arguments.asSequence().map { it.toProto(userDataReader) } } internal sealed class GenericArg { @@ -77,6 +87,14 @@ internal sealed class GenericArg { } } +class GenericOptions private constructor(options: InternalOptions) : AbstractOptions(options) { + companion object { + @JvmField + val DEFAULT = GenericOptions(InternalOptions.EMPTY) + } + override fun self(options: InternalOptions) = GenericOptions(options) +} + internal class DatabaseSource : Stage("database") { override fun args(userDataReader: UserDataReader): Sequence = emptySequence() } From 5e8f7f024a604a4dc8c6c07c17dcc772e2c7205c Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 3 Mar 2025 15:37:48 -0500 Subject: [PATCH 29/77] Spotless --- firebase-firestore/CHANGELOG.md | 2 +- firebase-firestore/api.txt | 24 ++++++++++++++++++- .../testutil/IntegrationTestUtil.java | 2 +- .../firebase/firestore/pipeline/stage.kt | 23 +++++++++++------- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/firebase-firestore/CHANGELOG.md b/firebase-firestore/CHANGELOG.md index 66fce5b35ce..d2f756372e9 100644 --- a/firebase-firestore/CHANGELOG.md +++ b/firebase-firestore/CHANGELOG.md @@ -1,5 +1,5 @@ # Unreleased - +* [feature] Pipelines # 25.1.2 * [fixed] Fixed a server and sdk mismatch in unicode string sorting. [#6615](//github.com/firebase/firebase-android-sdk/pull/6615) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 7a960e3061f..db0a902420e 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -430,7 +430,8 @@ package com.google.firebase.firestore { method public com.google.android.gms.tasks.Task execute(); method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Expr property, double[] vector, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Expr property, double[] vector, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure, com.google.firebase.firestore.pipeline.FindNearestOptions options); - method public com.google.firebase.firestore.Pipeline genericStage(String name, java.lang.Object... params); + method public com.google.firebase.firestore.Pipeline genericStage(com.google.firebase.firestore.pipeline.GenericStage stage); + method public com.google.firebase.firestore.Pipeline genericStage(String name, java.lang.Object... arguments); method public com.google.firebase.firestore.Pipeline limit(long limit); method public com.google.firebase.firestore.Pipeline offset(long offset); method public com.google.firebase.firestore.Pipeline removeFields(com.google.firebase.firestore.pipeline.Field... fields); @@ -1259,6 +1260,25 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); } + public final class GenericOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { + field public static final com.google.firebase.firestore.pipeline.GenericOptions.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.GenericOptions DEFAULT; + } + + public static final class GenericOptions.Companion { + } + + public final class GenericStage extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.GenericStage of(String name); + method public com.google.firebase.firestore.pipeline.GenericStage withArguments(java.lang.Object... arguments); + method public com.google.firebase.firestore.pipeline.GenericStage withOptions(com.google.firebase.firestore.pipeline.GenericOptions options); + field public static final com.google.firebase.firestore.pipeline.GenericStage.Companion Companion; + } + + public static final class GenericStage.Companion { + method public com.google.firebase.firestore.pipeline.GenericStage of(String name); + } + public final class Ordering { method public static com.google.firebase.firestore.pipeline.Ordering ascending(com.google.firebase.firestore.pipeline.Expr expr); method public static com.google.firebase.firestore.pipeline.Ordering ascending(String fieldName); @@ -1301,6 +1321,8 @@ package com.google.firebase.firestore.pipeline { } public abstract class Stage { + method protected final String getName(); + property protected final String name; } public final class UnnestOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java index a7417d96563..d11c27828cf 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java @@ -98,7 +98,7 @@ public enum TargetBackend { // Set this to the desired enum value to change the target backend when running tests locally. // Note: DO NOT change this variable except for local testing. - private static final TargetBackend backendForLocalTesting = null; + private static final TargetBackend backendForLocalTesting = TargetBackend.NIGHTLY; private static final TargetBackend backend = getTargetBackend(); private static final String EMULATOR_HOST = "10.0.2.2"; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index 7ab8ec02b07..e4b0345f662 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -36,14 +36,21 @@ private constructor(protected val name: String, private val options: InternalOpt } class GenericStage -private constructor(name: String, private val arguments: List, private val options: GenericOptions) : Stage(name, options) { - internal constructor(name: String, arguments: List) : this(name, arguments, GenericOptions.DEFAULT) +private constructor( + name: String, + private val arguments: List, + private val options: GenericOptions +) : Stage(name, options) { + internal constructor( + name: String, + arguments: List + ) : this(name, arguments, GenericOptions.DEFAULT) companion object { - @JvmStatic - fun of(name: String) = GenericStage(name, emptyList()) + @JvmStatic fun of(name: String) = GenericStage(name, emptyList()) } - fun withArguments(vararg arguments: Any): GenericStage = GenericStage(name, arguments.map(GenericArg::from), options) + fun withArguments(vararg arguments: Any): GenericStage = + GenericStage(name, arguments.map(GenericArg::from), options) fun withOptions(options: GenericOptions): GenericStage = GenericStage(name, arguments, options) @@ -87,10 +94,10 @@ internal sealed class GenericArg { } } -class GenericOptions private constructor(options: InternalOptions) : AbstractOptions(options) { +class GenericOptions private constructor(options: InternalOptions) : + AbstractOptions(options) { companion object { - @JvmField - val DEFAULT = GenericOptions(InternalOptions.EMPTY) + @JvmField val DEFAULT = GenericOptions(InternalOptions.EMPTY) } override fun self(options: InternalOptions) = GenericOptions(options) } From 8d049e061091f00992ae6d94a48f14748b56e8ef Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Wed, 19 Mar 2025 11:51:49 -0400 Subject: [PATCH 30/77] Bit Operators --- .../firestore/pipeline/expressions.kt | 404 ++++++++++++------ 1 file changed, 276 insertions(+), 128 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index cfe0d810454..401aa2ff20a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -22,6 +22,7 @@ import com.google.firebase.firestore.GeoPoint import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.VectorValue import com.google.firebase.firestore.model.DocumentKey +import com.google.firebase.firestore.model.FieldPath as ModelFieldPath import com.google.firebase.firestore.model.Values.encodeValue import com.google.firebase.firestore.pipeline.Constant.Companion.of import com.google.firebase.firestore.util.CustomClassMapper @@ -29,13 +30,16 @@ import com.google.firestore.v1.MapValue import com.google.firestore.v1.Value import java.util.Date import kotlin.reflect.KFunction1 -import com.google.firebase.firestore.model.FieldPath as ModelFieldPath abstract class Expr internal constructor() { internal companion object { - internal fun toExprOrConstant(value: Any?): Expr = toExpr(value, ::toExprOrConstant) ?: pojoToExprOrConstant(CustomClassMapper.convertToPlainJavaTypes(value)) + internal fun toExprOrConstant(value: Any?): Expr = + toExpr(value, ::toExprOrConstant) + ?: pojoToExprOrConstant(CustomClassMapper.convertToPlainJavaTypes(value)) - private fun pojoToExprOrConstant(value: Any?): Expr = toExpr(value, ::pojoToExprOrConstant) ?: throw IllegalArgumentException("Unknown type: $value") + private fun pojoToExprOrConstant(value: Any?): Expr = + toExpr(value, ::pojoToExprOrConstant) + ?: throw IllegalArgumentException("Unknown type: $value") private fun toExpr(value: Any?, toExpr: KFunction1): Expr? { if (value == null) return Constant.nullValue() @@ -50,11 +54,15 @@ abstract class Expr internal constructor() { is Blob -> of(value) is DocumentReference -> of(value) is VectorValue -> of(value) - is Map<*, *> -> MapOfExpr(value.entries.associate { - val key = it.key - if (key is String) key to toExpr(it.value) else - throw IllegalArgumentException("Maps with non-string keys are not supported") - }) + is Value -> of(value) + is Map<*, *> -> + MapOfExpr( + value.entries.associate { + val key = it.key + if (key is String) key to toExpr(it.value) + else throw IllegalArgumentException("Maps with non-string keys are not supported") + } + ) is List<*> -> ListOfExprs(value.map(toExpr).toTypedArray()) else -> null } @@ -67,6 +75,28 @@ abstract class Expr internal constructor() { others.map(::toExprOrConstant).toTypedArray() } + fun bitAnd(right: Expr) = Function.bitAnd(this, right) + + fun bitAnd(right: Any) = Function.bitAnd(this, right) + + fun bitOr(right: Expr) = Function.bitOr(this, right) + + fun bitOr(right: Any) = Function.bitOr(this, right) + + fun bitXor(right: Expr) = Function.bitXor(this, right) + + fun bitXor(right: Any) = Function.bitXor(this, right) + + fun bitNot() = Function.bitNot(this) + + fun bitLeftShift(numberExpr: Expr) = Function.bitLeftShift(this, numberExpr) + + fun bitLeftShift(number: Int) = Function.bitLeftShift(this, number) + + fun bitRightShift(numberExpr: Expr) = Function.bitRightShift(this, numberExpr) + + fun bitRightShift(number: Int) = Function.bitRightShift(this, number) + /** * Assigns an alias to this expression. * @@ -291,6 +321,8 @@ abstract class Expr internal constructor() { fun lte(other: Any) = Function.lte(this, other) + fun exists() = Function.exists(this) + internal abstract fun toProto(userDataReader: UserDataReader): Value } @@ -315,8 +347,7 @@ class ExprWithAlias internal constructor(private val alias: String, private val override fun toProto(userDataReader: UserDataReader): Value = expr.toProto(userDataReader) } -class Field private constructor(private val fieldPath: ModelFieldPath) : - Selectable() { +class Field internal constructor(private val fieldPath: ModelFieldPath) : Selectable() { companion object { @JvmStatic @@ -329,9 +360,6 @@ class Field private constructor(private val fieldPath: ModelFieldPath) : @JvmStatic fun of(fieldPath: FieldPath): Field { - if (fieldPath == FieldPath.documentId()) { - return Field(FieldPath.documentId().internalPath) - } return Field(fieldPath.internalPath) } } @@ -347,36 +375,102 @@ class Field private constructor(private val fieldPath: ModelFieldPath) : internal class MapOfExpr(private val expressions: Map) : Expr() { override fun toProto(userDataReader: UserDataReader): Value { val builder = MapValue.newBuilder() - for (expr in expressions) { - builder.putFields(expr.key, expr.value.toProto(userDataReader)) + for ((key, value) in expressions) { + builder.putFields(key, value.toProto(userDataReader)) } return Value.newBuilder().setMapValue(builder).build() } } internal class ListOfExprs(private val expressions: Array) : Expr() { - override fun toProto(userDataReader: UserDataReader): Value = encodeValue(expressions.map{it.toProto(userDataReader)}) + override fun toProto(userDataReader: UserDataReader): Value = + encodeValue(expressions.map { it.toProto(userDataReader) }) } open class Function protected constructor(private val name: String, private val params: Array) : Expr() { - private constructor(name: String, param: Expr, vararg params: Any) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) - private constructor(name: String, fieldName: String, vararg params: Any) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) + private constructor( + name: String, + param: Expr, + vararg params: Any + ) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) + private constructor( + name: String, + fieldName: String, + vararg params: Any + ) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) companion object { @JvmStatic fun generic(name: String, vararg expr: Expr) = Function(name, expr) @JvmStatic - fun and(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("and", condition, *conditions) + fun and(condition: BooleanExpr, vararg conditions: BooleanExpr) = + BooleanExpr("and", condition, *conditions) @JvmStatic - fun or(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("or", condition, *conditions) + fun or(condition: BooleanExpr, vararg conditions: BooleanExpr) = + BooleanExpr("or", condition, *conditions) @JvmStatic - fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("xor", condition, *conditions) + fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = + BooleanExpr("xor", condition, *conditions) @JvmStatic fun not(condition: BooleanExpr) = BooleanExpr("not", condition) + @JvmStatic fun bitAnd(left: Expr, right: Expr) = Function("bit_and", left, right) + + @JvmStatic fun bitAnd(left: Expr, right: Any) = Function("bit_and", left, right) + + @JvmStatic fun bitAnd(fieldName: String, right: Expr) = Function("bit_and", fieldName, right) + + @JvmStatic fun bitAnd(fieldName: String, right: Any) = Function("bit_and", fieldName, right) + + @JvmStatic fun bitOr(left: Expr, right: Expr) = Function("bit_or", left, right) + + @JvmStatic fun bitOr(left: Expr, right: Any) = Function("bit_or", left, right) + + @JvmStatic fun bitOr(fieldName: String, right: Expr) = Function("bit_or", fieldName, right) + + @JvmStatic fun bitOr(fieldName: String, right: Any) = Function("bit_or", fieldName, right) + + @JvmStatic fun bitXor(left: Expr, right: Expr) = Function("bit_xor", left, right) + + @JvmStatic fun bitXor(left: Expr, right: Any) = Function("bit_xor", left, right) + + @JvmStatic fun bitXor(fieldName: String, right: Expr) = Function("bit_xor", fieldName, right) + + @JvmStatic fun bitXor(fieldName: String, right: Any) = Function("bit_xor", fieldName, right) + + @JvmStatic fun bitNot(left: Expr) = Function("bit_not", left) + + @JvmStatic fun bitNot(fieldName: String) = Function("bit_not", fieldName) + + @JvmStatic + fun bitLeftShift(left: Expr, numberExpr: Expr) = Function("bit_left_shift", left, numberExpr) + + @JvmStatic fun bitLeftShift(left: Expr, number: Int) = Function("bit_left_shift", left, number) + + @JvmStatic + fun bitLeftShift(fieldName: String, numberExpr: Expr) = + Function("bit_left_shift", fieldName, numberExpr) + + @JvmStatic + fun bitLeftShift(fieldName: String, number: Int) = Function("bit_left_shift", fieldName, number) + + @JvmStatic + fun bitRightShift(left: Expr, numberExpr: Expr) = Function("bit_right_shift", left, numberExpr) + + @JvmStatic + fun bitRightShift(left: Expr, number: Int) = Function("bit_right_shift", left, number) + + @JvmStatic + fun bitRightShift(fieldName: String, numberExpr: Expr) = + Function("bit_right_shift", fieldName, numberExpr) + + @JvmStatic + fun bitRightShift(fieldName: String, number: Int) = + Function("bit_right_shift", fieldName, number) + @JvmStatic fun add(left: Expr, right: Expr) = Function("add", left, right) @JvmStatic fun add(left: Expr, right: Any) = Function("add", left, right) @@ -417,9 +511,13 @@ protected constructor(private val name: String, private val params: Array) = BooleanExpr("in", array, ListOfExprs(toArrayOfExprOrConstant(values))) + @JvmStatic + fun inAny(array: Expr, values: List) = + BooleanExpr("in", array, ListOfExprs(toArrayOfExprOrConstant(values))) - @JvmStatic fun inAny(fieldName: String, values: List) = BooleanExpr("in", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + @JvmStatic + fun inAny(fieldName: String, values: List) = + BooleanExpr("in", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic fun notInAny(array: Expr, values: List) = not(inAny(array, values)) @@ -434,7 +532,8 @@ protected constructor(private val name: String, private val params: Array) = Function("array_concat", array, ListOfExprs(toArrayOfExprOrConstant(arrays))) + @JvmStatic + fun arrayConcat(array: Expr, arrays: List) = + Function("array_concat", array, ListOfExprs(toArrayOfExprOrConstant(arrays))) @JvmStatic - fun arrayConcat(fieldName: String, arrays: List) = Function("array_concat", fieldName, ListOfExprs(toArrayOfExprOrConstant(arrays))) + fun arrayConcat(fieldName: String, arrays: List) = + Function("array_concat", fieldName, ListOfExprs(toArrayOfExprOrConstant(arrays))) @JvmStatic fun arrayReverse(array: Expr) = Function("array_reverse", array) @JvmStatic fun arrayReverse(fieldName: String) = Function("array_reverse", fieldName) - @JvmStatic fun arrayContains(array: Expr, value: Expr) = BooleanExpr("array_contains", array, value) + @JvmStatic + fun arrayContains(array: Expr, value: Expr) = BooleanExpr("array_contains", array, value) - @JvmStatic fun arrayContains(fieldName: String, value: Expr) = BooleanExpr("array_contains", fieldName, value) + @JvmStatic + fun arrayContains(fieldName: String, value: Expr) = + BooleanExpr("array_contains", fieldName, value) - @JvmStatic fun arrayContains(array: Expr, value: Any) = BooleanExpr("array_contains", array, value) + @JvmStatic + fun arrayContains(array: Expr, value: Any) = BooleanExpr("array_contains", array, value) - @JvmStatic fun arrayContains(fieldName: String, value: Any) = BooleanExpr("array_contains", fieldName, value) + @JvmStatic + fun arrayContains(fieldName: String, value: Any) = + BooleanExpr("array_contains", fieldName, value) @JvmStatic - fun arrayContainsAll(array: Expr, values: List) = BooleanExpr("array_contains_all", array, ListOfExprs(toArrayOfExprOrConstant(values))) + fun arrayContainsAll(array: Expr, values: List) = + BooleanExpr("array_contains_all", array, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic - fun arrayContainsAll(fieldName: String, values: List) = BooleanExpr("array_contains_all", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + fun arrayContainsAll(fieldName: String, values: List) = + BooleanExpr("array_contains_all", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic - fun arrayContainsAny(array: Expr, values: List) = BooleanExpr("array_contains_any", array, ListOfExprs(toArrayOfExprOrConstant(values))) + fun arrayContainsAny(array: Expr, values: List) = + BooleanExpr("array_contains_any", array, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic - fun arrayContainsAny(fieldName: String, values: List) = BooleanExpr("array_contains_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + fun arrayContainsAny(fieldName: String, values: List) = + BooleanExpr("array_contains_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic fun arrayLength(array: Expr) = Function("array_length", array) @JvmStatic fun arrayLength(fieldName: String) = Function("array_length", fieldName) - @JvmStatic fun ifThen(condition: BooleanExpr, then: Expr) = - Function("if", condition, then, Constant.NULL) + @JvmStatic + fun ifThen(condition: BooleanExpr, then: Expr) = Function("if", condition, then, Constant.NULL) - @JvmStatic fun ifThen(condition: BooleanExpr, then: Any) = Function("if", condition, then, Constant.NULL) + @JvmStatic + fun ifThen(condition: BooleanExpr, then: Any) = Function("if", condition, then, Constant.NULL) - @JvmStatic fun ifThenElse(condition: BooleanExpr, then: Expr, `else`: Expr) = Function("if", condition, then, `else`) + @JvmStatic + fun ifThenElse(condition: BooleanExpr, then: Expr, `else`: Expr) = + Function("if", condition, then, `else`) + + @JvmStatic + fun ifThenElse(condition: BooleanExpr, then: Any, `else`: Any) = + Function("if", condition, then, `else`) - @JvmStatic fun ifThenElse(condition: BooleanExpr, then: Any, `else`: Any) = Function("if", condition, then, `else`) + @JvmStatic fun exists(expr: Expr) = BooleanExpr("exists", expr) } override fun toProto(userDataReader: UserDataReader): Value { @@ -787,13 +960,24 @@ protected constructor(private val name: String, private val params: Array) : Function(name, params) { - internal constructor(name: String, param: Expr, vararg params: Any) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) - internal constructor(name: String, fieldName: String, vararg params: Any) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) + internal constructor( + name: String, + params: List + ) : this(name, toArrayOfExprOrConstant(params)) + internal constructor( + name: String, + param: Expr, + vararg params: Any + ) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) + internal constructor( + name: String, + fieldName: String, + vararg params: Any + ) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) companion object { @JvmStatic fun generic(name: String, vararg expr: Expr) = BooleanExpr(name, expr) - } fun not() = not(this) @@ -838,39 +1022,3 @@ class Ordering private constructor(private val expr: Expr, private val dir: Dire ) .build() } - -// class BitAnd(left: Expr, right: Expr) : Function("bit_and", left, right) { -// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) -// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) -// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -// } - -// class BitOr(left: Expr, right: Expr) : Function("bit_or", left, right) { -// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) -// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) -// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -// } - -// class BitXor(left: Expr, right: Expr) : Function("bit_xor", left, right) { -// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) -// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) -// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -// } - -// class BitNot(left: Expr, right: Expr) : Function("bit_not", left, right) { -// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) -// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) -// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -// } - -// class BitLeftShift(left: Expr, right: Expr) : Function("bit_left_shift", left, right) { -// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) -// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) -// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -// } - -// class BitRightShift(left: Expr, right: Expr) : Function("bit_right_shift", left, right) { -// constructor(left: Expr, right: Any) : this(left, castToExprOrConvertToConstant(right)) -// constructor(fieldName: String, right: Expr) : this(Field.of(fieldName), right) -// constructor(fieldName: String, right: Any) : this(Field.of(fieldName), right) -// } From fcae38059aaffe89bed9ad915f9d9fafd9e3a5cf Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 24 Mar 2025 15:41:48 -0400 Subject: [PATCH 31/77] Convert query to pipeline --- .../firestore/QueryToPipelineTest.java | 889 ++++++++++++++++++ .../testutil/IntegrationTestUtil.java | 39 + .../firestore/CollectionReference.java | 1 + .../com/google/firebase/firestore/Pipeline.kt | 48 +- .../com/google/firebase/firestore/Query.java | 5 + .../firebase/firestore/UserDataReader.java | 2 +- .../firebase/firestore/UserDataWriter.java | 2 +- .../firestore/core/CompositeFilter.java | 14 + .../firebase/firestore/core/FieldFilter.java | 47 + .../firebase/firestore/core/Filter.java | 3 + .../firebase/firestore/core/OrderBy.java | 2 +- .../google/firebase/firestore/core/Query.java | 104 ++ .../firebase/firestore/model/BasePath.java | 9 +- .../firebase/firestore/model/ObjectValue.java | 9 +- .../google/firebase/firestore/model/Values.kt | 24 +- .../firebase/firestore/pipeline/Constant.kt | 4 + .../firestore/pipeline/expressions.kt | 46 +- .../firebase/firestore/pipeline/stage.kt | 12 +- .../firestore/remote/RemoteSerializer.java | 46 +- 19 files changed, 1241 insertions(+), 65 deletions(-) create mode 100644 firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java new file mode 100644 index 00000000000..c4f8f33bb01 --- /dev/null +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java @@ -0,0 +1,889 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.firestore; + +import static com.google.common.io.Files.map; +import static com.google.firebase.firestore.Filter.and; +import static com.google.firebase.firestore.Filter.arrayContains; +import static com.google.firebase.firestore.Filter.arrayContainsAny; +import static com.google.firebase.firestore.Filter.equalTo; +import static com.google.firebase.firestore.Filter.inArray; +import static com.google.firebase.firestore.Filter.or; +import static com.google.firebase.firestore.pipeline.Function.ifThen; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.checkQueryAndPipelineResultsMatch; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.nullList; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.pipelineSnapshotToIds; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.pipelineSnapshotToValues; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.testCollection; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.testCollectionWithDocs; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.testFirestore; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.waitFor; +import static com.google.firebase.firestore.testutil.TestUtil.expectError; +import static com.google.firebase.firestore.testutil.TestUtil.map; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.android.gms.tasks.Task; +import com.google.common.collect.Lists; +import com.google.firebase.firestore.Query.Direction; +import com.google.firebase.firestore.pipeline.Constant; +import com.google.firebase.firestore.pipeline.Field; +import com.google.firebase.firestore.testutil.IntegrationTestUtil; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class QueryToPipelineTest { + + @After + public void tearDown() { + IntegrationTestUtil.tearDown(); + } + + @Test + public void testLimitQueries() { + CollectionReference collection = + testCollectionWithDocs( + map( + "a", map("k", "a"), + "b", map("k", "b"), + "c", map("k", "c"))); + + Query query = collection.limit(2); + PipelineSnapshot set = waitFor(query.pipeline().execute()); + List> data = pipelineSnapshotToValues(set); + assertEquals(asList(map("k", "a"), map("k", "b")), data); + } + + @Test + public void testLimitQueriesUsingDescendingSortOrder() { + CollectionReference collection = + testCollectionWithDocs( + map( + "a", map("k", "a", "sort", 0), + "b", map("k", "b", "sort", 1), + "c", map("k", "c", "sort", 1), + "d", map("k", "d", "sort", 2))); + + Query query = collection.limit(2).orderBy("sort", Direction.DESCENDING); + PipelineSnapshot set = waitFor(query.pipeline().execute()); + List> data = pipelineSnapshotToValues(set); + assertEquals(asList(map("k", "d", "sort", 2L), map("k", "c", "sort", 1L)), data); + } + + @Test + public void testLimitToLastMustAlsoHaveExplicitOrderBy() { + CollectionReference collection = testCollectionWithDocs(map()); + + Query query = collection.limitToLast(2); + expectError( + () -> waitFor(query.pipeline().execute()), + "limitToLast() queries require specifying at least one orderBy() clause"); + } + + @Test + public void testLimitToLastQueriesWithCursors() { + CollectionReference collection = + testCollectionWithDocs( + map( + "a", map("k", "a", "sort", 0), + "b", map("k", "b", "sort", 1), + "c", map("k", "c", "sort", 1), + "d", map("k", "d", "sort", 2))); + + Query query = collection.limitToLast(3).orderBy("sort").endBefore(2); + PipelineSnapshot set = waitFor(query.pipeline().execute()); + List> data = pipelineSnapshotToValues(set); + assertEquals( + asList(map("k", "a", "sort", 0L), map("k", "b", "sort", 1L), map("k", "c", "sort", 1L)), + data); + + query = collection.limitToLast(3).orderBy("sort").endAt(1); + set = waitFor(query.pipeline().execute()); + data = pipelineSnapshotToValues(set); + assertEquals( + asList(map("k", "a", "sort", 0L), map("k", "b", "sort", 1L), map("k", "c", "sort", 1L)), + data); + + query = collection.limitToLast(3).orderBy("sort").startAt(2); + set = waitFor(query.pipeline().execute()); + data = pipelineSnapshotToValues(set); + assertEquals(asList(map("k", "d", "sort", 2L)), data); + + query = collection.limitToLast(3).orderBy("sort").startAfter(0); + set = waitFor(query.pipeline().execute()); + data = pipelineSnapshotToValues(set); + assertEquals( + asList(map("k", "b", "sort", 1L), map("k", "c", "sort", 1L), map("k", "d", "sort", 2L)), + data); + + query = collection.limitToLast(3).orderBy("sort").startAfter(-1); + set = waitFor(query.pipeline().execute()); + data = pipelineSnapshotToValues(set); + assertEquals( + asList(map("k", "b", "sort", 1L), map("k", "c", "sort", 1L), map("k", "d", "sort", 2L)), + data); + } + + @Test + public void testKeyOrderIsDescendingForDescendingInequality() { + CollectionReference collection = + testCollectionWithDocs( + map( + "a", map("foo", 42), + "b", map("foo", 42.0), + "c", map("foo", 42), + "d", map("foo", 21), + "e", map("foo", 21.0), + "f", map("foo", 66), + "g", map("foo", 66.0))); + + Query query = collection.whereGreaterThan("foo", 21.0).orderBy("foo", Direction.DESCENDING); + PipelineSnapshot result = waitFor(query.pipeline().execute()); + assertEquals(asList("g", "f", "c", "b", "a"), pipelineSnapshotToIds(result)); + } + + @Test + public void testUnaryFilterQueries() { + CollectionReference collection = + testCollectionWithDocs( + map( + "a", map("null", null, "nan", Double.NaN), + "b", map("null", null, "nan", 0), + "c", map("null", false, "nan", Double.NaN))); + PipelineSnapshot results = + waitFor( + collection + .whereEqualTo("null", null) + .whereEqualTo("nan", Double.NaN) + .pipeline() + .execute()); + assertEquals(1, results.getResults().size()); + PipelineResult result = results.getResults().get(0); + // Can't use assertEquals() since NaN != NaN. + assertEquals(null, result.get("null")); + assertTrue(((Double) result.get("nan")).isNaN()); + } + + @Test + public void testFilterOnInfinity() { + CollectionReference collection = + testCollectionWithDocs( + map( + "a", map("inf", Double.POSITIVE_INFINITY), + "b", map("inf", Double.NEGATIVE_INFINITY))); + PipelineSnapshot results = + waitFor(collection.whereEqualTo("inf", Double.POSITIVE_INFINITY).pipeline().execute()); + assertEquals(1, results.getResults().size()); + assertEquals(asList(map("inf", Double.POSITIVE_INFINITY)), pipelineSnapshotToValues(results)); + } + + @Test + public void testCanExplicitlySortByDocumentId() { + Map> testDocs = + map( + "a", map("key", "a"), + "b", map("key", "b"), + "c", map("key", "c")); + CollectionReference collection = testCollectionWithDocs(testDocs); + // Ideally this would be descending to validate it's different than + // the default, but that requires an extra index + PipelineSnapshot docs = + waitFor(collection.orderBy(FieldPath.documentId()).pipeline().execute()); + assertEquals( + asList(testDocs.get("a"), testDocs.get("b"), testDocs.get("c")), + pipelineSnapshotToValues(docs)); + } + + @Test + public void testCanQueryByDocumentId() { + Map> testDocs = + map( + "aa", map("key", "aa"), + "ab", map("key", "ab"), + "ba", map("key", "ba"), + "bb", map("key", "bb")); + CollectionReference collection = testCollectionWithDocs(testDocs); + PipelineSnapshot docs = + waitFor(collection.whereEqualTo(FieldPath.documentId(), "ab").pipeline().execute()); + assertEquals(singletonList(testDocs.get("ab")), pipelineSnapshotToValues(docs)); + + docs = + waitFor( + collection + .whereGreaterThan(FieldPath.documentId(), "aa") + .whereLessThanOrEqualTo(FieldPath.documentId(), "ba") + .pipeline() + .execute()); + assertEquals(asList(testDocs.get("ab"), testDocs.get("ba")), pipelineSnapshotToValues(docs)); + } + + @Test + public void testCanQueryByDocumentIdUsingRefs() { + Map> testDocs = + map( + "aa", map("key", "aa"), + "ab", map("key", "ab"), + "ba", map("key", "ba"), + "bb", map("key", "bb")); + CollectionReference collection = testCollectionWithDocs(testDocs); + PipelineSnapshot docs = + waitFor( + collection + .whereEqualTo(FieldPath.documentId(), collection.document("ab")) + .pipeline() + .execute()); + assertEquals(singletonList(testDocs.get("ab")), pipelineSnapshotToValues(docs)); + + docs = + waitFor( + collection + .whereGreaterThan(FieldPath.documentId(), collection.document("aa")) + .whereLessThanOrEqualTo(FieldPath.documentId(), collection.document("ba")) + .pipeline() + .execute()); + assertEquals(asList(testDocs.get("ab"), testDocs.get("ba")), pipelineSnapshotToValues(docs)); + } + + @Test + public void testCanQueryWithAndWithoutDocumentKey() { + CollectionReference collection = testCollection(); + collection.add(map()); + Task query1 = + collection.orderBy(FieldPath.documentId(), Direction.ASCENDING).pipeline().execute(); + Task query2 = collection.pipeline().execute(); + + waitFor(query1); + waitFor(query2); + + assertEquals( + pipelineSnapshotToValues(query1.getResult()), pipelineSnapshotToValues(query2.getResult())); + } + + @Test + public void testQueriesCanUseNotEqualFilters() { + // These documents are ordered by value in "zip" since the notEquals filter is an inequality, + // which results in documents being sorted by value. + Map docA = map("zip", Double.NaN); + Map docB = map("zip", 91102L); + Map docC = map("zip", 98101L); + Map docD = map("zip", "98101"); + Map docE = map("zip", asList(98101L)); + Map docF = map("zip", asList(98101L, 98102L)); + Map docG = map("zip", asList("98101", map("zip", 98101L))); + Map docH = map("zip", map("code", 500L)); + Map docI = map("code", 500L); + Map docJ = map("zip", null); + + Map> allDocs = + map( + "a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", docH, + "i", docI, "j", docJ); + CollectionReference collection = testCollectionWithDocs(allDocs); + + // Search for zips not matching 98101. + Map> expectedDocsMap = new LinkedHashMap<>(allDocs); + expectedDocsMap.remove("c"); + expectedDocsMap.remove("i"); + expectedDocsMap.remove("j"); + + PipelineSnapshot snapshot = + waitFor(collection.whereNotEqualTo("zip", 98101L).pipeline().execute()); + assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); + + // With objects. + expectedDocsMap = new LinkedHashMap<>(allDocs); + expectedDocsMap.remove("h"); + expectedDocsMap.remove("i"); + expectedDocsMap.remove("j"); + snapshot = waitFor(collection.whereNotEqualTo("zip", map("code", 500)).pipeline().execute()); + assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); + + // With Null. + expectedDocsMap = new LinkedHashMap<>(allDocs); + expectedDocsMap.remove("i"); + expectedDocsMap.remove("j"); + snapshot = waitFor(collection.whereNotEqualTo("zip", null).pipeline().execute()); + assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); + + List pipelineResults = waitFor(collection.pipeline() + .addFields( + Field.of("zip").isNan().as("isNan1"), + ifThen(Field.of("zip").isNan(), Constant.of(true)).as("isNan2"), + ifThen(Field.of("zip").isNan(), Constant.of(true)).isNotNull().as("isNan3") + ).execute()).getResults(); + + // With NaN. + expectedDocsMap = new LinkedHashMap<>(allDocs); + expectedDocsMap.remove("a"); + expectedDocsMap.remove("i"); + expectedDocsMap.remove("j"); + snapshot = waitFor(collection.whereEqualTo("zip", Double.NaN).pipeline().execute()); + assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); + } + + @Test + public void testQueriesCanUseNotEqualFiltersWithDocIds() { + Map docA = map("key", "aa"); + Map docB = map("key", "ab"); + Map docC = map("key", "ba"); + Map docD = map("key", "bb"); + Map> testDocs = + map( + "aa", docA, + "ab", docB, + "ba", docC, + "bb", docD); + CollectionReference collection = testCollectionWithDocs(testDocs); + PipelineSnapshot docs = + waitFor(collection.whereNotEqualTo(FieldPath.documentId(), "aa").pipeline().execute()); + assertEquals(asList(docB, docC, docD), pipelineSnapshotToValues(docs)); + } + + @Test + public void testQueriesCanUseArrayContainsFilters() { + Map docA = map("array", asList(42L)); + Map docB = map("array", asList("a", 42L, "c")); + Map docC = map("array", asList(41.999, "42", map("a", asList(42)))); + Map docD = map("array", asList(42L), "array2", asList("bingo")); + Map docE = map("array", nullList()); + Map docF = map("array", asList(Double.NaN)); + CollectionReference collection = + testCollectionWithDocs( + map("a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF)); + + // Search for "array" to contain 42 + PipelineSnapshot snapshot = + waitFor(collection.whereArrayContains("array", 42L).pipeline().execute()); + assertEquals(asList(docA, docB, docD), pipelineSnapshotToValues(snapshot)); + + // Note: whereArrayContains() requires a non-null value parameter, so no null test is needed. + // With NaN. + snapshot = waitFor(collection.whereArrayContains("array", Double.NaN).pipeline().execute()); + assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); + } + + @Test + public void testQueriesCanUseInFilters() { + Map docA = map("zip", 98101L); + Map docB = map("zip", 91102L); + Map docC = map("zip", 98103L); + Map docD = map("zip", asList(98101L)); + Map docE = map("zip", asList("98101", map("zip", 98101L))); + Map docF = map("zip", map("code", 500L)); + Map docG = map("zip", asList(98101L, 98102L)); + Map docH = map("zip", null); + Map docI = map("zip", Double.NaN); + + CollectionReference collection = + testCollectionWithDocs( + map( + "a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", + docH, "i", docI)); + + // Search for zips matching 98101, 98103, or [98101, 98102]. + PipelineSnapshot snapshot = + waitFor( + collection + .whereIn("zip", asList(98101L, 98103L, asList(98101L, 98102L))) + .pipeline() + .execute()); + assertEquals(asList(docA, docC, docG), pipelineSnapshotToValues(snapshot)); + + // With objects. + snapshot = waitFor(collection.whereIn("zip", asList(map("code", 500L))).pipeline().execute()); + assertEquals(asList(docF), pipelineSnapshotToValues(snapshot)); + + // With null. + snapshot = waitFor(collection.whereIn("zip", nullList()).pipeline().execute()); + assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); + + // With null and a value. + List inputList = nullList(); + inputList.add(98101L); + snapshot = waitFor(collection.whereIn("zip", inputList).pipeline().execute()); + assertEquals(asList(docA), pipelineSnapshotToValues(snapshot)); + + // With NaN. + snapshot = waitFor(collection.whereIn("zip", asList(Double.NaN)).pipeline().execute()); + assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); + + // With NaN and a value. + snapshot = waitFor(collection.whereIn("zip", asList(Double.NaN, 98101L)).pipeline().execute()); + assertEquals(asList(docA), pipelineSnapshotToValues(snapshot)); + } + + @Test + public void testQueriesCanUseInFiltersWithDocIds() { + Map docA = map("key", "aa"); + Map docB = map("key", "ab"); + Map docC = map("key", "ba"); + Map docD = map("key", "bb"); + Map> testDocs = + map( + "aa", docA, + "ab", docB, + "ba", docC, + "bb", docD); + CollectionReference collection = testCollectionWithDocs(testDocs); + PipelineSnapshot docs = + waitFor( + collection.whereIn(FieldPath.documentId(), asList("aa", "ab")).pipeline().execute()); + assertEquals(asList(docA, docB), pipelineSnapshotToValues(docs)); + } + + @Test + public void testQueriesCanUseNotInFilters() { + // These documents are ordered by value in "zip" since the notEquals filter is an inequality, + // which results in documents being sorted by value. + Map docA = map("zip", Double.NaN); + Map docB = map("zip", 91102L); + Map docC = map("zip", 98101L); + Map docD = map("zip", 98103L); + Map docE = map("zip", asList(98101L)); + Map docF = map("zip", asList(98101L, 98102L)); + Map docG = map("zip", asList("98101", map("zip", 98101L))); + Map docH = map("zip", map("code", 500L)); + Map docI = map("code", 500L); + Map docJ = map("zip", null); + + Map> allDocs = + map( + "a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", docH, + "i", docI, "j", docJ); + CollectionReference collection = testCollectionWithDocs(allDocs); + + // Search for zips not matching 98101, 98103, or [98101, 98102]. + Map> expectedDocsMap = new LinkedHashMap<>(allDocs); + expectedDocsMap.remove("c"); + expectedDocsMap.remove("d"); + expectedDocsMap.remove("f"); + expectedDocsMap.remove("i"); + expectedDocsMap.remove("j"); + + PipelineSnapshot snapshot = + waitFor( + collection + .whereNotIn("zip", asList(98101L, 98103L, asList(98101L, 98102L))) + .pipeline() + .execute()); + assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); + + // With objects. + expectedDocsMap = new LinkedHashMap<>(allDocs); + expectedDocsMap.remove("h"); + expectedDocsMap.remove("i"); + expectedDocsMap.remove("j"); + snapshot = + waitFor(collection.whereNotIn("zip", asList(map("code", 500L))).pipeline().execute()); + assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); + + // With Null. + snapshot = waitFor(collection.whereNotIn("zip", nullList()).pipeline().execute()); + assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); + + // With NaN. + expectedDocsMap = new LinkedHashMap<>(allDocs); + expectedDocsMap.remove("a"); + expectedDocsMap.remove("i"); + expectedDocsMap.remove("j"); + snapshot = waitFor(collection.whereNotIn("zip", asList(Double.NaN)).pipeline().execute()); + assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); + + // With NaN and a number. + expectedDocsMap = new LinkedHashMap<>(allDocs); + expectedDocsMap.remove("a"); + expectedDocsMap.remove("c"); + expectedDocsMap.remove("i"); + expectedDocsMap.remove("j"); + snapshot = + waitFor(collection.whereNotIn("zip", asList(Float.NaN, 98101L)).pipeline().execute()); + assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); + } + + @Test + public void testQueriesCanUseNotInFiltersWithDocIds() { + Map docA = map("key", "aa"); + Map docB = map("key", "ab"); + Map docC = map("key", "ba"); + Map docD = map("key", "bb"); + Map> testDocs = + map( + "aa", docA, + "ab", docB, + "ba", docC, + "bb", docD); + CollectionReference collection = testCollectionWithDocs(testDocs); + PipelineSnapshot docs = + waitFor( + collection.whereNotIn(FieldPath.documentId(), asList("aa", "ab")).pipeline().execute()); + assertEquals(asList(docC, docD), pipelineSnapshotToValues(docs)); + } + + @Test + public void testQueriesCanUseArrayContainsAnyFilters() { + Map docA = map("array", asList(42L)); + Map docB = map("array", asList("a", 42L, "c")); + Map docC = map("array", asList(41.999, "42", map("a", asList(42)))); + Map docD = map("array", asList(42L), "array2", asList("bingo")); + Map docE = map("array", asList(43L)); + Map docF = map("array", asList(map("a", 42L))); + Map docG = map("array", 42L); + Map docH = map("array", nullList()); + Map docI = map("array", asList(Double.NaN)); + + CollectionReference collection = + testCollectionWithDocs( + map( + "a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", + docH, "i", docI)); + + // Search for "array" to contain [42, 43]. + PipelineSnapshot snapshot = + waitFor(collection.whereArrayContainsAny("array", asList(42L, 43L)).pipeline().execute()); + assertEquals(asList(docA, docB, docD, docE), pipelineSnapshotToValues(snapshot)); + + // With objects. + snapshot = + waitFor( + collection.whereArrayContainsAny("array", asList(map("a", 42L))).pipeline().execute()); + assertEquals(asList(docF), pipelineSnapshotToValues(snapshot)); + + // With null. + snapshot = waitFor(collection.whereArrayContainsAny("array", nullList()).pipeline().execute()); + assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); + + // With null and a value. + List inputList = nullList(); + inputList.add(43L); + snapshot = waitFor(collection.whereArrayContainsAny("array", inputList).pipeline().execute()); + assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); + + // With NaN. + snapshot = + waitFor(collection.whereArrayContainsAny("array", asList(Double.NaN)).pipeline().execute()); + assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); + + // With NaN and a value. + snapshot = + waitFor( + collection + .whereArrayContainsAny("array", asList(Double.NaN, 43L)) + .pipeline() + .execute()); + assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); + } + + @Test + public void testCollectionGroupQueries() { + FirebaseFirestore db = testFirestore(); + // Use .document() to get a random collection group name to use but ensure it starts with 'b' + // for predictable ordering. + String collectionGroup = "b" + db.collection("foo").document().getId(); + + String[] docPaths = + new String[] { + "abc/123/${collectionGroup}/cg-doc1", + "abc/123/${collectionGroup}/cg-doc2", + "${collectionGroup}/cg-doc3", + "${collectionGroup}/cg-doc4", + "def/456/${collectionGroup}/cg-doc5", + "${collectionGroup}/virtual-doc/nested-coll/not-cg-doc", + "x${collectionGroup}/not-cg-doc", + "${collectionGroup}x/not-cg-doc", + "abc/123/${collectionGroup}x/not-cg-doc", + "abc/123/x${collectionGroup}/not-cg-doc", + "abc/${collectionGroup}" + }; + WriteBatch batch = db.batch(); + for (String path : docPaths) { + batch.set(db.document(path.replace("${collectionGroup}", collectionGroup)), map("x", 1)); + } + waitFor(batch.commit()); + + PipelineSnapshot snapshot = waitFor(db.collectionGroup(collectionGroup).pipeline().execute()); + assertEquals( + asList("cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5"), + pipelineSnapshotToIds(snapshot)); + } + + @Test + public void testCollectionGroupQueriesWithStartAtEndAtWithArbitraryDocumentIds() { + FirebaseFirestore db = testFirestore(); + // Use .document() to get a random collection group name to use but ensure it starts with 'b' + // for predictable ordering. + String collectionGroup = "b" + db.collection("foo").document().getId(); + + String[] docPaths = + new String[] { + "a/a/${collectionGroup}/cg-doc1", + "a/b/a/b/${collectionGroup}/cg-doc2", + "a/b/${collectionGroup}/cg-doc3", + "a/b/c/d/${collectionGroup}/cg-doc4", + "a/c/${collectionGroup}/cg-doc5", + "${collectionGroup}/cg-doc6", + "a/b/nope/nope" + }; + WriteBatch batch = db.batch(); + for (String path : docPaths) { + batch.set(db.document(path.replace("${collectionGroup}", collectionGroup)), map("x", 1)); + } + waitFor(batch.commit()); + + PipelineSnapshot snapshot = + waitFor( + db.collectionGroup(collectionGroup) + .orderBy(FieldPath.documentId()) + .startAt("a/b") + .endAt("a/b0") + .pipeline() + .execute()); + assertEquals(asList("cg-doc2", "cg-doc3", "cg-doc4"), pipelineSnapshotToIds(snapshot)); + + snapshot = + waitFor( + db.collectionGroup(collectionGroup) + .orderBy(FieldPath.documentId()) + .startAfter("a/b") + .endBefore("a/b/" + collectionGroup + "/cg-doc3") + .pipeline() + .execute()); + assertEquals(asList("cg-doc2"), pipelineSnapshotToIds(snapshot)); + } + + @Test + public void testCollectionGroupQueriesWithWhereFiltersOnArbitraryDocumentIds() { + FirebaseFirestore db = testFirestore(); + // Use .document() to get a random collection group name to use but ensure it starts with 'b' + // for predictable ordering. + String collectionGroup = "b" + db.collection("foo").document().getId(); + + String[] docPaths = + new String[] { + "a/a/${collectionGroup}/cg-doc1", + "a/b/a/b/${collectionGroup}/cg-doc2", + "a/b/${collectionGroup}/cg-doc3", + "a/b/c/d/${collectionGroup}/cg-doc4", + "a/c/${collectionGroup}/cg-doc5", + "${collectionGroup}/cg-doc6", + "a/b/nope/nope" + }; + WriteBatch batch = db.batch(); + for (String path : docPaths) { + batch.set(db.document(path.replace("${collectionGroup}", collectionGroup)), map("x", 1)); + } + waitFor(batch.commit()); + + PipelineSnapshot snapshot = + waitFor( + db.collectionGroup(collectionGroup) + .whereGreaterThanOrEqualTo(FieldPath.documentId(), "a/b") + .whereLessThanOrEqualTo(FieldPath.documentId(), "a/b0") + .pipeline() + .execute()); + assertEquals(asList("cg-doc2", "cg-doc3", "cg-doc4"), pipelineSnapshotToIds(snapshot)); + + snapshot = + waitFor( + db.collectionGroup(collectionGroup) + .whereGreaterThan(FieldPath.documentId(), "a/b") + .whereLessThan(FieldPath.documentId(), "a/b/" + collectionGroup + "/cg-doc3") + .pipeline() + .execute()); + assertEquals(asList("cg-doc2"), pipelineSnapshotToIds(snapshot)); + } + + @Test + public void testOrQueries() { + Map> testDocs = + map( + "doc1", map("a", 1, "b", 0), + "doc2", map("a", 2, "b", 1), + "doc3", map("a", 3, "b", 2), + "doc4", map("a", 1, "b", 3), + "doc5", map("a", 1, "b", 1)); + CollectionReference collection = testCollectionWithDocs(testDocs); + + // Two equalities: a==1 || b==1. + checkQueryAndPipelineResultsMatch( + collection.where(or(equalTo("a", 1), equalTo("b", 1))), "doc1", "doc2", "doc4", "doc5"); + + // (a==1 && b==0) || (a==3 && b==2) + checkQueryAndPipelineResultsMatch( + collection.where( + or(and(equalTo("a", 1), equalTo("b", 0)), and(equalTo("a", 3), equalTo("b", 2)))), + "doc1", + "doc3"); + + // a==1 && (b==0 || b==3). + checkQueryAndPipelineResultsMatch( + collection.where(and(equalTo("a", 1), or(equalTo("b", 0), equalTo("b", 3)))), + "doc1", + "doc4"); + + // (a==2 || b==2) && (a==3 || b==3) + checkQueryAndPipelineResultsMatch( + collection.where( + and(or(equalTo("a", 2), equalTo("b", 2)), or(equalTo("a", 3), equalTo("b", 3)))), + "doc3"); + + // Test with limits without orderBy (the __name__ ordering is the tie breaker). + checkQueryAndPipelineResultsMatch( + collection.where(or(equalTo("a", 2), equalTo("b", 1))).limit(1), "doc2"); + } + + @Test + public void testOrQueriesWithIn() { + Map> testDocs = + map( + "doc1", map("a", 1, "b", 0), + "doc2", map("b", 1), + "doc3", map("a", 3, "b", 2), + "doc4", map("a", 1, "b", 3), + "doc5", map("a", 1), + "doc6", map("a", 2)); + CollectionReference collection = testCollectionWithDocs(testDocs); + + // a==2 || b in [2,3] + checkQueryAndPipelineResultsMatch( + collection.where(or(equalTo("a", 2), inArray("b", asList(2, 3)))), "doc3", "doc4", "doc6"); + } + + @Test + public void testOrQueriesWithArrayMembership() { + Map> testDocs = + map( + "doc1", map("a", 1, "b", asList(0)), + "doc2", map("b", asList(1)), + "doc3", map("a", 3, "b", asList(2, 7)), + "doc4", map("a", 1, "b", asList(3, 7)), + "doc5", map("a", 1), + "doc6", map("a", 2)); + CollectionReference collection = testCollectionWithDocs(testDocs); + + // a==2 || b array-contains 7 + checkQueryAndPipelineResultsMatch( + collection.where(or(equalTo("a", 2), arrayContains("b", 7))), "doc3", "doc4", "doc6"); + + // a==2 || b array-contains-any [0, 3] + checkQueryAndPipelineResultsMatch( + collection.where(or(equalTo("a", 2), arrayContainsAny("b", asList(0, 3)))), + "doc1", + "doc4", + "doc6"); + } + + @Test + public void testMultipleInOps() { + Map> testDocs = + map( + "doc1", map("a", 1, "b", 0), + "doc2", map("b", 1), + "doc3", map("a", 3, "b", 2), + "doc4", map("a", 1, "b", 3), + "doc5", map("a", 1), + "doc6", map("a", 2)); + CollectionReference collection = testCollectionWithDocs(testDocs); + + // Two IN operations on different fields with disjunction. + Query query1 = collection.where(or(inArray("a", asList(2, 3)), inArray("b", asList(0, 2)))); + checkQueryAndPipelineResultsMatch(query1, "doc1", "doc3", "doc6"); + + // Two IN operations on the same field with disjunction. + // a IN [0,3] || a IN [0,2] should union them (similar to: a IN [0,2,3]). + Query query2 = collection.where(or(inArray("a", asList(0, 3)), inArray("a", asList(0, 2)))); + checkQueryAndPipelineResultsMatch(query2, "doc3", "doc6"); + } + + @Test + public void testUsingInWithArrayContainsAny() { + Map> testDocs = + map( + "doc1", map("a", 1, "b", asList(0)), + "doc2", map("b", asList(1)), + "doc3", map("a", 3, "b", asList(2, 7), "c", 10), + "doc4", map("a", 1, "b", asList(3, 7)), + "doc5", map("a", 1), + "doc6", map("a", 2, "c", 20)); + CollectionReference collection = testCollectionWithDocs(testDocs); + + Query query1 = + collection.where(or(inArray("a", asList(2, 3)), arrayContainsAny("b", asList(0, 7)))); + checkQueryAndPipelineResultsMatch(query1, "doc1", "doc3", "doc4", "doc6"); + + Query query2 = + collection.where( + or( + and(inArray("a", asList(2, 3)), equalTo("c", 10)), + arrayContainsAny("b", asList(0, 7)))); + checkQueryAndPipelineResultsMatch(query2, "doc1", "doc3", "doc4"); + } + + @Test + public void testUsingInWithArrayContains() { + Map> testDocs = + map( + "doc1", map("a", 1, "b", asList(0)), + "doc2", map("b", asList(1)), + "doc3", map("a", 3, "b", asList(2, 7)), + "doc4", map("a", 1, "b", asList(3, 7)), + "doc5", map("a", 1), + "doc6", map("a", 2)); + CollectionReference collection = testCollectionWithDocs(testDocs); + + Query query1 = collection.where(or(inArray("a", asList(2, 3)), arrayContains("b", 3))); + checkQueryAndPipelineResultsMatch(query1, "doc3", "doc4", "doc6"); + + Query query2 = collection.where(and(inArray("a", asList(2, 3)), arrayContains("b", 7))); + checkQueryAndPipelineResultsMatch(query2, "doc3"); + + Query query3 = + collection.where( + or(inArray("a", asList(2, 3)), and(arrayContains("b", 3), equalTo("a", 1)))); + checkQueryAndPipelineResultsMatch(query3, "doc3", "doc4", "doc6"); + + Query query4 = + collection.where( + and(inArray("a", asList(2, 3)), or(arrayContains("b", 7), equalTo("a", 1)))); + checkQueryAndPipelineResultsMatch(query4, "doc3"); + } + + @Test + public void testOrderByEquality() { + Map> testDocs = + map( + "doc1", map("a", 1, "b", asList(0)), + "doc2", map("b", asList(1)), + "doc3", map("a", 3, "b", asList(2, 7), "c", 10), + "doc4", map("a", 1, "b", asList(3, 7)), + "doc5", map("a", 1), + "doc6", map("a", 2, "c", 20)); + CollectionReference collection = testCollectionWithDocs(testDocs); + + Query query1 = collection.where(equalTo("a", 1)).orderBy("a"); + checkQueryAndPipelineResultsMatch(query1, "doc1", "doc4", "doc5"); + + Query query2 = collection.where(inArray("a", asList(2, 3))).orderBy("a"); + checkQueryAndPipelineResultsMatch(query2, "doc6", "doc3"); + } +} diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java index d11c27828cf..5a8a9ceb67c 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java @@ -38,6 +38,8 @@ import com.google.firebase.firestore.FirebaseFirestoreSettings; import com.google.firebase.firestore.ListenerRegistration; import com.google.firebase.firestore.MetadataChanges; +import com.google.firebase.firestore.PipelineResult; +import com.google.firebase.firestore.PipelineSnapshot; import com.google.firebase.firestore.Query; import com.google.firebase.firestore.QuerySnapshot; import com.google.firebase.firestore.Source; @@ -465,6 +467,15 @@ public static List> querySnapshotToValues(QuerySnapshot quer return res; } + public static List> pipelineSnapshotToValues( + PipelineSnapshot pipelineSnapshot) { + List> res = new ArrayList<>(); + for (PipelineResult result : pipelineSnapshot) { + res.add(result.getData()); + } + return res; + } + public static List querySnapshotToIds(QuerySnapshot querySnapshot) { List res = new ArrayList<>(); for (DocumentSnapshot doc : querySnapshot) { @@ -473,6 +484,15 @@ public static List querySnapshotToIds(QuerySnapshot querySnapshot) { return res; } + public static List pipelineSnapshotToIds(PipelineSnapshot pipelineResults) { + List res = new ArrayList<>(); + for (PipelineResult result : pipelineResults) { + DocumentReference ref = result.getRef(); + res.add(ref == null ? null : ref.getId()); + } + return res; + } + public static void disableNetwork(FirebaseFirestore firestore) { if (firestoreStatus.get(firestore)) { waitFor(firestore.disableNetwork()); @@ -537,4 +557,23 @@ public static void checkOnlineAndOfflineResultsMatch(Query query, String... expe assertEquals(expected, querySnapshotToIds(docsFromCache)); } } + + /** + * Checks that running the query while online (against the backend/emulator) results in the same + * documents as running the query while offline. If `expectedDocs` is provided, it also checks + * that both online and offline query result is equal to the expected documents. + * + * @param query The query to check + * @param expectedDocs Ordered list of document keys that are expected to match the query + */ + public static void checkQueryAndPipelineResultsMatch(Query query, String... expectedDocs) { + QuerySnapshot docsFromQuery = waitFor(query.get(Source.SERVER)); + PipelineSnapshot docsFromPipeline = waitFor(query.pipeline().execute()); + + assertEquals(querySnapshotToIds(docsFromQuery), pipelineSnapshotToIds(docsFromPipeline)); + List expected = asList(expectedDocs); + if (!expected.isEmpty()) { + assertEquals(expected, querySnapshotToIds(docsFromQuery)); + } + } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java index 8f4e1a00d79..c8b9cfaa90a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java @@ -130,6 +130,7 @@ public Task add(@NonNull Object data) { } @NonNull + @Override public Pipeline pipeline() { return new Pipeline(firestore, firestore.getUserDataReader(), new CollectionSource(getPath())); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 29b81683b61..8f3ca218061 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -20,6 +20,7 @@ import com.google.common.collect.FluentIterable import com.google.common.collect.ImmutableList import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.SnapshotVersion +import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.pipeline.AddFieldsStage import com.google.firebase.firestore.pipeline.AggregateStage import com.google.firebase.firestore.pipeline.AggregateWithAlias @@ -123,9 +124,9 @@ internal constructor( fun where(condition: BooleanExpr): Pipeline = append(WhereStage(condition)) - fun offset(offset: Long): Pipeline = append(OffsetStage(offset)) + fun offset(offset: Int): Pipeline = append(OffsetStage(offset)) - fun limit(limit: Long): Pipeline = append(LimitStage(limit)) + fun limit(limit: Int): Pipeline = append(LimitStage(limit)) fun distinct(vararg groups: Selectable): Pipeline = append(DistinctStage(groups)) @@ -175,12 +176,15 @@ internal constructor( append(UnnestStage(selectable)) private inner class ObserverSnapshotTask : PipelineResultObserver { + private val userDataWriter = + UserDataWriter(firestore, DocumentSnapshot.ServerTimestampBehavior.DEFAULT) private val taskCompletionSource = TaskCompletionSource() private val results: ImmutableList.Builder = ImmutableList.builder() override fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) { results.add( PipelineResult( firestore, + userDataWriter, if (key == null) null else DocumentReference(key, firestore), data, version @@ -249,20 +253,52 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto } class PipelineSnapshot -internal constructor(private val executionTime: SnapshotVersion, val results: List) +internal constructor( + private val executionTime: SnapshotVersion, + val results: List +) : Iterable { + override fun iterator() = results.iterator() +} class PipelineResult internal constructor( private val firestore: FirebaseFirestore, + private val userDataWriter: UserDataWriter, val ref: DocumentReference?, private val fields: Map, private val version: SnapshotVersion, ) { - fun getData(): Map = userDataWriter().convertObject(fields) + /** + * Returns the ID of the document represented by this result. Returns null if this result is not + * corresponding to a Firestore document. + */ + fun getId(): String? = ref?.id + + fun getData(): Map = userDataWriter.convertObject(fields) + + private fun extractNestedValue(fieldPath: FieldPath): Value? { + val segments = fieldPath.internalPath.iterator() + if (!segments.hasNext()) { + return Values.encodeValue(fields) + } + val firstSegment = segments.next() + if (!fields.containsKey(firstSegment)) { + return null + } + var value: Value? = fields[firstSegment] + for (segment in segments) { + if (value == null || !value.hasMapValue()) { + return null + } + value = value.mapValue.getFieldsOrDefault(segment, null) + } + return value + } + + fun get(field: String): Any? = get(FieldPath.fromDotSeparatedPath(field)) - private fun userDataWriter(): UserDataWriter = - UserDataWriter(firestore, DocumentSnapshot.ServerTimestampBehavior.DEFAULT) + fun get(fieldPath: FieldPath): Any? = userDataWriter.convertValue(extractNestedValue(fieldPath)) override fun toString() = "PipelineResult{ref=$ref, version=$version}, data=${getData()}" } 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 d5fb8a4399b..12ff36bf960 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 @@ -1241,6 +1241,11 @@ public AggregateQuery aggregate( return new AggregateQuery(this, fields); } + @NonNull + public Pipeline pipeline() { + return query.toPipeline(firestore, firestore.getUserDataReader()); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java index 3ce7cfec87c..97c9d9d33e1 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataReader.java @@ -230,7 +230,7 @@ private ObjectValue convertAndParseDocumentData(Object input, ParseContext conte Object converted = CustomClassMapper.convertToPlainJavaTypes(input); Value parsedValue = parseData(converted, context); - if (parsedValue.getValueTypeCase() != Value.ValueTypeCase.MAP_VALUE) { + if (!parsedValue.hasMapValue()) { throw new IllegalArgumentException(badDocReason + "of type: " + Util.typeName(input)); } return new ObjectValue(parsedValue); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataWriter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataWriter.java index d6ac7b90bba..8c90a4d02e4 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataWriter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/UserDataWriter.java @@ -78,7 +78,7 @@ public Object convertValue(Value value) { case TYPE_ORDER_BOOLEAN: return value.getBooleanValue(); case TYPE_ORDER_NUMBER: - return value.getValueTypeCase().equals(Value.ValueTypeCase.INTEGER_VALUE) + return value.hasIntegerValue() ? (Object) value.getIntegerValue() // Cast to Object to prevent type coercion to double : (Object) value.getDoubleValue(); case TYPE_ORDER_STRING: diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java index 26654f7a1ba..c9ed9c6c0e3 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java @@ -17,6 +17,7 @@ import android.text.TextUtils; import androidx.annotation.Nullable; import com.google.firebase.firestore.model.Document; +import com.google.firebase.firestore.pipeline.BooleanExpr; import com.google.firebase.firestore.util.Function; import java.util.ArrayList; import java.util.Collections; @@ -167,6 +168,19 @@ public String getCanonicalId() { return builder.toString(); } + @Override + BooleanExpr toPipelineExpr() { + BooleanExpr[] booleanExprs = filters.stream().map(Filter::toPipelineExpr).toArray(BooleanExpr[]::new); + switch (operator) { + case AND: + return new BooleanExpr("and", booleanExprs); + case OR: + return new BooleanExpr("or", booleanExprs); + } + // Handle OPERATOR_UNSPECIFIED and UNRECOGNIZED cases as needed + throw new IllegalArgumentException("Unsupported operator: " + operator); + } + @Override public String toString() { return getCanonicalId(); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java index 6ebf26d0718..4d2a5a404c0 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java @@ -14,11 +14,15 @@ package com.google.firebase.firestore.core; +import static com.google.firebase.firestore.pipeline.Function.and; import static com.google.firebase.firestore.util.Assert.hardAssert; +import static java.lang.Double.isNaN; import com.google.firebase.firestore.model.Document; import com.google.firebase.firestore.model.FieldPath; import com.google.firebase.firestore.model.Values; +import com.google.firebase.firestore.pipeline.BooleanExpr; +import com.google.firebase.firestore.pipeline.Field; import com.google.firebase.firestore.util.Assert; import com.google.firestore.v1.Value; import java.util.Arrays; @@ -172,6 +176,49 @@ public List getFilters() { return Collections.singletonList(this); } + @Override + BooleanExpr toPipelineExpr() { + Field x = new Field(field); + BooleanExpr exists = x.exists(); + switch (operator) { + case LESS_THAN: + return and(exists, x.lt(value)); + case LESS_THAN_OR_EQUAL: + return and(exists, x.lte(value)); + case EQUAL: + if (value.hasNullValue()) { + return and(exists, x.isNull()); + } else if (value.hasDoubleValue() && isNaN(value.getDoubleValue())) { + return and(exists, x.isNan()); + } else { + return and(exists, x.eq(value)); + } + case NOT_EQUAL: + if (value.hasNullValue()) { + return and(exists, x.isNotNull()); + } else if (value.hasDoubleValue() && isNaN(value.getDoubleValue())) { + return and(exists, x.isNotNan()); + } else { + return and(exists, x.neq(value)); + } + case GREATER_THAN: + return and(exists, x.gt(value)); + case GREATER_THAN_OR_EQUAL: + return and(exists, x.gte(value)); + case ARRAY_CONTAINS: + return and(exists, x.arrayContains(value)); + case ARRAY_CONTAINS_ANY: + return and(exists, x.arrayContainsAny(value.getArrayValue().getValuesList())); + case IN: + return and(exists, x.eqAny(value.getArrayValue().getValuesList())); + case NOT_IN: + return and(exists, x.notEqAny(value.getArrayValue().getValuesList())); + default: + // Handle OPERATOR_UNSPECIFIED and UNRECOGNIZED cases as needed + throw new IllegalArgumentException("Unsupported operator: " + operator); + } + } + @Override public String toString() { return getCanonicalId(); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Filter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Filter.java index 063b994f7a8..3f33bd3d5bc 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Filter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Filter.java @@ -15,6 +15,7 @@ package com.google.firebase.firestore.core; import com.google.firebase.firestore.model.Document; +import com.google.firebase.firestore.pipeline.BooleanExpr; import java.util.List; public abstract class Filter { @@ -29,4 +30,6 @@ public abstract class Filter { /** Returns a list of all filters that are contained within this filter */ public abstract List getFilters(); + + abstract BooleanExpr toPipelineExpr(); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/OrderBy.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/OrderBy.java index 8636fd0498a..1fd8a42ada5 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/OrderBy.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/OrderBy.java @@ -21,7 +21,7 @@ import com.google.firestore.v1.Value; /** Represents a sort order for a Firestore Query */ -public class OrderBy { +public final class OrderBy { /** The direction of the ordering */ public enum Direction { ASCENDING(1), diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index bf57dfdb7a3..a923be48e8d 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -14,21 +14,41 @@ package com.google.firebase.firestore.core; +import static com.google.firebase.firestore.pipeline.Function.and; +import static com.google.firebase.firestore.pipeline.Function.or; import static com.google.firebase.firestore.util.Assert.hardAssert; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.Pipeline; +import com.google.firebase.firestore.UserDataReader; import com.google.firebase.firestore.core.OrderBy.Direction; import com.google.firebase.firestore.model.Document; import com.google.firebase.firestore.model.DocumentKey; import com.google.firebase.firestore.model.FieldPath; import com.google.firebase.firestore.model.ResourcePath; +import com.google.firebase.firestore.pipeline.BooleanExpr; +import com.google.firebase.firestore.pipeline.CollectionGroupSource; +import com.google.firebase.firestore.pipeline.CollectionSource; +import com.google.firebase.firestore.pipeline.DocumentsSource; +import com.google.firebase.firestore.pipeline.Expr; +import com.google.firebase.firestore.pipeline.Field; +import com.google.firebase.firestore.pipeline.Function; +import com.google.firebase.firestore.pipeline.Ordering; +import com.google.firebase.firestore.pipeline.Stage; +import com.google.firestore.v1.Value; + import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; +import java.util.function.BiFunction; +import java.util.stream.Collectors; /** * Encapsulates all the query attributes we support in the SDK. It can be run against the @@ -502,6 +522,90 @@ private synchronized Target toTarget(List orderBys) { } } + @NonNull + public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataReader) { + Pipeline p = new Pipeline(firestore, userDataReader, pipelineSource()); + + // Filters + for (Filter filter : filters) { + p = p.where(filter.toPipelineExpr()); + } + + // Orders + List normalizedOrderBy = getNormalizedOrderBy(); + int size = normalizedOrderBy.size(); + List fields = new ArrayList<>(size); + List orderings = new ArrayList<>(size); + for (OrderBy order : normalizedOrderBy) { + Field field = new Field(order.getField()); + fields.add(field); + if (order.getDirection() == Direction.ASCENDING) { + orderings.add(field.ascending()); + } else { + orderings.add(field.descending()); + } + } + + if (fields.size() == 1) { + p = p.where(fields.get(0).exists()); + } else { + p = p.where(and(fields.get(0).exists(), fields.stream().skip(1).map(Expr::exists).toArray(BooleanExpr[]::new))); + } + + if (startAt != null) { + p = p.where(whereConditionsFromCursor(startAt, fields, Function::gt)); + } + + if (endAt != null) { + p = p.where(whereConditionsFromCursor(endAt, fields, Function::lt)); + } + + // Cursors, Limit, Offset + if (hasLimit()) { + // TODO: Handle situation where user enters limit larger than integer. + if (limitType == LimitType.LIMIT_TO_FIRST) { + p = p.sort(orderings.toArray(Ordering[]::new)); + p = p.limit((int) limit); + } else { + p = p.sort(orderings.stream().map(Ordering::reverse).toArray(Ordering[]::new)); + p = p.limit((int) limit); + p = p.sort(orderings.toArray(Ordering[]::new)); + } + } else { + p = p.sort(orderings.toArray(Ordering[]::new)); + } + + return p; + } + + private static BooleanExpr whereConditionsFromCursor(Bound bound, List fields, BiFunction cmp) { + List boundPosition = bound.getPosition(); + int size = boundPosition.size(); + hardAssert(size <= fields.size(), "Bound positions must not exceed order fields."); + int last = size - 1; + BooleanExpr condition = cmp.apply(fields.get(last), boundPosition.get(last)); + if (bound.isInclusive()) { + condition = or(condition, Function.eq(fields.get(last), boundPosition.get(last))); + } + for (int i = size - 2; i >=0; i--) { + final Field field = fields.get(i); + final Value value = boundPosition.get(i); + condition = or(cmp.apply(field, value), and(field.eq(value), condition)); + } + return condition; + } + + @NonNull + private Stage pipelineSource() { + if (isDocumentQuery()) { + return new DocumentsSource(path.canonicalString()); + } else if (isCollectionGroupQuery()) { + return new CollectionGroupSource(collectionGroup); + } else { + return new CollectionSource(path.canonicalString()); + } + } + /** * This method is marked as synchronized because it modifies the internal state in some cases. * diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/BasePath.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/BasePath.java index 66356e12595..6d800de05d4 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/BasePath.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/BasePath.java @@ -19,19 +19,26 @@ import androidx.annotation.NonNull; import com.google.firebase.firestore.util.Util; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; /** * BasePath represents a path sequence in the Firestore database. It is composed of an ordered * sequence of string segments. */ -public abstract class BasePath> implements Comparable { +public abstract class BasePath> implements Comparable, Iterable { final List segments; BasePath(List segments) { this.segments = segments; } + @NonNull + @Override + public Iterator iterator() { + return segments.iterator(); + } + public String getSegment(int index) { return segments.get(index); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/ObjectValue.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/ObjectValue.java index a7ea2997618..581bbf8481b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/ObjectValue.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/ObjectValue.java @@ -47,9 +47,7 @@ public static ObjectValue fromMap(Map value) { } public ObjectValue(Value value) { - hardAssert( - value.getValueTypeCase() == Value.ValueTypeCase.MAP_VALUE, - "ObjectValues should be backed by a MapValue"); + hardAssert(value.hasMapValue(), "ObjectValues should be backed by a MapValue"); hardAssert( !ServerTimestamps.isServerTimestamp(value), "ServerTimestamps should not be used as an ObjectValue"); @@ -103,7 +101,7 @@ private FieldMask extractFieldMask(MapValue value) { } @Nullable - private Value extractNestedValue(Value value, FieldPath fieldPath) { + private static Value extractNestedValue(Value value, FieldPath fieldPath) { if (fieldPath.isEmpty()) { return value; } else { @@ -180,8 +178,7 @@ private void setOverlay(FieldPath path, @Nullable Value value) { if (currentValue instanceof Map) { // Re-use a previously created map currentLevel = (Map) currentValue; - } else if (currentValue instanceof Value - && ((Value) currentValue).getValueTypeCase() == Value.ValueTypeCase.MAP_VALUE) { + } else if (currentValue instanceof Value && ((Value) currentValue).hasMapValue()) { // Convert the existing Protobuf MapValue into a Java map Map nextLevel = new HashMap<>(((Value) currentValue).getMapValue().getFieldsMap()); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt index d5ae4064d95..afda3ca32ae 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt @@ -267,16 +267,16 @@ internal object Values { } private fun compareNumbers(left: Value, right: Value): Int { - if (left.valueTypeCase == ValueTypeCase.DOUBLE_VALUE) { - if (right.valueTypeCase == ValueTypeCase.DOUBLE_VALUE) { + if (left.hasDoubleValue()) { + if (right.hasDoubleValue()) { return Util.compareDoubles(left.doubleValue, right.doubleValue) - } else if (right.valueTypeCase == ValueTypeCase.INTEGER_VALUE) { + } else if (right.hasIntegerValue()) { return Util.compareMixed(left.doubleValue, right.integerValue) } - } else if (left.valueTypeCase == ValueTypeCase.INTEGER_VALUE) { - if (right.valueTypeCase == ValueTypeCase.INTEGER_VALUE) { + } else if (left.hasIntegerValue()) { + if (right.hasIntegerValue()) { return Util.compareLongs(left.integerValue, right.integerValue) - } else if (right.valueTypeCase == ValueTypeCase.DOUBLE_VALUE) { + } else if (right.hasDoubleValue()) { return -1 * Util.compareMixed(right.doubleValue, left.integerValue) } } @@ -435,13 +435,13 @@ internal object Values { /** Returns true if `value` is a INTEGER_VALUE. */ @JvmStatic fun isInteger(value: Value?): Boolean { - return value != null && value.valueTypeCase == ValueTypeCase.INTEGER_VALUE + return value != null && value.hasIntegerValue() } /** Returns true if `value` is a DOUBLE_VALUE. */ @JvmStatic fun isDouble(value: Value?): Boolean { - return value != null && value.valueTypeCase == ValueTypeCase.DOUBLE_VALUE + return value != null && value.hasDoubleValue() } /** Returns true if `value` is either a INTEGER_VALUE or a DOUBLE_VALUE. */ @@ -453,17 +453,17 @@ internal object Values { /** Returns true if `value` is an ARRAY_VALUE. */ @JvmStatic fun isArray(value: Value?): Boolean { - return value != null && value.valueTypeCase == ValueTypeCase.ARRAY_VALUE + return value != null && value.hasArrayValue() } @JvmStatic fun isReferenceValue(value: Value?): Boolean { - return value != null && value.valueTypeCase == ValueTypeCase.REFERENCE_VALUE + return value != null && value.hasReferenceValue() } @JvmStatic fun isNullValue(value: Value?): Boolean { - return value != null && value.valueTypeCase == ValueTypeCase.NULL_VALUE + return value != null && value.hasNullValue() } @JvmStatic @@ -473,7 +473,7 @@ internal object Values { @JvmStatic fun isMapValue(value: Value?): Boolean { - return value != null && value.valueTypeCase == ValueTypeCase.MAP_VALUE + return value != null && value.hasMapValue() } @JvmStatic diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt index e9bcf7aac43..0edf481cf16 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt @@ -34,6 +34,10 @@ abstract class Constant internal constructor() : Expr() { companion object { internal val NULL: Constant = ValueConstant(Values.NULL_VALUE) + internal fun of(value: Value): Constant { + return ValueConstant(value) + } + @JvmStatic fun of(value: String): Constant { return ValueConstant(encodeValue(value)) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 401aa2ff20a..452d60e6787 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -27,11 +27,13 @@ import com.google.firebase.firestore.model.Values.encodeValue import com.google.firebase.firestore.pipeline.Constant.Companion.of import com.google.firebase.firestore.util.CustomClassMapper import com.google.firestore.v1.MapValue +import com.google.firestore.v1.StructuredQuery.Order import com.google.firestore.v1.Value import java.util.Date import kotlin.reflect.KFunction1 abstract class Expr internal constructor() { + internal companion object { internal fun toExprOrConstant(value: Any?): Expr = toExpr(value, ::toExprOrConstant) @@ -159,14 +161,18 @@ abstract class Expr internal constructor() { fun mod(other: Any) = Function.mod(this, other) - fun inAny(values: List) = Function.inAny(this, values) + fun eqAny(values: List) = Function.eqAny(this, values) - fun notInAny(values: List) = Function.notInAny(this, values) + fun notEqAny(values: List) = Function.notEqAny(this, values) fun isNan() = Function.isNan(this) + fun isNotNan() = Function.isNotNan(this) + fun isNull() = Function.isNull(this) + fun isNotNull() = Function.isNotNull(this) + fun replaceFirst(find: Expr, replace: Expr) = Function.replaceFirst(this, find, replace) fun replaceFirst(find: String, replace: String) = Function.replaceFirst(this, find, replace) @@ -349,6 +355,8 @@ class ExprWithAlias internal constructor(private val alias: String, private val class Field internal constructor(private val fieldPath: ModelFieldPath) : Selectable() { companion object { + @JvmField + val DOCUMENT_ID: Field = of(FieldPath.documentId()) @JvmStatic fun of(name: String): Field { @@ -512,25 +520,35 @@ protected constructor(private val name: String, private val params: Array) = - BooleanExpr("in", array, ListOfExprs(toArrayOfExprOrConstant(values))) + fun eqAny(value: Expr, values: List) = + BooleanExpr("eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic - fun inAny(fieldName: String, values: List) = - BooleanExpr("in", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + fun eqAny(fieldName: String, values: List) = + BooleanExpr("eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) - @JvmStatic fun notInAny(array: Expr, values: List) = not(inAny(array, values)) + @JvmStatic fun notEqAny(value: Expr, values: List) = + BooleanExpr("not_eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) - @JvmStatic fun notInAny(fieldName: String, values: List) = not(inAny(fieldName, values)) + @JvmStatic fun notEqAny(fieldName: String, values: List) = + BooleanExpr("not_eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic fun isNan(expr: Expr) = BooleanExpr("is_nan", expr) @JvmStatic fun isNan(fieldName: String) = BooleanExpr("is_nan", fieldName) + @JvmStatic fun isNotNan(expr: Expr) = BooleanExpr("is_not_nan", expr) + + @JvmStatic fun isNotNan(fieldName: String) = BooleanExpr("is_not_nan", fieldName) + @JvmStatic fun isNull(expr: Expr) = BooleanExpr("is_null", expr) @JvmStatic fun isNull(fieldName: String) = BooleanExpr("is_null", fieldName) + @JvmStatic fun isNotNull(expr: Expr) = BooleanExpr("is_not_null", expr) + + @JvmStatic fun isNotNull(fieldName: String) = BooleanExpr("is_not_null", fieldName) + @JvmStatic fun replaceFirst(value: Expr, find: Expr, replace: Expr) = Function("replace_first", value, find, replace) @@ -932,18 +950,18 @@ protected constructor(private val name: String, private val params: Array) : fun ifThenElse(then: Any, `else`: Any) = ifThenElse(this, then, `else`) } -class Ordering private constructor(private val expr: Expr, private val dir: Direction) { +class Ordering private constructor(val expr: Expr, private val dir: Direction) { companion object { @JvmStatic fun ascending(expr: Expr): Ordering = Ordering(expr, Direction.ASCENDING) @@ -1021,4 +1039,6 @@ class Ordering private constructor(private val expr: Expr, private val dir: Dire .putFields("expression", expr.toProto(userDataReader)) ) .build() + + fun reverse(): Ordering = Ordering(expr, if (dir == Direction.ASCENDING) Direction.DESCENDING else Direction.ASCENDING) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index e4b0345f662..f72ede652ad 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -28,7 +28,7 @@ private constructor(protected val name: String, private val options: InternalOpt internal fun toProtoStage(userDataReader: UserDataReader): Pipeline.Stage { val builder = Pipeline.Stage.newBuilder() builder.setName(name) - args(userDataReader).forEach { arg -> builder.addArgs(arg) } + args(userDataReader).forEach(builder::addArgs) options.forEach(builder::putOptions) return builder.build() } @@ -64,7 +64,8 @@ internal sealed class GenericArg { when (arg) { is AggregateExpr -> AggregateArg(arg) is Ordering -> OrderingArg(arg) - is Map<*, *> -> MapArg(arg.asIterable().associate { it.key as String to from(it.value) }) + is Map<*, *> -> + MapArg(arg.asIterable().associate { (key, value) -> key as String to from(value) }) is List<*> -> ListArg(arg.map(::from)) else -> ExprArg(Expr.toExprOrConstant(arg)) } @@ -120,8 +121,9 @@ internal class CollectionGroupSource internal constructor(val collectionId: Stri internal class DocumentsSource internal constructor(private val documents: Array) : Stage("documents") { + internal constructor(document: String) : this(arrayOf(document)) override fun args(userDataReader: UserDataReader): Sequence = - documents.asSequence().map(::encodeValue) + documents.asSequence().map { if (it.startsWith("/")) it else "/" + it }.map(::encodeValue) } internal class AddFieldsStage internal constructor(private val fields: Array) : @@ -211,12 +213,12 @@ class FindNearestOptions private constructor(options: InternalOptions) : withDistanceField(of(distanceField)) } -internal class LimitStage internal constructor(private val limit: Long) : Stage("limit") { +internal class LimitStage internal constructor(private val limit: Int) : Stage("limit") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(limit)) } -internal class OffsetStage internal constructor(private val offset: Long) : Stage("offset") { +internal class OffsetStage internal constructor(private val offset: Int) : Stage("offset") { override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(offset)) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java index 8e509247524..2e813ac3b98 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java @@ -727,31 +727,39 @@ StructuredQuery.Filter encodeFilter(com.google.firebase.firestore.core.Filter fi @VisibleForTesting StructuredQuery.Filter encodeUnaryOrFieldFilter(FieldFilter filter) { - if (filter.getOperator() == FieldFilter.Operator.EQUAL - || filter.getOperator() == FieldFilter.Operator.NOT_EQUAL) { - UnaryFilter.Builder unaryProto = UnaryFilter.newBuilder(); - unaryProto.setField(encodeFieldPath(filter.getField())); - if (Values.isNanValue(filter.getValue())) { - unaryProto.setOp( - filter.getOperator() == FieldFilter.Operator.EQUAL - ? UnaryFilter.Operator.IS_NAN - : UnaryFilter.Operator.IS_NOT_NAN); - return StructuredQuery.Filter.newBuilder().setUnaryFilter(unaryProto).build(); - } else if (Values.isNullValue(filter.getValue())) { - unaryProto.setOp( - filter.getOperator() == FieldFilter.Operator.EQUAL - ? UnaryFilter.Operator.IS_NULL - : UnaryFilter.Operator.IS_NOT_NULL); - return StructuredQuery.Filter.newBuilder().setUnaryFilter(unaryProto).build(); + FieldFilter.Operator op = filter.getOperator(); + Value value = filter.getValue(); + FieldReference fieldReference = encodeFieldPath(filter.getField()); + if (op == FieldFilter.Operator.EQUAL) { + if (Values.isNanValue(value)) { + return encodeUnaryFilter(fieldReference, UnaryFilter.Operator.IS_NAN); + } + if (Values.isNullValue(value)) { + return encodeUnaryFilter(fieldReference, UnaryFilter.Operator.IS_NULL); + } + } else if (op == FieldFilter.Operator.NOT_EQUAL) { + if (Values.isNanValue(value)) { + return encodeUnaryFilter(fieldReference, UnaryFilter.Operator.IS_NOT_NAN); + } + if (Values.isNullValue(value)) { + return encodeUnaryFilter(fieldReference, UnaryFilter.Operator.IS_NOT_NULL); } } StructuredQuery.FieldFilter.Builder proto = StructuredQuery.FieldFilter.newBuilder(); - proto.setField(encodeFieldPath(filter.getField())); - proto.setOp(encodeFieldFilterOperator(filter.getOperator())); - proto.setValue(filter.getValue()); + proto.setField(fieldReference); + proto.setOp(encodeFieldFilterOperator(op)); + proto.setValue(value); return StructuredQuery.Filter.newBuilder().setFieldFilter(proto).build(); } + private StructuredQuery.Filter encodeUnaryFilter( + FieldReference fieldReference, UnaryFilter.Operator op) { + UnaryFilter.Builder unaryProto = UnaryFilter.newBuilder(); + unaryProto.setField(fieldReference); + unaryProto.setOp(op); + return StructuredQuery.Filter.newBuilder().setUnaryFilter(unaryProto).build(); + } + StructuredQuery.CompositeFilter.Operator encodeCompositeFilterOperator( com.google.firebase.firestore.core.CompositeFilter.Operator op) { switch (op) { From 35a9116d59a45e9f3728cf8dd2aa0a40f750ba12 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 24 Mar 2025 18:38:46 -0400 Subject: [PATCH 32/77] Spotless and Generate API --- firebase-firestore/api.txt | 104 +++++++++++++++--- .../firestore/core/CompositeFilter.java | 3 +- .../google/firebase/firestore/core/Query.java | 12 +- .../firestore/pipeline/expressions.kt | 16 +-- 4 files changed, 107 insertions(+), 28 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index db0a902420e..c3ef4cac64a 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -54,7 +54,6 @@ package com.google.firebase.firestore { method public String getId(); method public com.google.firebase.firestore.DocumentReference? getParent(); method public String getPath(); - method public com.google.firebase.firestore.Pipeline pipeline(); } public class DocumentChange { @@ -432,8 +431,8 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Expr property, double[] vector, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure, com.google.firebase.firestore.pipeline.FindNearestOptions options); method public com.google.firebase.firestore.Pipeline genericStage(com.google.firebase.firestore.pipeline.GenericStage stage); method public com.google.firebase.firestore.Pipeline genericStage(String name, java.lang.Object... arguments); - method public com.google.firebase.firestore.Pipeline limit(long limit); - method public com.google.firebase.firestore.Pipeline offset(long offset); + method public com.google.firebase.firestore.Pipeline limit(int limit); + method public com.google.firebase.firestore.Pipeline offset(int offset); method public com.google.firebase.firestore.Pipeline removeFields(com.google.firebase.firestore.pipeline.Field... fields); method public com.google.firebase.firestore.Pipeline removeFields(java.lang.String... fields); method public com.google.firebase.firestore.Pipeline replace(com.google.firebase.firestore.pipeline.Selectable field); @@ -453,13 +452,17 @@ package com.google.firebase.firestore { } public final class PipelineResult { + method public Object? get(com.google.firebase.firestore.FieldPath fieldPath); + method public Object? get(String field); method public java.util.Map getData(); + method public String? getId(); method public com.google.firebase.firestore.DocumentReference? getRef(); property public final com.google.firebase.firestore.DocumentReference? ref; } - public final class PipelineSnapshot { + public final class PipelineSnapshot implements java.lang.Iterable kotlin.jvm.internal.markers.KMappedMarker { method public java.util.List getResults(); + method public java.util.Iterator iterator(); property public final java.util.List results; } @@ -499,6 +502,7 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Query orderBy(com.google.firebase.firestore.FieldPath, com.google.firebase.firestore.Query.Direction); method public com.google.firebase.firestore.Query orderBy(String); method public com.google.firebase.firestore.Query orderBy(String, com.google.firebase.firestore.Query.Direction); + method public com.google.firebase.firestore.Pipeline pipeline(); method public com.google.firebase.firestore.Query startAfter(com.google.firebase.firestore.DocumentSnapshot); method public com.google.firebase.firestore.Query startAfter(java.lang.Object!...!); method public com.google.firebase.firestore.Query startAt(com.google.firebase.firestore.DocumentSnapshot); @@ -780,6 +784,17 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.ExprWithAlias as(String alias); method public final com.google.firebase.firestore.pipeline.Ordering ascending(); method public final com.google.firebase.firestore.pipeline.AggregateExpr avg(); + method public final com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr right); + method public final com.google.firebase.firestore.pipeline.Function bitAnd(Object right); + method public final com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr numberExpr); + method public final com.google.firebase.firestore.pipeline.Function bitLeftShift(int number); + method public final com.google.firebase.firestore.pipeline.Function bitNot(); + method public final com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr right); + method public final com.google.firebase.firestore.pipeline.Function bitOr(Object right); + method public final com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr numberExpr); + method public final com.google.firebase.firestore.pipeline.Function bitRightShift(int number); + method public final com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr right); + method public final com.google.firebase.firestore.pipeline.Function bitXor(Object right); method public final com.google.firebase.firestore.pipeline.Function byteLength(); method public final com.google.firebase.firestore.pipeline.Function charLength(); method public final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector); @@ -795,15 +810,18 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String suffix); method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(Object other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(java.util.List values); method public final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector); method public final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.VectorValue vector); method public final com.google.firebase.firestore.pipeline.Function euclideanDistance(double[] vector); + method public final com.google.firebase.firestore.pipeline.BooleanExpr exists(); method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(Object other); method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(Object other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr inAny(java.util.List values); method public final com.google.firebase.firestore.pipeline.BooleanExpr isNan(); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(); method public final com.google.firebase.firestore.pipeline.BooleanExpr isNull(); method public final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr like(String pattern); @@ -825,7 +843,7 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Function multiply(Object other); method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(Object other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr notInAny(java.util.List values); + method public final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(java.util.List values); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr pattern); @@ -868,6 +886,7 @@ package com.google.firebase.firestore.pipeline { method public static com.google.firebase.firestore.pipeline.Field of(com.google.firebase.firestore.FieldPath fieldPath); method public static com.google.firebase.firestore.pipeline.Field of(String name); field public static final com.google.firebase.firestore.pipeline.Field.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.Field DOCUMENT_ID; } public static final class Field.Companion { @@ -925,6 +944,28 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Function arrayLength(String fieldName); method public static final com.google.firebase.firestore.pipeline.Function arrayReverse(com.google.firebase.firestore.pipeline.Expr array); method public static final com.google.firebase.firestore.pipeline.Function arrayReverse(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function bitAnd(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public static final com.google.firebase.firestore.pipeline.Function bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Function bitLeftShift(String fieldName, int number); + method public static final com.google.firebase.firestore.pipeline.Function bitNot(com.google.firebase.firestore.pipeline.Expr left); + method public static final com.google.firebase.firestore.pipeline.Function bitNot(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function bitOr(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public static final com.google.firebase.firestore.pipeline.Function bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Function bitRightShift(String fieldName, int number); + method public static final com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.Function bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Function bitXor(String fieldName, Object right); method public static final com.google.firebase.firestore.pipeline.Function byteLength(com.google.firebase.firestore.pipeline.Expr value); method public static final com.google.firebase.firestore.pipeline.Function byteLength(String fieldName); method public static final com.google.firebase.firestore.pipeline.Function charLength(com.google.firebase.firestore.pipeline.Expr value); @@ -953,12 +994,15 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, java.util.List values); method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Function generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); @@ -972,10 +1016,12 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then); method public static final com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr else); method public static final com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object else); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr inAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr inAny(String fieldName, java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(String fieldName); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(String fieldName); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNull(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNull(String fieldName); method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); @@ -1015,8 +1061,8 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr not(com.google.firebase.firestore.pipeline.BooleanExpr condition); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr notInAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr notInAny(String fieldName, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(String fieldName, java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr or(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); @@ -1104,6 +1150,28 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Function arrayLength(String fieldName); method public com.google.firebase.firestore.pipeline.Function arrayReverse(com.google.firebase.firestore.pipeline.Expr array); method public com.google.firebase.firestore.pipeline.Function arrayReverse(String fieldName); + method public com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function bitAnd(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public com.google.firebase.firestore.pipeline.Function bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Function bitLeftShift(String fieldName, int number); + method public com.google.firebase.firestore.pipeline.Function bitNot(com.google.firebase.firestore.pipeline.Expr left); + method public com.google.firebase.firestore.pipeline.Function bitNot(String fieldName); + method public com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function bitOr(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public com.google.firebase.firestore.pipeline.Function bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Function bitRightShift(String fieldName, int number); + method public com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Function bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Function bitXor(String fieldName, Object right); method public com.google.firebase.firestore.pipeline.Function byteLength(com.google.firebase.firestore.pipeline.Expr value); method public com.google.firebase.firestore.pipeline.Function byteLength(String fieldName); method public com.google.firebase.firestore.pipeline.Function charLength(com.google.firebase.firestore.pipeline.Expr value); @@ -1132,12 +1200,15 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, java.util.List values); method public com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); method public com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); method public com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); method public com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); method public com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); method public com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Function generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); @@ -1151,10 +1222,12 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then); method public com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr else); method public com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object else); - method public com.google.firebase.firestore.pipeline.BooleanExpr inAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); - method public com.google.firebase.firestore.pipeline.BooleanExpr inAny(String fieldName, java.util.List values); method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); + method public com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(String fieldName); + method public com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr isNull(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.BooleanExpr isNull(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); @@ -1194,8 +1267,8 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr not(com.google.firebase.firestore.pipeline.BooleanExpr condition); - method public com.google.firebase.firestore.pipeline.BooleanExpr notInAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); - method public com.google.firebase.firestore.pipeline.BooleanExpr notInAny(String fieldName, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(String fieldName, java.util.List values); method public com.google.firebase.firestore.pipeline.BooleanExpr or(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); @@ -1284,6 +1357,9 @@ package com.google.firebase.firestore.pipeline { method public static com.google.firebase.firestore.pipeline.Ordering ascending(String fieldName); method public static com.google.firebase.firestore.pipeline.Ordering descending(com.google.firebase.firestore.pipeline.Expr expr); method public static com.google.firebase.firestore.pipeline.Ordering descending(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr getExpr(); + method public com.google.firebase.firestore.pipeline.Ordering reverse(); + property public final com.google.firebase.firestore.pipeline.Expr expr; field public static final com.google.firebase.firestore.pipeline.Ordering.Companion Companion; } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java index c9ed9c6c0e3..ee471318f80 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java @@ -170,7 +170,8 @@ public String getCanonicalId() { @Override BooleanExpr toPipelineExpr() { - BooleanExpr[] booleanExprs = filters.stream().map(Filter::toPipelineExpr).toArray(BooleanExpr[]::new); + BooleanExpr[] booleanExprs = + filters.stream().map(Filter::toPipelineExpr).toArray(BooleanExpr[]::new); switch (operator) { case AND: return new BooleanExpr("and", booleanExprs); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index a923be48e8d..266b280d41f 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -38,9 +38,7 @@ import com.google.firebase.firestore.pipeline.Ordering; import com.google.firebase.firestore.pipeline.Stage; import com.google.firestore.v1.Value; - import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; @@ -48,7 +46,6 @@ import java.util.SortedSet; import java.util.TreeSet; import java.util.function.BiFunction; -import java.util.stream.Collectors; /** * Encapsulates all the query attributes we support in the SDK. It can be run against the @@ -549,7 +546,9 @@ public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataR if (fields.size() == 1) { p = p.where(fields.get(0).exists()); } else { - p = p.where(and(fields.get(0).exists(), fields.stream().skip(1).map(Expr::exists).toArray(BooleanExpr[]::new))); + BooleanExpr[] conditions = + fields.stream().skip(1).map(Expr::exists).toArray(BooleanExpr[]::new); + p = p.where(and(fields.get(0).exists(), conditions)); } if (startAt != null) { @@ -578,7 +577,8 @@ public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataR return p; } - private static BooleanExpr whereConditionsFromCursor(Bound bound, List fields, BiFunction cmp) { + private static BooleanExpr whereConditionsFromCursor( + Bound bound, List fields, BiFunction cmp) { List boundPosition = bound.getPosition(); int size = boundPosition.size(); hardAssert(size <= fields.size(), "Bound positions must not exceed order fields."); @@ -587,7 +587,7 @@ private static BooleanExpr whereConditionsFromCursor(Bound bound, List fi if (bound.isInclusive()) { condition = or(condition, Function.eq(fields.get(last), boundPosition.get(last))); } - for (int i = size - 2; i >=0; i--) { + for (int i = size - 2; i >= 0; i--) { final Field field = fields.get(i); final Value value = boundPosition.get(i); condition = or(cmp.apply(field, value), and(field.eq(value), condition)); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 452d60e6787..005fdbd9068 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -27,7 +27,6 @@ import com.google.firebase.firestore.model.Values.encodeValue import com.google.firebase.firestore.pipeline.Constant.Companion.of import com.google.firebase.firestore.util.CustomClassMapper import com.google.firestore.v1.MapValue -import com.google.firestore.v1.StructuredQuery.Order import com.google.firestore.v1.Value import java.util.Date import kotlin.reflect.KFunction1 @@ -355,8 +354,7 @@ class ExprWithAlias internal constructor(private val alias: String, private val class Field internal constructor(private val fieldPath: ModelFieldPath) : Selectable() { companion object { - @JvmField - val DOCUMENT_ID: Field = of(FieldPath.documentId()) + @JvmField val DOCUMENT_ID: Field = of(FieldPath.documentId()) @JvmStatic fun of(name: String): Field { @@ -527,10 +525,12 @@ protected constructor(private val name: String, private val params: Array) = BooleanExpr("eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) - @JvmStatic fun notEqAny(value: Expr, values: List) = + @JvmStatic + fun notEqAny(value: Expr, values: List) = BooleanExpr("not_eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) - @JvmStatic fun notEqAny(fieldName: String, values: List) = + @JvmStatic + fun notEqAny(fieldName: String, values: List) = BooleanExpr("not_eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) @JvmStatic fun isNan(expr: Expr) = BooleanExpr("is_nan", expr) @@ -950,7 +950,8 @@ protected constructor(private val name: String, private val params: Array Date: Wed, 2 Apr 2025 11:03:08 -0400 Subject: [PATCH 33/77] Fixups --- .../firebase/firestore/PipelineTest.java | 144 ++++++---- .../firestore/QueryToPipelineTest.java | 252 +++++++++++------- .../firebase/firestore/AggregateField.java | 24 ++ .../firestore/CollectionReference.java | 7 - .../com/google/firebase/firestore/Pipeline.kt | 27 +- .../com/google/firebase/firestore/Query.java | 5 - .../firebase/firestore/pipeline/aggregates.kt | 2 +- .../firestore/pipeline/expressions.kt | 78 +++--- 8 files changed, 335 insertions(+), 204 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 7498bfccff2..7b69f8f216b 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -25,7 +25,6 @@ import static com.google.firebase.firestore.pipeline.Function.euclideanDistance; import static com.google.firebase.firestore.pipeline.Function.gt; import static com.google.firebase.firestore.pipeline.Function.logicalMax; -import static com.google.firebase.firestore.pipeline.Function.logicalMin; import static com.google.firebase.firestore.pipeline.Function.lt; import static com.google.firebase.firestore.pipeline.Function.lte; import static com.google.firebase.firestore.pipeline.Function.mapGet; @@ -227,7 +226,7 @@ public void aggregateResultsCountAll() { firestore .pipeline() .collection(randomCol) - .aggregate(AggregateExpr.countAll().as("count")) + .aggregate(AggregateExpr.countAll().alias("count")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -243,9 +242,9 @@ public void aggregateResultsMany() { .collection(randomCol) .where(Function.eq("genre", "Science Fiction")) .aggregate( - AggregateExpr.countAll().as("count"), - AggregateExpr.avg("rating").as("avgRating"), - Field.of("rating").max().as("maxRating")) + AggregateExpr.countAll().alias("count"), + AggregateExpr.avg("rating").alias("avgRating"), + Field.of("rating").max().alias("maxRating")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -261,7 +260,7 @@ public void groupAndAccumulateResults() { .collection(randomCol) .where(lt(Field.of("published"), 1984)) .aggregate( - AggregateStage.withAccumulators(AggregateExpr.avg("rating").as("avgRating")) + AggregateStage.withAccumulators(AggregateExpr.avg("rating").alias("avgRating")) .withGroups("genre")) .where(gt("avgRating", 4.3)) .sort(Field.of("avgRating").descending()) @@ -304,9 +303,9 @@ public void minAndMaxAccumulations() { .pipeline() .collection(randomCol) .aggregate( - AggregateExpr.countAll().as("count"), - Field.of("rating").max().as("maxRating"), - Field.of("published").min().as("minPublished")) + AggregateExpr.countAll().alias("count"), + Field.of("rating").max().alias("maxRating"), + Field.of("published").min().alias("minPublished")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -443,9 +442,10 @@ public void arrayContainsAllWorks() { @Test public void arrayLengthWorks() { Task execute = - randomCol + firestore .pipeline() - .select(Field.of("tags").arrayLength().as("tagsCount")) + .collection(randomCol) + .select(Field.of("tags").arrayLength().alias("tagsCount")) .where(eq("tagsCount", 3)) .execute(); assertThat(waitFor(execute).getResults()).hasSize(10); @@ -462,7 +462,7 @@ public void arrayConcatWorks() { .select( Field.of("tags") .arrayConcat(ImmutableList.of("newTag1", "newTag2")) - .as("modifiedTags")) + .alias("modifiedTags")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -476,9 +476,10 @@ public void arrayConcatWorks() { @Test public void testStrConcat() { Task execute = - randomCol + firestore .pipeline() - .select(Field.of("author").strConcat(" - ", Field.of("title")).as("bookInfo")) + .collection(randomCol) + .select(Field.of("author").strConcat(" - ", Field.of("title")).alias("bookInfo")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -490,8 +491,9 @@ public void testStrConcat() { @Test public void testStartsWith() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where(startsWith("title", "The")) .select("title") .sort(Field.of("title").ascending()) @@ -508,8 +510,9 @@ public void testStartsWith() { @Test public void testEndsWith() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where(endsWith("title", "y")) .select("title") .sort(Field.of("title").descending()) @@ -524,9 +527,10 @@ public void testEndsWith() { @Test public void testLength() { Task execute = - randomCol + firestore .pipeline() - .select(Field.of("title").charLength().as("titleLength"), Field.of("title")) + .collection(randomCol) + .select(Field.of("title").charLength().alias("titleLength"), Field.of("title")) .where(gt("titleLength", 20)) .sort(Field.of("title").ascending()) .execute(); @@ -543,9 +547,10 @@ public void testLength() { @Ignore("Not supported yet") public void testToLowercase() { Task execute = - randomCol + firestore .pipeline() - .select(Field.of("title").toLower().as("lowercaseTitle")) + .collection(randomCol) + .select(Field.of("title").toLower().alias("lowercaseTitle")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -557,9 +562,10 @@ public void testToLowercase() { @Ignore("Not supported yet") public void testToUppercase() { Task execute = - randomCol + firestore .pipeline() - .select(Field.of("author").toLower().as("uppercaseAuthor")) + .collection(randomCol) + .select(Field.of("author").toLower().alias("uppercaseAuthor")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -571,10 +577,11 @@ public void testToUppercase() { @Ignore("Not supported yet") public void testTrim() { Task execute = - randomCol + firestore .pipeline() - .addFields(strConcat(" ", Field.of("title"), " ").as("spacedTitle")) - .select(Field.of("spacedTitle").trim().as("trimmedTitle")) + .collection(randomCol) + .addFields(strConcat(" ", Field.of("title"), " ").alias("spacedTitle")) + .select(Field.of("spacedTitle").trim().alias("trimmedTitle")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -590,7 +597,12 @@ public void testTrim() { @Test public void testLike() { Task execute = - randomCol.pipeline().where(Function.like("title", "%Guide%")).select("title").execute(); + firestore + .pipeline() + .collection(randomCol) + .where(Function.like("title", "%Guide%")) + .select("title") + .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly(ImmutableMap.of("title", "The Hitchhiker's Guide to the Galaxy")); @@ -599,27 +611,36 @@ public void testLike() { @Test public void testRegexContains() { Task execute = - randomCol.pipeline().where(Function.regexContains("title", "(?i)(the|of)")).execute(); + firestore + .pipeline() + .collection(randomCol) + .where(Function.regexContains("title", "(?i)(the|of)")) + .execute(); assertThat(waitFor(execute).getResults()).hasSize(5); } @Test public void testRegexMatches() { Task execute = - randomCol.pipeline().where(Function.regexContains("title", ".*(?i)(the|of).*")).execute(); + firestore + .pipeline() + .collection(randomCol) + .where(Function.regexContains("title", ".*(?i)(the|of).*")) + .execute(); assertThat(waitFor(execute).getResults()).hasSize(5); } @Test public void testArithmeticOperations() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .select( - add(Field.of("rating"), 1).as("ratingPlusOne"), - subtract(Field.of("published"), 1900).as("yearsSince1900"), - Field.of("rating").multiply(10).as("ratingTimesTen"), - Field.of("rating").divide(2).as("ratingDividedByTwo")) + add(Field.of("rating"), 1).alias("ratingPlusOne"), + subtract(Field.of("published"), 1900).alias("yearsSince1900"), + Field.of("rating").multiply(10).alias("ratingTimesTen"), + Field.of("rating").divide(2).alias("ratingDividedByTwo")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -635,8 +656,9 @@ public void testArithmeticOperations() { @Test public void testComparisonOperators() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where( and( gt("rating", 4.2), @@ -656,8 +678,9 @@ public void testComparisonOperators() { @Test public void testLogicalOperators() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where( or( and(gt("rating", 4.5), eq("genre", "Science Fiction")), @@ -676,13 +699,14 @@ public void testLogicalOperators() { @Test public void testChecks() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where(not(Field.of("rating").isNan())) .select( - Field.of("rating").isNull().as("ratingIsNull"), - Field.of("rating").eq(Constant.nullValue()).as("ratingEqNull"), - not(Field.of("rating").isNan()).as("ratingIsNotNan")) + Field.of("rating").isNull().alias("ratingIsNull"), + Field.of("rating").eq(Constant.nullValue()).alias("ratingEqNull"), + not(Field.of("rating").isNan()).alias("ratingIsNotNan")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -698,12 +722,13 @@ public void testChecks() { @Ignore("Not supported yet") public void testLogicalMax() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where(Field.of("author").eq("Douglas Adams")) .select( - Field.of("rating").logicalMax(4.5).as("max_rating"), - logicalMax(Field.of("published"), 1900).as("max_published")) + Field.of("rating").logicalMax(4.5).alias("max_rating"), + logicalMax(Field.of("published"), 1900).alias("max_published")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -714,12 +739,7 @@ public void testLogicalMax() { @Ignore("Not supported yet") public void testLogicalMin() { Task execute = - randomCol - .pipeline() - .select( - Field.of("rating").logicalMin(4.5).as("min_rating"), - logicalMin(Field.of("published"), 1900).as("min_published")) - .execute(); + firestore.pipeline().collection(randomCol).sort(Field.of("rating").ascending()).execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly(ImmutableMap.of("min_rating", 4.2, "min_published", 1900)); @@ -728,9 +748,10 @@ public void testLogicalMin() { @Test public void testMapGet() { Task execute = - randomCol + firestore .pipeline() - .select(Field.of("awards").mapGet("hugo").as("hugoAward"), Field.of("title")) + .collection(randomCol) + .select(Field.of("awards").mapGet("hugo").alias("hugoAward"), Field.of("title")) .where(eq("hugoAward", true)) .execute(); assertThat(waitFor(execute).getResults()) @@ -745,14 +766,15 @@ public void testDistanceFunctions() { double[] sourceVector = {0.1, 0.1}; double[] targetVector = {0.5, 0.8}; Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .select( - cosineDistance(Constant.vector(sourceVector), targetVector).as("cosineDistance"), + cosineDistance(Constant.vector(sourceVector), targetVector).alias("cosineDistance"), Function.dotProduct(Constant.vector(sourceVector), targetVector) - .as("dotProductDistance"), + .alias("dotProductDistance"), euclideanDistance(Constant.vector(sourceVector), targetVector) - .as("euclideanDistance")) + .alias("euclideanDistance")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -767,8 +789,9 @@ public void testDistanceFunctions() { @Test public void testNestedFields() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where(eq("awards.hugo", true)) .select("title", "awards.hugo") .execute(); @@ -782,13 +805,14 @@ public void testNestedFields() { @Test public void testMapGetWithFieldNameIncludingNotation() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where(eq("awards.hugo", true)) .select( "title", Field.of("nestedField.level.1"), - mapGet("nestedField", "level.1").mapGet("level.2").as("nested")) + mapGet("nestedField", "level.1").mapGet("level.2").alias("nested")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -806,8 +830,9 @@ public void testMapGetWithFieldNameIncludingNotation() { @Test public void testListEquals() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where(eq("tags", ImmutableList.of("philosophy", "crime", "redemption"))) .execute(); assertThat(waitFor(execute).getResults()) @@ -818,8 +843,9 @@ public void testListEquals() { @Test public void testMapEquals() { Task execute = - randomCol + firestore .pipeline() + .collection(randomCol) .where(eq("awards", ImmutableMap.of("nobel", true, "nebula", false))) .execute(); assertThat(waitFor(execute).getResults()) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java index c4f8f33bb01..188b047f739 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java @@ -21,7 +21,6 @@ import static com.google.firebase.firestore.Filter.equalTo; import static com.google.firebase.firestore.Filter.inArray; import static com.google.firebase.firestore.Filter.or; -import static com.google.firebase.firestore.pipeline.Function.ifThen; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.checkQueryAndPipelineResultsMatch; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.nullList; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.pipelineSnapshotToIds; @@ -41,8 +40,6 @@ import com.google.android.gms.tasks.Task; import com.google.common.collect.Lists; import com.google.firebase.firestore.Query.Direction; -import com.google.firebase.firestore.pipeline.Constant; -import com.google.firebase.firestore.pipeline.Field; import com.google.firebase.firestore.testutil.IntegrationTestUtil; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -70,7 +67,8 @@ public void testLimitQueries() { "c", map("k", "c"))); Query query = collection.limit(2); - PipelineSnapshot set = waitFor(query.pipeline().execute()); + FirebaseFirestore db = collection.firestore; + PipelineSnapshot set = waitFor(db.pipeline().createFrom(query).execute()); List> data = pipelineSnapshotToValues(set); assertEquals(asList(map("k", "a"), map("k", "b")), data); } @@ -86,7 +84,9 @@ public void testLimitQueriesUsingDescendingSortOrder() { "d", map("k", "d", "sort", 2))); Query query = collection.limit(2).orderBy("sort", Direction.DESCENDING); - PipelineSnapshot set = waitFor(query.pipeline().execute()); + FirebaseFirestore db = collection.firestore; + PipelineSnapshot set = waitFor(db.pipeline().createFrom(query).execute()); + List> data = pipelineSnapshotToValues(set); assertEquals(asList(map("k", "d", "sort", 2L), map("k", "c", "sort", 1L)), data); } @@ -94,10 +94,11 @@ public void testLimitQueriesUsingDescendingSortOrder() { @Test public void testLimitToLastMustAlsoHaveExplicitOrderBy() { CollectionReference collection = testCollectionWithDocs(map()); + FirebaseFirestore db = collection.firestore; Query query = collection.limitToLast(2); expectError( - () -> waitFor(query.pipeline().execute()), + () -> waitFor(db.pipeline().createFrom(query).execute()), "limitToLast() queries require specifying at least one orderBy() clause"); } @@ -112,33 +113,35 @@ public void testLimitToLastQueriesWithCursors() { "d", map("k", "d", "sort", 2))); Query query = collection.limitToLast(3).orderBy("sort").endBefore(2); - PipelineSnapshot set = waitFor(query.pipeline().execute()); + FirebaseFirestore db = collection.firestore; + + PipelineSnapshot set = waitFor(db.pipeline().createFrom(query).execute()); List> data = pipelineSnapshotToValues(set); assertEquals( asList(map("k", "a", "sort", 0L), map("k", "b", "sort", 1L), map("k", "c", "sort", 1L)), data); query = collection.limitToLast(3).orderBy("sort").endAt(1); - set = waitFor(query.pipeline().execute()); + set = waitFor(db.pipeline().createFrom(query).execute()); data = pipelineSnapshotToValues(set); assertEquals( asList(map("k", "a", "sort", 0L), map("k", "b", "sort", 1L), map("k", "c", "sort", 1L)), data); query = collection.limitToLast(3).orderBy("sort").startAt(2); - set = waitFor(query.pipeline().execute()); + set = waitFor(db.pipeline().createFrom(query).execute()); data = pipelineSnapshotToValues(set); assertEquals(asList(map("k", "d", "sort", 2L)), data); query = collection.limitToLast(3).orderBy("sort").startAfter(0); - set = waitFor(query.pipeline().execute()); + set = waitFor(db.pipeline().createFrom(query).execute()); data = pipelineSnapshotToValues(set); assertEquals( asList(map("k", "b", "sort", 1L), map("k", "c", "sort", 1L), map("k", "d", "sort", 2L)), data); query = collection.limitToLast(3).orderBy("sort").startAfter(-1); - set = waitFor(query.pipeline().execute()); + set = waitFor(db.pipeline().createFrom(query).execute()); data = pipelineSnapshotToValues(set); assertEquals( asList(map("k", "b", "sort", 1L), map("k", "c", "sort", 1L), map("k", "d", "sort", 2L)), @@ -159,7 +162,8 @@ public void testKeyOrderIsDescendingForDescendingInequality() { "g", map("foo", 66.0))); Query query = collection.whereGreaterThan("foo", 21.0).orderBy("foo", Direction.DESCENDING); - PipelineSnapshot result = waitFor(query.pipeline().execute()); + FirebaseFirestore db = collection.firestore; + PipelineSnapshot result = waitFor(db.pipeline().createFrom(query).execute()); assertEquals(asList("g", "f", "c", "b", "a"), pipelineSnapshotToIds(result)); } @@ -171,12 +175,11 @@ public void testUnaryFilterQueries() { "a", map("null", null, "nan", Double.NaN), "b", map("null", null, "nan", 0), "c", map("null", false, "nan", Double.NaN))); + FirebaseFirestore db = collection.firestore; PipelineSnapshot results = waitFor( - collection - .whereEqualTo("null", null) - .whereEqualTo("nan", Double.NaN) - .pipeline() + db.pipeline() + .createFrom(collection.whereEqualTo("null", null).whereEqualTo("nan", Double.NaN)) .execute()); assertEquals(1, results.getResults().size()); PipelineResult result = results.getResults().get(0); @@ -192,8 +195,12 @@ public void testFilterOnInfinity() { map( "a", map("inf", Double.POSITIVE_INFINITY), "b", map("inf", Double.NEGATIVE_INFINITY))); + FirebaseFirestore db = collection.firestore; PipelineSnapshot results = - waitFor(collection.whereEqualTo("inf", Double.POSITIVE_INFINITY).pipeline().execute()); + waitFor( + db.pipeline() + .createFrom(collection.whereEqualTo("inf", Double.POSITIVE_INFINITY)) + .execute()); assertEquals(1, results.getResults().size()); assertEquals(asList(map("inf", Double.POSITIVE_INFINITY)), pipelineSnapshotToValues(results)); } @@ -206,10 +213,11 @@ public void testCanExplicitlySortByDocumentId() { "b", map("key", "b"), "c", map("key", "c")); CollectionReference collection = testCollectionWithDocs(testDocs); + FirebaseFirestore db = collection.firestore; // Ideally this would be descending to validate it's different than // the default, but that requires an extra index PipelineSnapshot docs = - waitFor(collection.orderBy(FieldPath.documentId()).pipeline().execute()); + waitFor(db.pipeline().createFrom(collection.orderBy(FieldPath.documentId())).execute()); assertEquals( asList(testDocs.get("a"), testDocs.get("b"), testDocs.get("c")), pipelineSnapshotToValues(docs)); @@ -224,16 +232,21 @@ public void testCanQueryByDocumentId() { "ba", map("key", "ba"), "bb", map("key", "bb")); CollectionReference collection = testCollectionWithDocs(testDocs); + FirebaseFirestore db = collection.firestore; PipelineSnapshot docs = - waitFor(collection.whereEqualTo(FieldPath.documentId(), "ab").pipeline().execute()); + waitFor( + db.pipeline() + .createFrom(collection.whereEqualTo(FieldPath.documentId(), "ab")) + .execute()); assertEquals(singletonList(testDocs.get("ab")), pipelineSnapshotToValues(docs)); docs = waitFor( - collection - .whereGreaterThan(FieldPath.documentId(), "aa") - .whereLessThanOrEqualTo(FieldPath.documentId(), "ba") - .pipeline() + db.pipeline() + .createFrom( + collection + .whereGreaterThan(FieldPath.documentId(), "aa") + .whereLessThanOrEqualTo(FieldPath.documentId(), "ba")) .execute()); assertEquals(asList(testDocs.get("ab"), testDocs.get("ba")), pipelineSnapshotToValues(docs)); } @@ -247,20 +260,22 @@ public void testCanQueryByDocumentIdUsingRefs() { "ba", map("key", "ba"), "bb", map("key", "bb")); CollectionReference collection = testCollectionWithDocs(testDocs); + FirebaseFirestore db = collection.firestore; PipelineSnapshot docs = waitFor( - collection - .whereEqualTo(FieldPath.documentId(), collection.document("ab")) - .pipeline() + db.pipeline() + .createFrom( + collection.whereEqualTo(FieldPath.documentId(), collection.document("ab"))) .execute()); assertEquals(singletonList(testDocs.get("ab")), pipelineSnapshotToValues(docs)); docs = waitFor( - collection - .whereGreaterThan(FieldPath.documentId(), collection.document("aa")) - .whereLessThanOrEqualTo(FieldPath.documentId(), collection.document("ba")) - .pipeline() + db.pipeline() + .createFrom( + collection + .whereGreaterThan(FieldPath.documentId(), collection.document("aa")) + .whereLessThanOrEqualTo(FieldPath.documentId(), collection.document("ba"))) .execute()); assertEquals(asList(testDocs.get("ab"), testDocs.get("ba")), pipelineSnapshotToValues(docs)); } @@ -268,10 +283,13 @@ public void testCanQueryByDocumentIdUsingRefs() { @Test public void testCanQueryWithAndWithoutDocumentKey() { CollectionReference collection = testCollection(); + FirebaseFirestore db = collection.firestore; collection.add(map()); Task query1 = - collection.orderBy(FieldPath.documentId(), Direction.ASCENDING).pipeline().execute(); - Task query2 = collection.pipeline().execute(); + db.pipeline() + .createFrom(collection.orderBy(FieldPath.documentId(), Direction.ASCENDING)) + .execute(); + Task query2 = db.pipeline().createFrom(collection).execute(); waitFor(query1); waitFor(query2); @@ -300,6 +318,7 @@ public void testQueriesCanUseNotEqualFilters() { "a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", docH, "i", docI, "j", docJ); CollectionReference collection = testCollectionWithDocs(allDocs); + FirebaseFirestore db = collection.firestore; // Search for zips not matching 98101. Map> expectedDocsMap = new LinkedHashMap<>(allDocs); @@ -308,7 +327,7 @@ public void testQueriesCanUseNotEqualFilters() { expectedDocsMap.remove("j"); PipelineSnapshot snapshot = - waitFor(collection.whereNotEqualTo("zip", 98101L).pipeline().execute()); + waitFor(db.pipeline().createFrom(collection.whereNotEqualTo("zip", 98101L)).execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); // With objects. @@ -316,29 +335,27 @@ public void testQueriesCanUseNotEqualFilters() { expectedDocsMap.remove("h"); expectedDocsMap.remove("i"); expectedDocsMap.remove("j"); - snapshot = waitFor(collection.whereNotEqualTo("zip", map("code", 500)).pipeline().execute()); + snapshot = + waitFor( + db.pipeline() + .createFrom(collection.whereNotEqualTo("zip", map("code", 500))) + .execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); // With Null. expectedDocsMap = new LinkedHashMap<>(allDocs); expectedDocsMap.remove("i"); expectedDocsMap.remove("j"); - snapshot = waitFor(collection.whereNotEqualTo("zip", null).pipeline().execute()); + snapshot = waitFor(db.pipeline().createFrom(collection.whereNotEqualTo("zip", null)).execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); - List pipelineResults = waitFor(collection.pipeline() - .addFields( - Field.of("zip").isNan().as("isNan1"), - ifThen(Field.of("zip").isNan(), Constant.of(true)).as("isNan2"), - ifThen(Field.of("zip").isNan(), Constant.of(true)).isNotNull().as("isNan3") - ).execute()).getResults(); - // With NaN. expectedDocsMap = new LinkedHashMap<>(allDocs); expectedDocsMap.remove("a"); expectedDocsMap.remove("i"); expectedDocsMap.remove("j"); - snapshot = waitFor(collection.whereEqualTo("zip", Double.NaN).pipeline().execute()); + snapshot = + waitFor(db.pipeline().createFrom(collection.whereEqualTo("zip", Double.NaN)).execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); } @@ -355,8 +372,12 @@ public void testQueriesCanUseNotEqualFiltersWithDocIds() { "ba", docC, "bb", docD); CollectionReference collection = testCollectionWithDocs(testDocs); + FirebaseFirestore db = collection.firestore; PipelineSnapshot docs = - waitFor(collection.whereNotEqualTo(FieldPath.documentId(), "aa").pipeline().execute()); + waitFor( + db.pipeline() + .createFrom(collection.whereNotEqualTo(FieldPath.documentId(), "aa")) + .execute()); assertEquals(asList(docB, docC, docD), pipelineSnapshotToValues(docs)); } @@ -371,15 +392,18 @@ public void testQueriesCanUseArrayContainsFilters() { CollectionReference collection = testCollectionWithDocs( map("a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF)); + FirebaseFirestore db = collection.firestore; // Search for "array" to contain 42 PipelineSnapshot snapshot = - waitFor(collection.whereArrayContains("array", 42L).pipeline().execute()); + waitFor(db.pipeline().createFrom(collection.whereArrayContains("array", 42L)).execute()); assertEquals(asList(docA, docB, docD), pipelineSnapshotToValues(snapshot)); // Note: whereArrayContains() requires a non-null value parameter, so no null test is needed. // With NaN. - snapshot = waitFor(collection.whereArrayContains("array", Double.NaN).pipeline().execute()); + snapshot = + waitFor( + db.pipeline().createFrom(collection.whereArrayContains("array", Double.NaN)).execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); } @@ -400,36 +424,46 @@ public void testQueriesCanUseInFilters() { map( "a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", docH, "i", docI)); + FirebaseFirestore db = collection.firestore; // Search for zips matching 98101, 98103, or [98101, 98102]. PipelineSnapshot snapshot = waitFor( - collection - .whereIn("zip", asList(98101L, 98103L, asList(98101L, 98102L))) - .pipeline() + db.pipeline() + .createFrom( + collection.whereIn("zip", asList(98101L, 98103L, asList(98101L, 98102L)))) .execute()); assertEquals(asList(docA, docC, docG), pipelineSnapshotToValues(snapshot)); // With objects. - snapshot = waitFor(collection.whereIn("zip", asList(map("code", 500L))).pipeline().execute()); + snapshot = + waitFor( + db.pipeline() + .createFrom(collection.whereIn("zip", asList(map("code", 500L)))) + .execute()); assertEquals(asList(docF), pipelineSnapshotToValues(snapshot)); // With null. - snapshot = waitFor(collection.whereIn("zip", nullList()).pipeline().execute()); + snapshot = waitFor(db.pipeline().createFrom(collection.whereIn("zip", nullList())).execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With null and a value. List inputList = nullList(); inputList.add(98101L); - snapshot = waitFor(collection.whereIn("zip", inputList).pipeline().execute()); + snapshot = waitFor(db.pipeline().createFrom(collection.whereIn("zip", inputList)).execute()); assertEquals(asList(docA), pipelineSnapshotToValues(snapshot)); // With NaN. - snapshot = waitFor(collection.whereIn("zip", asList(Double.NaN)).pipeline().execute()); + snapshot = + waitFor(db.pipeline().createFrom(collection.whereIn("zip", asList(Double.NaN))).execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With NaN and a value. - snapshot = waitFor(collection.whereIn("zip", asList(Double.NaN, 98101L)).pipeline().execute()); + snapshot = + waitFor( + db.pipeline() + .createFrom(collection.whereIn("zip", asList(Double.NaN, 98101L))) + .execute()); assertEquals(asList(docA), pipelineSnapshotToValues(snapshot)); } @@ -446,9 +480,12 @@ public void testQueriesCanUseInFiltersWithDocIds() { "ba", docC, "bb", docD); CollectionReference collection = testCollectionWithDocs(testDocs); + FirebaseFirestore db = collection.firestore; PipelineSnapshot docs = waitFor( - collection.whereIn(FieldPath.documentId(), asList("aa", "ab")).pipeline().execute()); + db.pipeline() + .createFrom(collection.whereIn(FieldPath.documentId(), asList("aa", "ab"))) + .execute()); assertEquals(asList(docA, docB), pipelineSnapshotToValues(docs)); } @@ -472,6 +509,7 @@ public void testQueriesCanUseNotInFilters() { "a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", docH, "i", docI, "j", docJ); CollectionReference collection = testCollectionWithDocs(allDocs); + FirebaseFirestore db = collection.firestore; // Search for zips not matching 98101, 98103, or [98101, 98102]. Map> expectedDocsMap = new LinkedHashMap<>(allDocs); @@ -483,9 +521,9 @@ public void testQueriesCanUseNotInFilters() { PipelineSnapshot snapshot = waitFor( - collection - .whereNotIn("zip", asList(98101L, 98103L, asList(98101L, 98102L))) - .pipeline() + db.pipeline() + .createFrom( + collection.whereNotIn("zip", asList(98101L, 98103L, asList(98101L, 98102L)))) .execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); @@ -495,11 +533,15 @@ public void testQueriesCanUseNotInFilters() { expectedDocsMap.remove("i"); expectedDocsMap.remove("j"); snapshot = - waitFor(collection.whereNotIn("zip", asList(map("code", 500L))).pipeline().execute()); + waitFor( + db.pipeline() + .createFrom(collection.whereNotIn("zip", asList(map("code", 500L)))) + .execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); // With Null. - snapshot = waitFor(collection.whereNotIn("zip", nullList()).pipeline().execute()); + snapshot = + waitFor(db.pipeline().createFrom(collection.whereNotIn("zip", nullList())).execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With NaN. @@ -507,7 +549,9 @@ public void testQueriesCanUseNotInFilters() { expectedDocsMap.remove("a"); expectedDocsMap.remove("i"); expectedDocsMap.remove("j"); - snapshot = waitFor(collection.whereNotIn("zip", asList(Double.NaN)).pipeline().execute()); + snapshot = + waitFor( + db.pipeline().createFrom(collection.whereNotIn("zip", asList(Double.NaN))).execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); // With NaN and a number. @@ -517,7 +561,10 @@ public void testQueriesCanUseNotInFilters() { expectedDocsMap.remove("i"); expectedDocsMap.remove("j"); snapshot = - waitFor(collection.whereNotIn("zip", asList(Float.NaN, 98101L)).pipeline().execute()); + waitFor( + db.pipeline() + .createFrom(collection.whereNotIn("zip", asList(Float.NaN, 98101L))) + .execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); } @@ -534,9 +581,12 @@ public void testQueriesCanUseNotInFiltersWithDocIds() { "ba", docC, "bb", docD); CollectionReference collection = testCollectionWithDocs(testDocs); + FirebaseFirestore db = collection.firestore; PipelineSnapshot docs = waitFor( - collection.whereNotIn(FieldPath.documentId(), asList("aa", "ab")).pipeline().execute()); + db.pipeline() + .createFrom(collection.whereNotIn(FieldPath.documentId(), asList("aa", "ab"))) + .execute()); assertEquals(asList(docC, docD), pipelineSnapshotToValues(docs)); } @@ -557,39 +607,55 @@ public void testQueriesCanUseArrayContainsAnyFilters() { map( "a", docA, "b", docB, "c", docC, "d", docD, "e", docE, "f", docF, "g", docG, "h", docH, "i", docI)); + FirebaseFirestore db = collection.firestore; // Search for "array" to contain [42, 43]. PipelineSnapshot snapshot = - waitFor(collection.whereArrayContainsAny("array", asList(42L, 43L)).pipeline().execute()); + waitFor( + db.pipeline() + .createFrom(collection.whereArrayContainsAny("array", asList(42L, 43L))) + .execute()); assertEquals(asList(docA, docB, docD, docE), pipelineSnapshotToValues(snapshot)); // With objects. snapshot = waitFor( - collection.whereArrayContainsAny("array", asList(map("a", 42L))).pipeline().execute()); + db.pipeline() + .createFrom(collection.whereArrayContainsAny("array", asList(map("a", 42L)))) + .execute()); assertEquals(asList(docF), pipelineSnapshotToValues(snapshot)); // With null. - snapshot = waitFor(collection.whereArrayContainsAny("array", nullList()).pipeline().execute()); + snapshot = + waitFor( + db.pipeline() + .createFrom(collection.whereArrayContainsAny("array", nullList())) + .execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With null and a value. List inputList = nullList(); inputList.add(43L); - snapshot = waitFor(collection.whereArrayContainsAny("array", inputList).pipeline().execute()); + snapshot = + waitFor( + db.pipeline() + .createFrom(collection.whereArrayContainsAny("array", inputList)) + .execute()); assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); // With NaN. snapshot = - waitFor(collection.whereArrayContainsAny("array", asList(Double.NaN)).pipeline().execute()); + waitFor( + db.pipeline() + .createFrom(collection.whereArrayContainsAny("array", asList(Double.NaN))) + .execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With NaN and a value. snapshot = waitFor( - collection - .whereArrayContainsAny("array", asList(Double.NaN, 43L)) - .pipeline() + db.pipeline() + .createFrom(collection.whereArrayContainsAny("array", asList(Double.NaN, 43L))) .execute()); assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); } @@ -621,7 +687,8 @@ public void testCollectionGroupQueries() { } waitFor(batch.commit()); - PipelineSnapshot snapshot = waitFor(db.collectionGroup(collectionGroup).pipeline().execute()); + PipelineSnapshot snapshot = + waitFor(db.pipeline().createFrom(db.collectionGroup(collectionGroup)).execute()); assertEquals( asList("cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5"), pipelineSnapshotToIds(snapshot)); @@ -652,21 +719,23 @@ public void testCollectionGroupQueriesWithStartAtEndAtWithArbitraryDocumentIds() PipelineSnapshot snapshot = waitFor( - db.collectionGroup(collectionGroup) - .orderBy(FieldPath.documentId()) - .startAt("a/b") - .endAt("a/b0") - .pipeline() + db.pipeline() + .createFrom( + db.collectionGroup(collectionGroup) + .orderBy(FieldPath.documentId()) + .startAt("a/b") + .endAt("a/b0")) .execute()); assertEquals(asList("cg-doc2", "cg-doc3", "cg-doc4"), pipelineSnapshotToIds(snapshot)); snapshot = waitFor( - db.collectionGroup(collectionGroup) - .orderBy(FieldPath.documentId()) - .startAfter("a/b") - .endBefore("a/b/" + collectionGroup + "/cg-doc3") - .pipeline() + db.pipeline() + .createFrom( + db.collectionGroup(collectionGroup) + .orderBy(FieldPath.documentId()) + .startAfter("a/b") + .endBefore("a/b/" + collectionGroup + "/cg-doc3")) .execute()); assertEquals(asList("cg-doc2"), pipelineSnapshotToIds(snapshot)); } @@ -696,19 +765,22 @@ public void testCollectionGroupQueriesWithWhereFiltersOnArbitraryDocumentIds() { PipelineSnapshot snapshot = waitFor( - db.collectionGroup(collectionGroup) - .whereGreaterThanOrEqualTo(FieldPath.documentId(), "a/b") - .whereLessThanOrEqualTo(FieldPath.documentId(), "a/b0") - .pipeline() + db.pipeline() + .createFrom( + db.collectionGroup(collectionGroup) + .whereGreaterThanOrEqualTo(FieldPath.documentId(), "a/b") + .whereLessThanOrEqualTo(FieldPath.documentId(), "a/b0")) .execute()); assertEquals(asList("cg-doc2", "cg-doc3", "cg-doc4"), pipelineSnapshotToIds(snapshot)); snapshot = waitFor( - db.collectionGroup(collectionGroup) - .whereGreaterThan(FieldPath.documentId(), "a/b") - .whereLessThan(FieldPath.documentId(), "a/b/" + collectionGroup + "/cg-doc3") - .pipeline() + db.pipeline() + .createFrom( + db.collectionGroup(collectionGroup) + .whereGreaterThan(FieldPath.documentId(), "a/b") + .whereLessThan( + FieldPath.documentId(), "a/b/" + collectionGroup + "/cg-doc3")) .execute()); assertEquals(asList("cg-doc2"), pipelineSnapshotToIds(snapshot)); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java index 902d515d86f..d9cdff77bfc 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java @@ -17,6 +17,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; +import com.google.firebase.firestore.pipeline.AggregateExpr; +import com.google.firebase.firestore.pipeline.AggregateWithAlias; +import com.google.firebase.firestore.pipeline.Field; import java.util.Objects; /** Represents an aggregation that can be performed by Firestore. */ @@ -61,6 +64,9 @@ public String getOperator() { return operator; } + @NonNull + abstract AggregateWithAlias toPipeline(); + /** * Returns true if the given object is equal to this object. Two `AggregateField` objects are * considered equal if they have the same operator and operate on the same field. @@ -195,6 +201,12 @@ public static class CountAggregateField extends AggregateField { private CountAggregateField() { super(null, "count"); } + + @NonNull + @Override + AggregateWithAlias toPipeline() { + return AggregateExpr.countAll().alias(getAlias()); + } } /** Represents a "sum" aggregation that can be performed by Firestore. */ @@ -202,6 +214,12 @@ public static class SumAggregateField extends AggregateField { private SumAggregateField(@NonNull FieldPath fieldPath) { super(fieldPath, "sum"); } + + @NonNull + @Override + AggregateWithAlias toPipeline() { + return Field.of(getFieldPath()).sum().alias(getAlias()); + } } /** Represents an "average" aggregation that can be performed by Firestore. */ @@ -209,5 +227,11 @@ public static class AverageAggregateField extends AggregateField { private AverageAggregateField(@NonNull FieldPath fieldPath) { super(fieldPath, "average"); } + + @NonNull + @Override + AggregateWithAlias toPipeline() { + return Field.of(getFieldPath()).avg().alias(getAlias()); + } } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java index c8b9cfaa90a..d0a358e2233 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/CollectionReference.java @@ -21,7 +21,6 @@ import com.google.android.gms.tasks.Task; import com.google.firebase.firestore.model.DocumentKey; import com.google.firebase.firestore.model.ResourcePath; -import com.google.firebase.firestore.pipeline.CollectionSource; import com.google.firebase.firestore.util.Executors; import com.google.firebase.firestore.util.Util; @@ -128,10 +127,4 @@ public Task add(@NonNull Object data) { return ref; }); } - - @NonNull - @Override - public Pipeline pipeline() { - return new Pipeline(firestore, firestore.getUserDataReader(), new CollectionSource(getPath())); - } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 8f3ca218061..3c4932168ce 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -165,10 +165,10 @@ internal constructor( fun union(other: Pipeline): Pipeline = append(UnionStage(other)) - fun unnest(field: String, alias: String): Pipeline = unnest(Field.of(field).`as`(alias)) + fun unnest(field: String, alias: String): Pipeline = unnest(Field.of(field).alias(alias)) fun unnest(field: String, alias: String, options: UnnestOptions): Pipeline = - unnest(Field.of(field).`as`(alias), options) + unnest(Field.of(field).alias(alias), options) fun unnest(selectable: Selectable): Pipeline = append(UnnestStage(selectable)) @@ -206,11 +206,23 @@ internal constructor( } class PipelineSource internal constructor(private val firestore: FirebaseFirestore) { - fun collection(path: String): Pipeline { - // Validate path by converting to CollectionReference - return collection(firestore.collection(path)) + fun createFrom(query: Query): Pipeline { + if (query.firestore.databaseId != firestore.databaseId) { + throw IllegalArgumentException("Provided query is from a different Firestore instance.") + } + return query.query.toPipeline(firestore, firestore.userDataReader) } + fun createFrom(query: AggregateQuery): Pipeline = + createFrom(query.query) + .aggregate( + *query.aggregateFields.map(AggregateField::toPipeline).toTypedArray() + ) + + fun collection(path: String): Pipeline = + // Validate path by converting to CollectionReference + collection(firestore.collection(path)) + fun collection(ref: CollectionReference): Pipeline { if (ref.firestore.databaseId != firestore.databaseId) { throw IllegalArgumentException( @@ -230,10 +242,9 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto fun database(): Pipeline = Pipeline(firestore, firestore.userDataReader, DatabaseSource()) - fun documents(vararg documents: String): Pipeline { + fun documents(vararg documents: String): Pipeline = // Validate document path by converting to DocumentReference - return documents(*documents.map(firestore::document).toTypedArray()) - } + documents(*documents.map(firestore::document).toTypedArray()) fun documents(vararg documents: DocumentReference): Pipeline { val databaseId = firestore.databaseId 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 12ff36bf960..d5fb8a4399b 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 @@ -1241,11 +1241,6 @@ public AggregateQuery aggregate( return new AggregateQuery(this, fields); } - @NonNull - public Pipeline pipeline() { - return query.toPipeline(firestore, firestore.getUserDataReader()); - } - @Override public boolean equals(Object o) { if (this == o) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt index c363c28be3e..308b6fb70f0 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt @@ -52,7 +52,7 @@ private constructor(private val name: String, private val params: Array of(value) is Value -> of(value) is Map<*, *> -> - MapOfExpr( - value.entries.associate { - val key = it.key - if (key is String) key to toExpr(it.value) - else throw IllegalArgumentException("Maps with non-string keys are not supported") - } + Function.map( + value + .flatMap { + val key = it.key + if (key is String) listOf(of(key), toExpr(it.value)) + else throw IllegalArgumentException("Maps with non-string keys are not supported") + } + .toTypedArray() ) is List<*> -> ListOfExprs(value.map(toExpr).toTypedArray()) else -> null @@ -116,7 +118,7 @@ abstract class Expr internal constructor() { * expression and associates it with the provided alias. * ``` */ - open fun `as`(alias: String) = ExprWithAlias(alias, this) + open fun alias(alias: String) = ExprWithAlias(alias, this) /** * Creates an expression that this expression to another expression. @@ -234,6 +236,13 @@ abstract class Expr internal constructor() { fun mapGet(key: String) = Function.mapGet(this, key) + fun mapMerge(secondMap: Expr, vararg otherMaps: Expr) = + Function.mapMerge(this, secondMap, *otherMaps) + + fun mapRemove(key: Expr) = Function.mapRemove(this, key) + + fun mapRemove(key: String) = Function.mapRemove(this, key) + fun cosineDistance(vector: Expr) = Function.cosineDistance(this, vector) fun cosineDistance(vector: DoubleArray) = Function.cosineDistance(this, vector) @@ -378,16 +387,6 @@ class Field internal constructor(private val fieldPath: ModelFieldPath) : Select Value.newBuilder().setFieldReferenceValue(fieldPath.canonicalString()).build() } -internal class MapOfExpr(private val expressions: Map) : Expr() { - override fun toProto(userDataReader: UserDataReader): Value { - val builder = MapValue.newBuilder() - for ((key, value) in expressions) { - builder.putFields(key, value.toProto(userDataReader)) - } - return Value.newBuilder().setMapValue(builder).build() - } -} - internal class ListOfExprs(private val expressions: Array) : Expr() { override fun toProto(userDataReader: UserDataReader): Value = encodeValue(expressions.map { it.toProto(userDataReader) }) @@ -704,6 +703,12 @@ protected constructor(private val name: String, private val params: Array) = Function("map", elements) + + @JvmStatic + fun map(elements: Map) = + map(elements.flatMap { listOf(of(it.key), toExprOrConstant(it.value)) }.toTypedArray()) + @JvmStatic fun mapGet(map: Expr, key: Expr) = Function("map_get", map, key) @JvmStatic fun mapGet(map: Expr, key: String) = Function("map_get", map, key) @@ -712,6 +717,22 @@ protected constructor(private val name: String, private val params: Array) : fun countIf(): AggregateExpr = AggregateExpr.countIf(this) - fun ifThen(then: Expr) = ifThen(this, then) - - fun ifThen(then: Any) = ifThen(this, then) - - fun ifThenElse(then: Expr, `else`: Expr) = ifThenElse(this, then, `else`) + fun cond(then: Expr, otherwise: Expr) = cond(this, then, otherwise) - fun ifThenElse(then: Any, `else`: Any) = ifThenElse(this, then, `else`) + fun cond(then: Any, otherwise: Any) = cond(this, then, otherwise) } class Ordering private constructor(val expr: Expr, private val dir: Direction) { From 5e1d84e4964f466a35bb2b9728e5679438814f33 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 8 Apr 2025 15:07:13 -0400 Subject: [PATCH 34/77] Fixups --- .../testutil/IntegrationTestUtil.java | 3 +- .../firebase/firestore/FirebaseFirestore.java | 5 + .../com/google/firebase/firestore/Pipeline.kt | 195 +++++++++++--- .../firebase/firestore/pipeline/options.kt | 25 +- .../firebase/firestore/pipeline/stage.kt | 252 ++++++++++++------ .../firebase/firestore/remote/Datastore.java | 21 +- 6 files changed, 353 insertions(+), 148 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java index 5a8a9ceb67c..e94fb3baf35 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java @@ -568,7 +568,8 @@ public static void checkOnlineAndOfflineResultsMatch(Query query, String... expe */ public static void checkQueryAndPipelineResultsMatch(Query query, String... expectedDocs) { QuerySnapshot docsFromQuery = waitFor(query.get(Source.SERVER)); - PipelineSnapshot docsFromPipeline = waitFor(query.pipeline().execute()); + PipelineSnapshot docsFromPipeline = + waitFor(query.getFirestore().pipeline().createFrom(query).execute()); assertEquals(querySnapshotToIds(docsFromQuery), pipelineSnapshotToIds(docsFromPipeline)); List expected = asList(expectedDocs); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java index a2797e72399..fa0ccf7f90f 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/FirebaseFirestore.java @@ -884,6 +884,11 @@ static void setClientLanguage(@NonNull String languageToken) { FirestoreChannel.setClientLanguage(languageToken); } + /** + * Build a new Pipeline + * + * @return {@code PipelineSource} for this Firestore instance. + */ @NonNull public PipelineSource pipeline() { clientProvider.ensureConfigured(); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 3c4932168ce..25496f498a9 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -18,8 +18,8 @@ import com.google.android.gms.tasks.Task import com.google.android.gms.tasks.TaskCompletionSource import com.google.common.collect.FluentIterable import com.google.common.collect.ImmutableList +import com.google.firebase.Timestamp import com.google.firebase.firestore.model.DocumentKey -import com.google.firebase.firestore.model.SnapshotVersion import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.pipeline.AddFieldsStage import com.google.firebase.firestore.pipeline.AggregateStage @@ -32,7 +32,6 @@ import com.google.firebase.firestore.pipeline.DistinctStage import com.google.firebase.firestore.pipeline.DocumentsSource import com.google.firebase.firestore.pipeline.Expr import com.google.firebase.firestore.pipeline.Field -import com.google.firebase.firestore.pipeline.FindNearestOptions import com.google.firebase.firestore.pipeline.FindNearestStage import com.google.firebase.firestore.pipeline.GenericArg import com.google.firebase.firestore.pipeline.GenericStage @@ -47,7 +46,6 @@ import com.google.firebase.firestore.pipeline.Selectable import com.google.firebase.firestore.pipeline.SortStage import com.google.firebase.firestore.pipeline.Stage import com.google.firebase.firestore.pipeline.UnionStage -import com.google.firebase.firestore.pipeline.UnnestOptions import com.google.firebase.firestore.pipeline.UnnestStage import com.google.firebase.firestore.pipeline.WhereStage import com.google.firebase.firestore.util.Preconditions @@ -59,15 +57,15 @@ class Pipeline internal constructor( internal val firestore: FirebaseFirestore, internal val userDataReader: UserDataReader, - private val stages: FluentIterable + private val stages: FluentIterable> ) { internal constructor( firestore: FirebaseFirestore, userDataReader: UserDataReader, - stage: Stage + stage: Stage<*> ) : this(firestore, userDataReader, FluentIterable.of(stage)) - private fun append(stage: Stage): Pipeline { + private fun append(stage: Stage<*>): Pipeline { return Pipeline(firestore, userDataReader, stages.append(stage)) } @@ -144,15 +142,28 @@ internal constructor( fun findNearest( property: Expr, vector: DoubleArray, - distanceMeasure: FindNearestStage.DistanceMeasure - ) = append(FindNearestStage(property, vector, distanceMeasure, FindNearestOptions.DEFAULT)) + distanceMeasure: FindNearestStage.DistanceMeasure, + ) = append(FindNearestStage.of(property, vector, distanceMeasure)) fun findNearest( - property: Expr, + propertyField: String, vector: DoubleArray, distanceMeasure: FindNearestStage.DistanceMeasure, - options: FindNearestOptions - ) = append(FindNearestStage(property, vector, distanceMeasure, options)) + ) = append(FindNearestStage.of(propertyField, vector, distanceMeasure)) + + fun findNearest( + property: Expr, + vector: Expr, + distanceMeasure: FindNearestStage.DistanceMeasure, + ) = append(FindNearestStage.of(property, vector, distanceMeasure)) + + fun findNearest( + propertyField: String, + vector: Expr, + distanceMeasure: FindNearestStage.DistanceMeasure, + ) = append(FindNearestStage.of(propertyField, vector, distanceMeasure)) + + fun findNearest(stage: FindNearestStage) = append(stage) fun replace(field: String): Pipeline = replace(Field.of(field)) @@ -165,34 +176,36 @@ internal constructor( fun union(other: Pipeline): Pipeline = append(UnionStage(other)) - fun unnest(field: String, alias: String): Pipeline = unnest(Field.of(field).alias(alias)) - - fun unnest(field: String, alias: String, options: UnnestOptions): Pipeline = - unnest(Field.of(field).alias(alias), options) + fun unnest(field: String, alias: String): Pipeline = unnest(UnnestStage.withField(field, alias)) fun unnest(selectable: Selectable): Pipeline = append(UnnestStage(selectable)) - fun unnest(selectable: Selectable, options: UnnestOptions): Pipeline = - append(UnnestStage(selectable)) + fun unnest(stage: UnnestStage): Pipeline = append(stage) private inner class ObserverSnapshotTask : PipelineResultObserver { private val userDataWriter = UserDataWriter(firestore, DocumentSnapshot.ServerTimestampBehavior.DEFAULT) private val taskCompletionSource = TaskCompletionSource() private val results: ImmutableList.Builder = ImmutableList.builder() - override fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) { + override fun onDocument( + key: DocumentKey?, + data: Map, + createTime: Timestamp?, + updateTime: Timestamp? + ) { results.add( PipelineResult( firestore, userDataWriter, if (key == null) null else DocumentReference(key, firestore), data, - version + createTime, + updateTime ) ) } - override fun onComplete(executionTime: SnapshotVersion) { + override fun onComplete(executionTime: Timestamp) { taskCompletionSource.setResult(PipelineSnapshot(executionTime, results.build())) } @@ -205,7 +218,17 @@ internal constructor( } } +/** Start of a Firestore Pipeline */ class PipelineSource internal constructor(private val firestore: FirebaseFirestore) { + + /** + * Convert the given Query into an equivalent Pipeline. + * + * @param query A Query to be converted into a Pipeline. + * @return Pipeline that is equivalent to [query] + * @throws [IllegalArgumentException] Thrown if the [query] provided targets a different project + * or database than the pipeline. + */ fun createFrom(query: Query): Pipeline { if (query.firestore.databaseId != firestore.databaseId) { throw IllegalArgumentException("Provided query is from a different Firestore instance.") @@ -213,16 +236,40 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto return query.query.toPipeline(firestore, firestore.userDataReader) } - fun createFrom(query: AggregateQuery): Pipeline = - createFrom(query.query) + /** + * Convert the given Aggregate Query into an equivalent Pipeline. + * + * @param aggregateQuery An Aggregate Query to be converted into a Pipeline. + * @return Pipeline that is equivalent to [aggregateQuery] + * @throws [IllegalArgumentException] Thrown if the [aggregateQuery] provided targets a different + * project or database than the pipeline. + */ + fun createFrom(aggregateQuery: AggregateQuery): Pipeline = + createFrom(aggregateQuery.query) .aggregate( - *query.aggregateFields.map(AggregateField::toPipeline).toTypedArray() + *aggregateQuery.aggregateFields + .map(AggregateField::toPipeline) + .toTypedArray() ) + /** + * Set the pipeline's source to the collection specified by the given path. + * + * @param path A path to a collection that will be the source of this pipeline. + * @return Pipeline with documents from target collection. + */ fun collection(path: String): Pipeline = // Validate path by converting to CollectionReference collection(firestore.collection(path)) + /** + * Set the pipeline's source to the collection specified by the given CollectionReference. + * + * @param ref A CollectionReference for a collection that will be the source of this pipeline. + * @return Pipeline with documents from target collection. + * @throws [IllegalArgumentException] Thrown if the [ref] provided targets a different project or + * database than the pipeline. + */ fun collection(ref: CollectionReference): Pipeline { if (ref.firestore.databaseId != firestore.databaseId) { throw IllegalArgumentException( @@ -232,6 +279,11 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto return Pipeline(firestore, firestore.userDataReader, CollectionSource(ref.path)) } + /** + * Set the pipeline's source to the collection group with the given id. + * + * @param collectionid The id of a collection group that will be the source of this pipeline. + */ fun collectionGroup(collectionId: String): Pipeline { Preconditions.checkNotNull(collectionId, "Provided collection ID must not be null.") require(!collectionId.contains("/")) { @@ -240,12 +292,33 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto return Pipeline(firestore, firestore.userDataReader, CollectionGroupSource(collectionId)) } + /** + * Set the pipeline's source to be all documents in this database. + * + * @return Pipeline with all documents in this database. + */ fun database(): Pipeline = Pipeline(firestore, firestore.userDataReader, DatabaseSource()) + /** + * Set the pipeline's source to the documents specified by the given paths. + * + * @param documents Paths specifying the individual documents that will be the source of this + * pipeline. + * @return Pipeline with [documents]. + */ fun documents(vararg documents: String): Pipeline = // Validate document path by converting to DocumentReference documents(*documents.map(firestore::document).toTypedArray()) + /** + * Set the pipeline's source to the documents specified by the given DocumentReferences. + * + * @param documents DocumentReferences specifying the individual documents that will be the source + * of this pipeline. + * @return Pipeline with [documents]. + * @throws [IllegalArgumentException] Thrown if the [documents] provided targets a different + * project or database than the pipeline. + */ fun documents(vararg documents: DocumentReference): Pipeline { val databaseId = firestore.databaseId for (document in documents) { @@ -263,11 +336,18 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto } } +/** + */ class PipelineSnapshot -internal constructor( - private val executionTime: SnapshotVersion, - val results: List -) : Iterable { +internal constructor(executionTime: Timestamp, results: List) : + Iterable { + + /** The time at which the pipeline producing this result is executed. */ + val executionTime: Timestamp = executionTime + + /** List of all the results */ + val results: List = results + override fun iterator() = results.iterator() } @@ -275,17 +355,51 @@ class PipelineResult internal constructor( private val firestore: FirebaseFirestore, private val userDataWriter: UserDataWriter, - val ref: DocumentReference?, + ref: DocumentReference?, private val fields: Map, - private val version: SnapshotVersion, + createTime: Timestamp?, + updateTime: Timestamp?, ) { + /** The time the document was created. Null if this result is not a document. */ + val createTime: Timestamp? = createTime + + /** + * The time the document was last updated (at the time the snapshot was generated). Null if this + * result is not a document. + */ + val updateTime: Timestamp? = updateTime + + /** + * The reference to the document, if the query returns the `__name__` field for a document. The + * name field will be returned by default if querying a document. + * + * The `__name__` field will not be returned if the query projects away this field. For example: + * ``` + * // this query does not select the `__name__` field as part of the select stage, + * // so the __name__ field will not be in the output docs from this stage + * db.pipeline().collection("books").select("title", "desc") + * ``` + * + * The `__name__` field will not be returned from queries with aggregate or distinct stages. + * + * @return [DocumentReference] Reference to the document, if applicable. + */ + val ref: DocumentReference? = ref + /** * Returns the ID of the document represented by this result. Returns null if this result is not * corresponding to a Firestore document. + * + * @return ID of document, if applicable. */ fun getId(): String? = ref?.id + /** + * Retrieves all fields in the result as an object map. + * + * @return Map of field names to objects. + */ fun getData(): Map = userDataWriter.convertObject(fields) private fun extractNestedValue(fieldPath: FieldPath): Value? { @@ -307,15 +421,32 @@ internal constructor( return value } + /** + * Retrieves the field specified by [field]. + * + * @param field The field path (e.g. "foo" or "foo.bar") to a specific field. + * @return The data at the specified field location or null if no such field exists. + */ fun get(field: String): Any? = get(FieldPath.fromDotSeparatedPath(field)) + /** + * Retrieves the field specified by [fieldPath]. + * + * @param fieldPath The field path to a specific field. + * @return The data at the specified field location or null if no such field exists. + */ fun get(fieldPath: FieldPath): Any? = userDataWriter.convertValue(extractNestedValue(fieldPath)) - override fun toString() = "PipelineResult{ref=$ref, version=$version}, data=${getData()}" + override fun toString() = "PipelineResult{ref=$ref, updateTime=$updateTime}, data=${getData()}" } internal interface PipelineResultObserver { - fun onDocument(key: DocumentKey?, data: Map, version: SnapshotVersion) - fun onComplete(executionTime: SnapshotVersion) + fun onDocument( + key: DocumentKey?, + data: Map, + createTime: Timestamp?, + updateTime: Timestamp? + ) + fun onComplete(executionTime: Timestamp) fun onError(exception: FirebaseFirestoreException) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt index 5695a9dff91..af3853f2f4a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt @@ -15,7 +15,6 @@ package com.google.firebase.firestore.pipeline import com.google.common.collect.ImmutableMap -import com.google.firebase.firestore.model.Values import com.google.firestore.v1.ArrayValue import com.google.firestore.v1.MapValue import com.google.firestore.v1.Value @@ -46,7 +45,11 @@ internal constructor(private val options: ImmutableMap) { return with(key, value.toValue()) } - internal fun forEach(f: (String, Value) -> Unit) = options.forEach(f) + internal fun forEach(f: (String, Value) -> Unit) { + for (entry in options.entries) { + f(entry.key, entry.value) + } + } private fun toValue(): Value { val mapValue = MapValue.newBuilder().putAllFields(options).build() @@ -61,21 +64,3 @@ internal constructor(private val options: ImmutableMap) { } } } - -abstract class AbstractOptions> -internal constructor(internal val options: InternalOptions) { - - internal abstract fun self(options: InternalOptions): T - - protected fun with(key: String, value: Value): T = self(options.with(key, value)) - - fun with(key: String, value: String): T = with(key, Values.encodeValue(value)) - - fun with(key: String, value: Boolean): T = with(key, Values.encodeValue(value)) - - fun with(key: String, value: Long): T = with(key, Values.encodeValue(value)) - - fun with(key: String, value: Double): T = with(key, Values.encodeValue(value)) - - fun with(key: String, value: Field): T = with(key, value.toProto()) -} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index f72ede652ad..bcae5dd66e5 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -15,16 +15,15 @@ package com.google.firebase.firestore.pipeline import com.google.firebase.firestore.UserDataReader +import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.Values.encodeValue -import com.google.firebase.firestore.model.Values.encodeVectorValue import com.google.firebase.firestore.pipeline.Field.Companion.of +import com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value -abstract class Stage -private constructor(protected val name: String, private val options: InternalOptions) { - internal constructor(name: String) : this(name, InternalOptions.EMPTY) - internal constructor(name: String, options: AbstractOptions<*>) : this(name, options.options) +abstract class Stage> +internal constructor(protected val name: String, internal val options: InternalOptions) { internal fun toProtoStage(userDataReader: UserDataReader): Pipeline.Stage { val builder = Pipeline.Stage.newBuilder() builder.setName(name) @@ -33,27 +32,37 @@ private constructor(protected val name: String, private val options: InternalOpt return builder.build() } internal abstract fun args(userDataReader: UserDataReader): Sequence + + internal abstract fun self(options: InternalOptions): T + + protected fun with(key: String, value: Value): T = self(options.with(key, value)) + + fun with(key: String, value: String): T = with(key, Values.encodeValue(value)) + + fun with(key: String, value: Boolean): T = with(key, Values.encodeValue(value)) + + fun with(key: String, value: Long): T = with(key, Values.encodeValue(value)) + + fun with(key: String, value: Double): T = with(key, Values.encodeValue(value)) + + fun with(key: String, value: Field): T = with(key, value.toProto()) } class GenericStage -private constructor( +internal constructor( name: String, private val arguments: List, - private val options: GenericOptions -) : Stage(name, options) { - internal constructor( - name: String, - arguments: List - ) : this(name, arguments, GenericOptions.DEFAULT) + options: InternalOptions = InternalOptions.EMPTY +) : Stage(name, options) { companion object { - @JvmStatic fun of(name: String) = GenericStage(name, emptyList()) + @JvmStatic fun of(name: String) = GenericStage(name, emptyList(), InternalOptions.EMPTY) } + override fun self(options: InternalOptions) = GenericStage(name, arguments, options) + fun withArguments(vararg arguments: Any): GenericStage = GenericStage(name, arguments.map(GenericArg::from), options) - fun withOptions(options: GenericOptions): GenericStage = GenericStage(name, arguments, options) - override fun args(userDataReader: UserDataReader): Sequence = arguments.asSequence().map { it.toProto(userDataReader) } } @@ -95,39 +104,52 @@ internal sealed class GenericArg { } } -class GenericOptions private constructor(options: InternalOptions) : - AbstractOptions(options) { - companion object { - @JvmField val DEFAULT = GenericOptions(InternalOptions.EMPTY) - } - override fun self(options: InternalOptions) = GenericOptions(options) -} - -internal class DatabaseSource : Stage("database") { +internal class DatabaseSource +@JvmOverloads +internal constructor(options: InternalOptions = InternalOptions.EMPTY) : + Stage("database", options) { + override fun self(options: InternalOptions) = DatabaseSource(options) override fun args(userDataReader: UserDataReader): Sequence = emptySequence() } -internal class CollectionSource internal constructor(path: String) : Stage("collection") { - private val path: String = if (path.startsWith("/")) path else "/" + path +internal class CollectionSource +@JvmOverloads +internal constructor(val path: String, options: InternalOptions = InternalOptions.EMPTY) : + Stage("collection", options) { + override fun self(options: InternalOptions): CollectionSource = CollectionSource(path, options) override fun args(userDataReader: UserDataReader): Sequence = - sequenceOf(Value.newBuilder().setReferenceValue(path).build()) + sequenceOf( + Value.newBuilder().setReferenceValue(if (path.startsWith("/")) path else "/" + path).build() + ) } -internal class CollectionGroupSource internal constructor(val collectionId: String) : - Stage("collection_group") { +internal class CollectionGroupSource +@JvmOverloads +internal constructor(val collectionId: String, options: InternalOptions = InternalOptions.EMPTY) : + Stage("collection_group", options) { + override fun self(options: InternalOptions) = CollectionGroupSource(collectionId, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setReferenceValue("").build(), encodeValue(collectionId)) } -internal class DocumentsSource internal constructor(private val documents: Array) : - Stage("documents") { +internal class DocumentsSource +@JvmOverloads +internal constructor( + private val documents: Array, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("documents", options) { internal constructor(document: String) : this(arrayOf(document)) + override fun self(options: InternalOptions) = DocumentsSource(documents, options) override fun args(userDataReader: UserDataReader): Sequence = documents.asSequence().map { if (it.startsWith("/")) it else "/" + it }.map(::encodeValue) } -internal class AddFieldsStage internal constructor(private val fields: Array) : - Stage("add_fields") { +internal class AddFieldsStage +internal constructor( + private val fields: Array, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("add_fields", options) { + override fun self(options: InternalOptions) = AddFieldsStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) } @@ -135,8 +157,9 @@ internal class AddFieldsStage internal constructor(private val fields: Array, - private val groups: Map -) : Stage("aggregate") { + private val groups: Map, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("aggregate", options) { private constructor(accumulators: Map) : this(accumulators, emptyMap()) companion object { @JvmStatic @@ -150,6 +173,8 @@ internal constructor( } } + override fun self(options: InternalOptions) = AggregateStage(accumulators, groups, options) + fun withGroups(vararg groups: Selectable) = AggregateStage(accumulators, groups.associateBy(Selectable::getAlias)) @@ -169,8 +194,12 @@ internal constructor( ) } -internal class WhereStage internal constructor(private val condition: BooleanExpr) : - Stage("where") { +internal class WhereStage +internal constructor( + private val condition: BooleanExpr, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("where", options) { + override fun self(options: InternalOptions) = WhereStage(condition, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(condition.toProto(userDataReader)) } @@ -178,77 +207,122 @@ internal class WhereStage internal constructor(private val condition: BooleanExp class FindNearestStage internal constructor( private val property: Expr, - private val vector: DoubleArray, + private val vector: Expr, private val distanceMeasure: DistanceMeasure, - options: FindNearestOptions -) : Stage("find_nearest", options) { + options: InternalOptions = InternalOptions.EMPTY +) : Stage("find_nearest", options) { + + companion object { + @JvmStatic + fun of(property: Expr, vector: Expr, distanceMeasure: DistanceMeasure) = + FindNearestStage(property, vector, distanceMeasure) + + @JvmStatic + fun of(property: Expr, vector: DoubleArray, distanceMeasure: DistanceMeasure) = + FindNearestStage(property, Constant.vector(vector), distanceMeasure) + + @JvmStatic + fun of(fieldName: String, vector: Expr, distanceMeasure: DistanceMeasure) = + FindNearestStage(Constant.of(fieldName), vector, distanceMeasure) + + @JvmStatic + fun of(fieldName: String, vector: DoubleArray, distanceMeasure: DistanceMeasure) = + FindNearestStage(Constant.of(fieldName), Constant.vector(vector), distanceMeasure) + } class DistanceMeasure private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) + companion object { - val EUCLIDEAN = DistanceMeasure("euclidean") - val COSINE = DistanceMeasure("cosine") - val DOT_PRODUCT = DistanceMeasure("dot_product") - } - } + @JvmField val EUCLIDEAN = DistanceMeasure("euclidean") - override fun args(userDataReader: UserDataReader): Sequence = - sequenceOf(property.toProto(userDataReader), encodeVectorValue(vector), distanceMeasure.proto) -} + @JvmField val COSINE = DistanceMeasure("cosine") -class FindNearestOptions private constructor(options: InternalOptions) : - AbstractOptions(options) { - companion object { - @JvmField val DEFAULT = FindNearestOptions(InternalOptions.EMPTY) + @JvmField val DOT_PRODUCT = DistanceMeasure("dot_product") + } } - override fun self(options: InternalOptions): FindNearestOptions = FindNearestOptions(options) + override fun self(options: InternalOptions) = + FindNearestStage(property, vector, distanceMeasure, options) - fun withLimit(limit: Long): FindNearestOptions = with("limit", limit) + override fun args(userDataReader: UserDataReader): Sequence = + sequenceOf( + property.toProto(userDataReader), + vector.toProto(userDataReader), + distanceMeasure.proto + ) + + fun withLimit(limit: Long): FindNearestStage = with("limit", limit) - fun withDistanceField(distanceField: Field): FindNearestOptions = + fun withDistanceField(distanceField: Field): FindNearestStage = with("distance_field", distanceField) - fun withDistanceField(distanceField: String): FindNearestOptions = + fun withDistanceField(distanceField: String): FindNearestStage = withDistanceField(of(distanceField)) } -internal class LimitStage internal constructor(private val limit: Int) : Stage("limit") { +internal class LimitStage +internal constructor(private val limit: Int, options: InternalOptions = InternalOptions.EMPTY) : + Stage("limit", options) { + override fun self(options: InternalOptions) = LimitStage(limit, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(limit)) } -internal class OffsetStage internal constructor(private val offset: Int) : Stage("offset") { +internal class OffsetStage +internal constructor(private val offset: Int, options: InternalOptions = InternalOptions.EMPTY) : + Stage("offset", options) { + override fun self(options: InternalOptions) = OffsetStage(offset, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(offset)) } -internal class SelectStage internal constructor(private val fields: Array) : - Stage("select") { +internal class SelectStage +internal constructor( + private val fields: Array, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("select", options) { + override fun self(options: InternalOptions) = SelectStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) } -internal class SortStage internal constructor(private val orders: Array) : - Stage("sort") { +internal class SortStage +internal constructor( + private val orders: Array, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("sort", options) { + override fun self(options: InternalOptions) = SortStage(orders, options) override fun args(userDataReader: UserDataReader): Sequence = orders.asSequence().map { it.toProto(userDataReader) } } -internal class DistinctStage internal constructor(private val groups: Array) : - Stage("distinct") { +internal class DistinctStage +internal constructor( + private val groups: Array, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("distinct", options) { + override fun self(options: InternalOptions) = DistinctStage(groups, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(groups.associate { it.getAlias() to it.toProto(userDataReader) })) } -internal class RemoveFieldsStage internal constructor(private val fields: Array) : - Stage("remove_fields") { +internal class RemoveFieldsStage +internal constructor( + private val fields: Array, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("remove_fields", options) { + override fun self(options: InternalOptions) = RemoveFieldsStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = fields.asSequence().map(Field::toProto) } internal class ReplaceStage -internal constructor(private val field: Selectable, private val mode: Mode) : Stage("replace") { +internal constructor( + private val field: Selectable, + private val mode: Mode, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("replace", options) { class Mode private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) companion object { @@ -257,12 +331,18 @@ internal constructor(private val field: Selectable, private val mode: Mode) : St val MERGE_PREFER_PARENT = Mode("merge_prefer_parent") } } + override fun self(options: InternalOptions) = ReplaceStage(field, mode, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(field.toProto(userDataReader), mode.proto) } -class SampleStage private constructor(private val size: Number, private val mode: Mode) : - Stage("sample") { +class SampleStage +private constructor( + private val size: Number, + private val mode: Mode, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("sample", options) { + override fun self(options: InternalOptions) = SampleStage(size, mode, options) class Mode private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) companion object { @@ -280,27 +360,29 @@ class SampleStage private constructor(private val size: Number, private val mode } internal class UnionStage -internal constructor(private val other: com.google.firebase.firestore.Pipeline) : Stage("union") { +internal constructor( + private val other: com.google.firebase.firestore.Pipeline, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("union", options) { + override fun self(options: InternalOptions) = UnionStage(other, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setPipelineValue(other.toPipelineProto()).build()) } -internal class UnnestStage -internal constructor(private val selectable: Selectable, options: UnnestOptions) : - Stage("unnest", options) { - internal constructor(selectable: Selectable) : this(selectable, UnnestOptions.DEFAULT) +class UnnestStage +internal constructor( + private val selectable: Selectable, + options: InternalOptions = InternalOptions.EMPTY +) : Stage("unnest", options) { + companion object { + @JvmStatic fun withField(selectable: Selectable) = UnnestStage(selectable) + @JvmStatic + fun withField(field: String, alias: String): UnnestStage = + UnnestStage(Field.of(field).alias(alias)) + } + override fun self(options: InternalOptions) = UnnestStage(selectable, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(selectable.getAlias()), selectable.toProto(userDataReader)) -} - -class UnnestOptions private constructor(options: InternalOptions) : - AbstractOptions(options) { - - fun withIndexField(indexField: String): UnnestOptions = with("index_field", indexField) - override fun self(options: InternalOptions) = UnnestOptions(options) - - companion object { - @JvmField val DEFAULT: UnnestOptions = UnnestOptions(InternalOptions.EMPTY) - } + fun withIndexField(indexField: String): UnnestStage = with("index_field", indexField) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java index 91086531db1..e3a8da26217 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/Datastore.java @@ -22,6 +22,7 @@ import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; import com.google.common.base.Strings; +import com.google.firebase.Timestamp; import com.google.firebase.firestore.AggregateField; import com.google.firebase.firestore.FirebaseFirestoreException; import com.google.firebase.firestore.PipelineResultObserver; @@ -248,17 +249,24 @@ public void executePipeline(ExecutePipelineRequest request, PipelineResultObserv request, new FirestoreChannel.StreamingListener() { - private SnapshotVersion executionTime = SnapshotVersion.NONE; + private Timestamp executionTime = null; @Override public void onMessage(ExecutePipelineResponse message) { - setExecutionTime(serializer.decodeVersion(message.getExecutionTime())); + if (message.hasExecutionTime()) { + executionTime = serializer.decodeTimestamp(message.getExecutionTime()); + } for (Document document : message.getResultsList()) { String documentName = document.getName(); observer.onDocument( Strings.isNullOrEmpty(documentName) ? null : serializer.decodeKey(documentName), document.getFieldsMap(), - serializer.decodeVersion(document.getUpdateTime())); + document.hasCreateTime() + ? serializer.decodeTimestamp(document.getCreateTime()) + : null, + document.hasUpdateTime() + ? serializer.decodeTimestamp(document.getUpdateTime()) + : null); } } @@ -274,13 +282,6 @@ public void onClose(Status status) { observer.onError(exception); } } - - private void setExecutionTime(SnapshotVersion executionTime) { - if (executionTime.equals(SnapshotVersion.NONE)) { - return; - } - this.executionTime = executionTime; - } }); } From 8141aa8c024119f5847aeac469535195b1578d40 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Wed, 9 Apr 2025 10:03:26 -0400 Subject: [PATCH 35/77] Fixups --- .../firebase/firestore/PipelineTest.java | 66 +-- .../firebase/firestore/AggregateField.java | 4 +- .../firebase/firestore/core/FieldFilter.java | 2 +- .../google/firebase/firestore/core/Query.java | 12 +- .../firebase/firestore/pipeline/aggregates.kt | 31 +- .../firestore/pipeline/expressions.kt | 488 +++++++++--------- .../firebase/firestore/pipeline/stage.kt | 11 +- 7 files changed, 308 insertions(+), 306 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 7b69f8f216b..cd4fc945221 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -15,25 +15,25 @@ package com.google.firebase.firestore; import static com.google.common.truth.Truth.assertThat; -import static com.google.firebase.firestore.pipeline.Function.add; -import static com.google.firebase.firestore.pipeline.Function.and; -import static com.google.firebase.firestore.pipeline.Function.arrayContains; -import static com.google.firebase.firestore.pipeline.Function.arrayContainsAny; -import static com.google.firebase.firestore.pipeline.Function.cosineDistance; -import static com.google.firebase.firestore.pipeline.Function.endsWith; -import static com.google.firebase.firestore.pipeline.Function.eq; -import static com.google.firebase.firestore.pipeline.Function.euclideanDistance; -import static com.google.firebase.firestore.pipeline.Function.gt; -import static com.google.firebase.firestore.pipeline.Function.logicalMax; -import static com.google.firebase.firestore.pipeline.Function.lt; -import static com.google.firebase.firestore.pipeline.Function.lte; -import static com.google.firebase.firestore.pipeline.Function.mapGet; -import static com.google.firebase.firestore.pipeline.Function.neq; -import static com.google.firebase.firestore.pipeline.Function.not; -import static com.google.firebase.firestore.pipeline.Function.or; -import static com.google.firebase.firestore.pipeline.Function.startsWith; -import static com.google.firebase.firestore.pipeline.Function.strConcat; -import static com.google.firebase.firestore.pipeline.Function.subtract; +import static com.google.firebase.firestore.pipeline.FunctionExpr.add; +import static com.google.firebase.firestore.pipeline.FunctionExpr.and; +import static com.google.firebase.firestore.pipeline.FunctionExpr.arrayContains; +import static com.google.firebase.firestore.pipeline.FunctionExpr.arrayContainsAny; +import static com.google.firebase.firestore.pipeline.FunctionExpr.cosineDistance; +import static com.google.firebase.firestore.pipeline.FunctionExpr.endsWith; +import static com.google.firebase.firestore.pipeline.FunctionExpr.eq; +import static com.google.firebase.firestore.pipeline.FunctionExpr.euclideanDistance; +import static com.google.firebase.firestore.pipeline.FunctionExpr.gt; +import static com.google.firebase.firestore.pipeline.FunctionExpr.logicalMax; +import static com.google.firebase.firestore.pipeline.FunctionExpr.lt; +import static com.google.firebase.firestore.pipeline.FunctionExpr.lte; +import static com.google.firebase.firestore.pipeline.FunctionExpr.mapGet; +import static com.google.firebase.firestore.pipeline.FunctionExpr.neq; +import static com.google.firebase.firestore.pipeline.FunctionExpr.not; +import static com.google.firebase.firestore.pipeline.FunctionExpr.or; +import static com.google.firebase.firestore.pipeline.FunctionExpr.startsWith; +import static com.google.firebase.firestore.pipeline.FunctionExpr.strConcat; +import static com.google.firebase.firestore.pipeline.FunctionExpr.subtract; import static com.google.firebase.firestore.pipeline.Ordering.ascending; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.waitFor; @@ -42,11 +42,11 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.truth.Correspondence; -import com.google.firebase.firestore.pipeline.AggregateExpr; +import com.google.firebase.firestore.pipeline.AggregateFunction; import com.google.firebase.firestore.pipeline.AggregateStage; import com.google.firebase.firestore.pipeline.Constant; import com.google.firebase.firestore.pipeline.Field; -import com.google.firebase.firestore.pipeline.Function; +import com.google.firebase.firestore.pipeline.FunctionExpr; import com.google.firebase.firestore.pipeline.GenericStage; import com.google.firebase.firestore.testutil.IntegrationTestUtil; import java.util.Collections; @@ -226,7 +226,7 @@ public void aggregateResultsCountAll() { firestore .pipeline() .collection(randomCol) - .aggregate(AggregateExpr.countAll().alias("count")) + .aggregate(AggregateFunction.countAll().alias("count")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -240,10 +240,10 @@ public void aggregateResultsMany() { firestore .pipeline() .collection(randomCol) - .where(Function.eq("genre", "Science Fiction")) + .where(FunctionExpr.eq("genre", "Science Fiction")) .aggregate( - AggregateExpr.countAll().alias("count"), - AggregateExpr.avg("rating").alias("avgRating"), + AggregateFunction.countAll().alias("count"), + AggregateFunction.avg("rating").alias("avgRating"), Field.of("rating").max().alias("maxRating")) .execute(); assertThat(waitFor(execute).getResults()) @@ -260,7 +260,7 @@ public void groupAndAccumulateResults() { .collection(randomCol) .where(lt(Field.of("published"), 1984)) .aggregate( - AggregateStage.withAccumulators(AggregateExpr.avg("rating").alias("avgRating")) + AggregateStage.withAccumulators(AggregateFunction.avg("rating").alias("avgRating")) .withGroups("genre")) .where(gt("avgRating", 4.3)) .sort(Field.of("avgRating").descending()) @@ -282,9 +282,9 @@ public void groupAndAccumulateResultsGeneric() { .genericStage("where", lt(Field.of("published"), 1984)) .genericStage( "aggregate", - ImmutableMap.of("avgRating", AggregateExpr.avg("rating")), + ImmutableMap.of("avgRating", AggregateFunction.avg("rating")), ImmutableMap.of("genre", Field.of("genre"))) - .genericStage(GenericStage.of("where").withArguments(gt("avgRating", 4.3))) + .genericStage(GenericStage.ofName("where").withArguments(gt("avgRating", 4.3))) .genericStage("sort", Field.of("avgRating").descending()) .execute(); assertThat(waitFor(execute).getResults()) @@ -303,7 +303,7 @@ public void minAndMaxAccumulations() { .pipeline() .collection(randomCol) .aggregate( - AggregateExpr.countAll().alias("count"), + AggregateFunction.countAll().alias("count"), Field.of("rating").max().alias("maxRating"), Field.of("published").min().alias("minPublished")) .execute(); @@ -600,7 +600,7 @@ public void testLike() { firestore .pipeline() .collection(randomCol) - .where(Function.like("title", "%Guide%")) + .where(FunctionExpr.like("title", "%Guide%")) .select("title") .execute(); assertThat(waitFor(execute).getResults()) @@ -614,7 +614,7 @@ public void testRegexContains() { firestore .pipeline() .collection(randomCol) - .where(Function.regexContains("title", "(?i)(the|of)")) + .where(FunctionExpr.regexContains("title", "(?i)(the|of)")) .execute(); assertThat(waitFor(execute).getResults()).hasSize(5); } @@ -625,7 +625,7 @@ public void testRegexMatches() { firestore .pipeline() .collection(randomCol) - .where(Function.regexContains("title", ".*(?i)(the|of).*")) + .where(FunctionExpr.regexContains("title", ".*(?i)(the|of).*")) .execute(); assertThat(waitFor(execute).getResults()).hasSize(5); } @@ -771,7 +771,7 @@ public void testDistanceFunctions() { .collection(randomCol) .select( cosineDistance(Constant.vector(sourceVector), targetVector).alias("cosineDistance"), - Function.dotProduct(Constant.vector(sourceVector), targetVector) + FunctionExpr.dotProduct(Constant.vector(sourceVector), targetVector) .alias("dotProductDistance"), euclideanDistance(Constant.vector(sourceVector), targetVector) .alias("euclideanDistance")) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java index d9cdff77bfc..d26f82ea7c2 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java @@ -17,7 +17,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; -import com.google.firebase.firestore.pipeline.AggregateExpr; +import com.google.firebase.firestore.pipeline.AggregateFunction; import com.google.firebase.firestore.pipeline.AggregateWithAlias; import com.google.firebase.firestore.pipeline.Field; import java.util.Objects; @@ -205,7 +205,7 @@ private CountAggregateField() { @NonNull @Override AggregateWithAlias toPipeline() { - return AggregateExpr.countAll().alias(getAlias()); + return AggregateFunction.countAll().alias(getAlias()); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java index 4d2a5a404c0..cc3c5402eb6 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java @@ -14,7 +14,7 @@ package com.google.firebase.firestore.core; -import static com.google.firebase.firestore.pipeline.Function.and; +import static com.google.firebase.firestore.pipeline.FunctionExpr.and; import static com.google.firebase.firestore.util.Assert.hardAssert; import static java.lang.Double.isNaN; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index 266b280d41f..e3045ea2aec 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -14,8 +14,8 @@ package com.google.firebase.firestore.core; -import static com.google.firebase.firestore.pipeline.Function.and; -import static com.google.firebase.firestore.pipeline.Function.or; +import static com.google.firebase.firestore.pipeline.FunctionExpr.and; +import static com.google.firebase.firestore.pipeline.FunctionExpr.or; import static com.google.firebase.firestore.util.Assert.hardAssert; import androidx.annotation.NonNull; @@ -34,7 +34,7 @@ import com.google.firebase.firestore.pipeline.DocumentsSource; import com.google.firebase.firestore.pipeline.Expr; import com.google.firebase.firestore.pipeline.Field; -import com.google.firebase.firestore.pipeline.Function; +import com.google.firebase.firestore.pipeline.FunctionExpr; import com.google.firebase.firestore.pipeline.Ordering; import com.google.firebase.firestore.pipeline.Stage; import com.google.firestore.v1.Value; @@ -552,11 +552,11 @@ public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataR } if (startAt != null) { - p = p.where(whereConditionsFromCursor(startAt, fields, Function::gt)); + p = p.where(whereConditionsFromCursor(startAt, fields, FunctionExpr::gt)); } if (endAt != null) { - p = p.where(whereConditionsFromCursor(endAt, fields, Function::lt)); + p = p.where(whereConditionsFromCursor(endAt, fields, FunctionExpr::lt)); } // Cursors, Limit, Offset @@ -585,7 +585,7 @@ private static BooleanExpr whereConditionsFromCursor( int last = size - 1; BooleanExpr condition = cmp.apply(fields.get(last), boundPosition.get(last)); if (bound.isInclusive()) { - condition = or(condition, Function.eq(fields.get(last), boundPosition.get(last))); + condition = or(condition, FunctionExpr.eq(fields.get(last), boundPosition.get(last))); } for (int i = size - 2; i >= 0; i--) { final Field field = fields.get(i); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt index 308b6fb70f0..0461718d7fa 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt @@ -18,38 +18,41 @@ import com.google.firebase.firestore.UserDataReader import com.google.firestore.v1.Value class AggregateWithAlias -internal constructor(internal val alias: String, internal val expr: AggregateExpr) +internal constructor(internal val alias: String, internal val expr: AggregateFunction) -class AggregateExpr +class AggregateFunction private constructor(private val name: String, private val params: Array) { private constructor(name: String) : this(name, emptyArray()) private constructor(name: String, expr: Expr) : this(name, arrayOf(expr)) private constructor(name: String, fieldName: String) : this(name, Field.of(fieldName)) companion object { - @JvmStatic fun countAll() = AggregateExpr("count") - @JvmStatic fun count(fieldName: String) = AggregateExpr("count", fieldName) + @JvmStatic fun generic(name: String, vararg expr: Expr) = AggregateFunction(name, expr) - @JvmStatic fun count(expr: Expr) = AggregateExpr("count", expr) + @JvmStatic fun countAll() = AggregateFunction("count") - @JvmStatic fun countIf(condition: BooleanExpr) = AggregateExpr("countIf", condition) + @JvmStatic fun count(fieldName: String) = AggregateFunction("count", fieldName) - @JvmStatic fun sum(fieldName: String) = AggregateExpr("sum", fieldName) + @JvmStatic fun count(expr: Expr) = AggregateFunction("count", expr) - @JvmStatic fun sum(expr: Expr) = AggregateExpr("sum", expr) + @JvmStatic fun countIf(condition: BooleanExpr) = AggregateFunction("countIf", condition) - @JvmStatic fun avg(fieldName: String) = AggregateExpr("avg", fieldName) + @JvmStatic fun sum(fieldName: String) = AggregateFunction("sum", fieldName) - @JvmStatic fun avg(expr: Expr) = AggregateExpr("avg", expr) + @JvmStatic fun sum(expr: Expr) = AggregateFunction("sum", expr) - @JvmStatic fun min(fieldName: String) = AggregateExpr("min", fieldName) + @JvmStatic fun avg(fieldName: String) = AggregateFunction("avg", fieldName) - @JvmStatic fun min(expr: Expr) = AggregateExpr("min", expr) + @JvmStatic fun avg(expr: Expr) = AggregateFunction("avg", expr) - @JvmStatic fun max(fieldName: String) = AggregateExpr("max", fieldName) + @JvmStatic fun min(fieldName: String) = AggregateFunction("min", fieldName) - @JvmStatic fun max(expr: Expr) = AggregateExpr("max", expr) + @JvmStatic fun min(expr: Expr) = AggregateFunction("min", expr) + + @JvmStatic fun max(fieldName: String) = AggregateFunction("max", fieldName) + + @JvmStatic fun max(expr: Expr) = AggregateFunction("max", expr) } fun alias(alias: String) = AggregateWithAlias(alias, this) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 1d84e905723..12e7439d745 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -57,7 +57,7 @@ abstract class Expr internal constructor() { is VectorValue -> of(value) is Value -> of(value) is Map<*, *> -> - Function.map( + FunctionExpr.map( value .flatMap { val key = it.key @@ -78,27 +78,27 @@ abstract class Expr internal constructor() { others.map(::toExprOrConstant).toTypedArray() } - fun bitAnd(right: Expr) = Function.bitAnd(this, right) + fun bitAnd(right: Expr) = FunctionExpr.bitAnd(this, right) - fun bitAnd(right: Any) = Function.bitAnd(this, right) + fun bitAnd(right: Any) = FunctionExpr.bitAnd(this, right) - fun bitOr(right: Expr) = Function.bitOr(this, right) + fun bitOr(right: Expr) = FunctionExpr.bitOr(this, right) - fun bitOr(right: Any) = Function.bitOr(this, right) + fun bitOr(right: Any) = FunctionExpr.bitOr(this, right) - fun bitXor(right: Expr) = Function.bitXor(this, right) + fun bitXor(right: Expr) = FunctionExpr.bitXor(this, right) - fun bitXor(right: Any) = Function.bitXor(this, right) + fun bitXor(right: Any) = FunctionExpr.bitXor(this, right) - fun bitNot() = Function.bitNot(this) + fun bitNot() = FunctionExpr.bitNot(this) - fun bitLeftShift(numberExpr: Expr) = Function.bitLeftShift(this, numberExpr) + fun bitLeftShift(numberExpr: Expr) = FunctionExpr.bitLeftShift(this, numberExpr) - fun bitLeftShift(number: Int) = Function.bitLeftShift(this, number) + fun bitLeftShift(number: Int) = FunctionExpr.bitLeftShift(this, number) - fun bitRightShift(numberExpr: Expr) = Function.bitRightShift(this, numberExpr) + fun bitRightShift(numberExpr: Expr) = FunctionExpr.bitRightShift(this, numberExpr) - fun bitRightShift(number: Int) = Function.bitRightShift(this, number) + fun bitRightShift(number: Int) = FunctionExpr.bitRightShift(this, number) /** * Assigns an alias to this expression. @@ -131,7 +131,7 @@ abstract class Expr internal constructor() { * @param other The expression to add to this expression. * @return A new {@code Expr} representing the addition operation. */ - fun add(other: Expr) = Function.add(this, other) + fun add(other: Expr) = FunctionExpr.add(this, other) /** * Creates an expression that this expression to another expression. @@ -144,198 +144,198 @@ abstract class Expr internal constructor() { * @param other The constant value to add to this expression. * @return A new {@code Expr} representing the addition operation. */ - fun add(other: Any) = Function.add(this, other) + fun add(other: Any) = FunctionExpr.add(this, other) - fun subtract(other: Expr) = Function.subtract(this, other) + fun subtract(other: Expr) = FunctionExpr.subtract(this, other) - fun subtract(other: Any) = Function.subtract(this, other) + fun subtract(other: Any) = FunctionExpr.subtract(this, other) - fun multiply(other: Expr) = Function.multiply(this, other) + fun multiply(other: Expr) = FunctionExpr.multiply(this, other) - fun multiply(other: Any) = Function.multiply(this, other) + fun multiply(other: Any) = FunctionExpr.multiply(this, other) - fun divide(other: Expr) = Function.divide(this, other) + fun divide(other: Expr) = FunctionExpr.divide(this, other) - fun divide(other: Any) = Function.divide(this, other) + fun divide(other: Any) = FunctionExpr.divide(this, other) - fun mod(other: Expr) = Function.mod(this, other) + fun mod(other: Expr) = FunctionExpr.mod(this, other) - fun mod(other: Any) = Function.mod(this, other) + fun mod(other: Any) = FunctionExpr.mod(this, other) - fun eqAny(values: List) = Function.eqAny(this, values) + fun eqAny(values: List) = FunctionExpr.eqAny(this, values) - fun notEqAny(values: List) = Function.notEqAny(this, values) + fun notEqAny(values: List) = FunctionExpr.notEqAny(this, values) - fun isNan() = Function.isNan(this) + fun isNan() = FunctionExpr.isNan(this) - fun isNotNan() = Function.isNotNan(this) + fun isNotNan() = FunctionExpr.isNotNan(this) - fun isNull() = Function.isNull(this) + fun isNull() = FunctionExpr.isNull(this) - fun isNotNull() = Function.isNotNull(this) + fun isNotNull() = FunctionExpr.isNotNull(this) - fun replaceFirst(find: Expr, replace: Expr) = Function.replaceFirst(this, find, replace) + fun replaceFirst(find: Expr, replace: Expr) = FunctionExpr.replaceFirst(this, find, replace) - fun replaceFirst(find: String, replace: String) = Function.replaceFirst(this, find, replace) + fun replaceFirst(find: String, replace: String) = FunctionExpr.replaceFirst(this, find, replace) - fun replaceAll(find: Expr, replace: Expr) = Function.replaceAll(this, find, replace) + fun replaceAll(find: Expr, replace: Expr) = FunctionExpr.replaceAll(this, find, replace) - fun replaceAll(find: String, replace: String) = Function.replaceAll(this, find, replace) + fun replaceAll(find: String, replace: String) = FunctionExpr.replaceAll(this, find, replace) - fun charLength() = Function.charLength(this) + fun charLength() = FunctionExpr.charLength(this) - fun byteLength() = Function.byteLength(this) + fun byteLength() = FunctionExpr.byteLength(this) - fun like(pattern: Expr) = Function.like(this, pattern) + fun like(pattern: Expr) = FunctionExpr.like(this, pattern) - fun like(pattern: String) = Function.like(this, pattern) + fun like(pattern: String) = FunctionExpr.like(this, pattern) - fun regexContains(pattern: Expr) = Function.regexContains(this, pattern) + fun regexContains(pattern: Expr) = FunctionExpr.regexContains(this, pattern) - fun regexContains(pattern: String) = Function.regexContains(this, pattern) + fun regexContains(pattern: String) = FunctionExpr.regexContains(this, pattern) - fun regexMatch(pattern: Expr) = Function.regexMatch(this, pattern) + fun regexMatch(pattern: Expr) = FunctionExpr.regexMatch(this, pattern) - fun regexMatch(pattern: String) = Function.regexMatch(this, pattern) + fun regexMatch(pattern: String) = FunctionExpr.regexMatch(this, pattern) - fun logicalMax(other: Expr) = Function.logicalMax(this, other) + fun logicalMax(other: Expr) = FunctionExpr.logicalMax(this, other) - fun logicalMax(other: Any) = Function.logicalMax(this, other) + fun logicalMax(other: Any) = FunctionExpr.logicalMax(this, other) - fun logicalMin(other: Expr) = Function.logicalMin(this, other) + fun logicalMin(other: Expr) = FunctionExpr.logicalMin(this, other) - fun logicalMin(other: Any) = Function.logicalMin(this, other) + fun logicalMin(other: Any) = FunctionExpr.logicalMin(this, other) - fun reverse() = Function.reverse(this) + fun reverse() = FunctionExpr.reverse(this) - fun strContains(substring: Expr) = Function.strContains(this, substring) + fun strContains(substring: Expr) = FunctionExpr.strContains(this, substring) - fun strContains(substring: String) = Function.strContains(this, substring) + fun strContains(substring: String) = FunctionExpr.strContains(this, substring) - fun startsWith(prefix: Expr) = Function.startsWith(this, prefix) + fun startsWith(prefix: Expr) = FunctionExpr.startsWith(this, prefix) - fun startsWith(prefix: String) = Function.startsWith(this, prefix) + fun startsWith(prefix: String) = FunctionExpr.startsWith(this, prefix) - fun endsWith(suffix: Expr) = Function.endsWith(this, suffix) + fun endsWith(suffix: Expr) = FunctionExpr.endsWith(this, suffix) - fun endsWith(suffix: String) = Function.endsWith(this, suffix) + fun endsWith(suffix: String) = FunctionExpr.endsWith(this, suffix) - fun toLower() = Function.toLower(this) + fun toLower() = FunctionExpr.toLower(this) - fun toUpper() = Function.toUpper(this) + fun toUpper() = FunctionExpr.toUpper(this) - fun trim() = Function.trim(this) + fun trim() = FunctionExpr.trim(this) - fun strConcat(vararg expr: Expr) = Function.strConcat(this, *expr) + fun strConcat(vararg expr: Expr) = FunctionExpr.strConcat(this, *expr) - fun strConcat(vararg string: String) = Function.strConcat(this, *string) + fun strConcat(vararg string: String) = FunctionExpr.strConcat(this, *string) - fun strConcat(vararg string: Any) = Function.strConcat(this, *string) + fun strConcat(vararg string: Any) = FunctionExpr.strConcat(this, *string) - fun mapGet(key: Expr) = Function.mapGet(this, key) + fun mapGet(key: Expr) = FunctionExpr.mapGet(this, key) - fun mapGet(key: String) = Function.mapGet(this, key) + fun mapGet(key: String) = FunctionExpr.mapGet(this, key) fun mapMerge(secondMap: Expr, vararg otherMaps: Expr) = - Function.mapMerge(this, secondMap, *otherMaps) + FunctionExpr.mapMerge(this, secondMap, *otherMaps) - fun mapRemove(key: Expr) = Function.mapRemove(this, key) + fun mapRemove(key: Expr) = FunctionExpr.mapRemove(this, key) - fun mapRemove(key: String) = Function.mapRemove(this, key) + fun mapRemove(key: String) = FunctionExpr.mapRemove(this, key) - fun cosineDistance(vector: Expr) = Function.cosineDistance(this, vector) + fun cosineDistance(vector: Expr) = FunctionExpr.cosineDistance(this, vector) - fun cosineDistance(vector: DoubleArray) = Function.cosineDistance(this, vector) + fun cosineDistance(vector: DoubleArray) = FunctionExpr.cosineDistance(this, vector) - fun cosineDistance(vector: VectorValue) = Function.cosineDistance(this, vector) + fun cosineDistance(vector: VectorValue) = FunctionExpr.cosineDistance(this, vector) - fun dotProduct(vector: Expr) = Function.dotProduct(this, vector) + fun dotProduct(vector: Expr) = FunctionExpr.dotProduct(this, vector) - fun dotProduct(vector: DoubleArray) = Function.dotProduct(this, vector) + fun dotProduct(vector: DoubleArray) = FunctionExpr.dotProduct(this, vector) - fun dotProduct(vector: VectorValue) = Function.dotProduct(this, vector) + fun dotProduct(vector: VectorValue) = FunctionExpr.dotProduct(this, vector) - fun euclideanDistance(vector: Expr) = Function.euclideanDistance(this, vector) + fun euclideanDistance(vector: Expr) = FunctionExpr.euclideanDistance(this, vector) - fun euclideanDistance(vector: DoubleArray) = Function.euclideanDistance(this, vector) + fun euclideanDistance(vector: DoubleArray) = FunctionExpr.euclideanDistance(this, vector) - fun euclideanDistance(vector: VectorValue) = Function.euclideanDistance(this, vector) + fun euclideanDistance(vector: VectorValue) = FunctionExpr.euclideanDistance(this, vector) - fun vectorLength() = Function.vectorLength(this) + fun vectorLength() = FunctionExpr.vectorLength(this) - fun unixMicrosToTimestamp() = Function.unixMicrosToTimestamp(this) + fun unixMicrosToTimestamp() = FunctionExpr.unixMicrosToTimestamp(this) - fun timestampToUnixMicros() = Function.timestampToUnixMicros(this) + fun timestampToUnixMicros() = FunctionExpr.timestampToUnixMicros(this) - fun unixMillisToTimestamp() = Function.unixMillisToTimestamp(this) + fun unixMillisToTimestamp() = FunctionExpr.unixMillisToTimestamp(this) - fun timestampToUnixMillis() = Function.timestampToUnixMillis(this) + fun timestampToUnixMillis() = FunctionExpr.timestampToUnixMillis(this) - fun unixSecondsToTimestamp() = Function.unixSecondsToTimestamp(this) + fun unixSecondsToTimestamp() = FunctionExpr.unixSecondsToTimestamp(this) - fun timestampToUnixSeconds() = Function.timestampToUnixSeconds(this) + fun timestampToUnixSeconds() = FunctionExpr.timestampToUnixSeconds(this) - fun timestampAdd(unit: Expr, amount: Expr) = Function.timestampAdd(this, unit, amount) + fun timestampAdd(unit: Expr, amount: Expr) = FunctionExpr.timestampAdd(this, unit, amount) - fun timestampAdd(unit: String, amount: Double) = Function.timestampAdd(this, unit, amount) + fun timestampAdd(unit: String, amount: Double) = FunctionExpr.timestampAdd(this, unit, amount) - fun timestampSub(unit: Expr, amount: Expr) = Function.timestampSub(this, unit, amount) + fun timestampSub(unit: Expr, amount: Expr) = FunctionExpr.timestampSub(this, unit, amount) - fun timestampSub(unit: String, amount: Double) = Function.timestampSub(this, unit, amount) + fun timestampSub(unit: String, amount: Double) = FunctionExpr.timestampSub(this, unit, amount) - fun arrayConcat(vararg arrays: Expr) = Function.arrayConcat(this, *arrays) + fun arrayConcat(vararg arrays: Expr) = FunctionExpr.arrayConcat(this, *arrays) - fun arrayConcat(arrays: List) = Function.arrayConcat(this, arrays) + fun arrayConcat(arrays: List) = FunctionExpr.arrayConcat(this, arrays) - fun arrayReverse() = Function.arrayReverse(this) + fun arrayReverse() = FunctionExpr.arrayReverse(this) - fun arrayContains(value: Expr) = Function.arrayContains(this, value) + fun arrayContains(value: Expr) = FunctionExpr.arrayContains(this, value) - fun arrayContains(value: Any) = Function.arrayContains(this, value) + fun arrayContains(value: Any) = FunctionExpr.arrayContains(this, value) - fun arrayContainsAll(values: List) = Function.arrayContainsAll(this, values) + fun arrayContainsAll(values: List) = FunctionExpr.arrayContainsAll(this, values) - fun arrayContainsAny(values: List) = Function.arrayContainsAny(this, values) + fun arrayContainsAny(values: List) = FunctionExpr.arrayContainsAny(this, values) - fun arrayLength() = Function.arrayLength(this) + fun arrayLength() = FunctionExpr.arrayLength(this) - fun sum() = AggregateExpr.sum(this) + fun sum() = AggregateFunction.sum(this) - fun avg() = AggregateExpr.avg(this) + fun avg() = AggregateFunction.avg(this) - fun min() = AggregateExpr.min(this) + fun min() = AggregateFunction.min(this) - fun max() = AggregateExpr.max(this) + fun max() = AggregateFunction.max(this) fun ascending() = Ordering.ascending(this) fun descending() = Ordering.descending(this) - fun eq(other: Expr) = Function.eq(this, other) + fun eq(other: Expr) = FunctionExpr.eq(this, other) - fun eq(other: Any) = Function.eq(this, other) + fun eq(other: Any) = FunctionExpr.eq(this, other) - fun neq(other: Expr) = Function.neq(this, other) + fun neq(other: Expr) = FunctionExpr.neq(this, other) - fun neq(other: Any) = Function.neq(this, other) + fun neq(other: Any) = FunctionExpr.neq(this, other) - fun gt(other: Expr) = Function.gt(this, other) + fun gt(other: Expr) = FunctionExpr.gt(this, other) - fun gt(other: Any) = Function.gt(this, other) + fun gt(other: Any) = FunctionExpr.gt(this, other) - fun gte(other: Expr) = Function.gte(this, other) + fun gte(other: Expr) = FunctionExpr.gte(this, other) - fun gte(other: Any) = Function.gte(this, other) + fun gte(other: Any) = FunctionExpr.gte(this, other) - fun lt(other: Expr) = Function.lt(this, other) + fun lt(other: Expr) = FunctionExpr.lt(this, other) - fun lt(other: Any) = Function.lt(this, other) + fun lt(other: Any) = FunctionExpr.lt(this, other) - fun lte(other: Expr) = Function.lte(this, other) + fun lte(other: Expr) = FunctionExpr.lte(this, other) - fun lte(other: Any) = Function.lte(this, other) + fun lte(other: Any) = FunctionExpr.lte(this, other) - fun exists() = Function.exists(this) + fun exists() = FunctionExpr.exists(this) internal abstract fun toProto(userDataReader: UserDataReader): Value } @@ -392,7 +392,7 @@ internal class ListOfExprs(private val expressions: Array) : Expr() { encodeValue(expressions.map { it.toProto(userDataReader) }) } -open class Function +open class FunctionExpr protected constructor(private val name: String, private val params: Array) : Expr() { private constructor( name: String, @@ -406,7 +406,7 @@ protected constructor(private val name: String, private val params: Array) = @@ -550,35 +550,35 @@ protected constructor(private val name: String, private val params: Array) = Function("map", elements) + internal fun map(elements: Array) = FunctionExpr("map", elements) @JvmStatic fun map(elements: Map) = map(elements.flatMap { listOf(of(it.key), toExprOrConstant(it.value)) }.toTypedArray()) - @JvmStatic fun mapGet(map: Expr, key: Expr) = Function("map_get", map, key) + @JvmStatic fun mapGet(map: Expr, key: Expr) = FunctionExpr("map_get", map, key) - @JvmStatic fun mapGet(map: Expr, key: String) = Function("map_get", map, key) + @JvmStatic fun mapGet(map: Expr, key: String) = FunctionExpr("map_get", map, key) - @JvmStatic fun mapGet(fieldName: String, key: Expr) = Function("map_get", fieldName, key) + @JvmStatic fun mapGet(fieldName: String, key: Expr) = FunctionExpr("map_get", fieldName, key) - @JvmStatic fun mapGet(fieldName: String, key: String) = Function("map_get", fieldName, key) + @JvmStatic fun mapGet(fieldName: String, key: String) = FunctionExpr("map_get", fieldName, key) @JvmStatic fun mapMerge(firstMap: Expr, secondMap: Expr, vararg otherMaps: Expr) = - Function("map_merge", firstMap, secondMap, otherMaps) + FunctionExpr("map_merge", firstMap, secondMap, otherMaps) @JvmStatic fun mapMerge(mapField: String, secondMap: Expr, vararg otherMaps: Expr) = - Function("map_merge", mapField, secondMap, otherMaps) + FunctionExpr("map_merge", mapField, secondMap, otherMaps) - @JvmStatic fun mapRemove(firstMap: Expr, key: Expr) = Function("map_remove", firstMap, key) + @JvmStatic fun mapRemove(firstMap: Expr, key: Expr) = FunctionExpr("map_remove", firstMap, key) - @JvmStatic fun mapRemove(mapField: String, key: Expr) = Function("map_remove", mapField, key) + @JvmStatic fun mapRemove(mapField: String, key: Expr) = FunctionExpr("map_remove", mapField, key) - @JvmStatic fun mapRemove(firstMap: Expr, key: String) = Function("map_remove", firstMap, key) + @JvmStatic fun mapRemove(firstMap: Expr, key: String) = FunctionExpr("map_remove", firstMap, key) - @JvmStatic fun mapRemove(mapField: String, key: String) = Function("map_remove", mapField, key) + @JvmStatic fun mapRemove(mapField: String, key: String) = FunctionExpr("map_remove", mapField, key) @JvmStatic - fun cosineDistance(vector1: Expr, vector2: Expr) = Function("cosine_distance", vector1, vector2) + fun cosineDistance(vector1: Expr, vector2: Expr) = FunctionExpr("cosine_distance", vector1, vector2) @JvmStatic fun cosineDistance(vector1: Expr, vector2: DoubleArray) = - Function("cosine_distance", vector1, Constant.vector(vector2)) + FunctionExpr("cosine_distance", vector1, Constant.vector(vector2)) @JvmStatic fun cosineDistance(vector1: Expr, vector2: VectorValue) = - Function("cosine_distance", vector1, vector2) + FunctionExpr("cosine_distance", vector1, vector2) @JvmStatic fun cosineDistance(fieldName: String, vector: Expr) = - Function("cosine_distance", fieldName, vector) + FunctionExpr("cosine_distance", fieldName, vector) @JvmStatic fun cosineDistance(fieldName: String, vector: DoubleArray) = - Function("cosine_distance", fieldName, Constant.vector(vector)) + FunctionExpr("cosine_distance", fieldName, Constant.vector(vector)) @JvmStatic fun cosineDistance(fieldName: String, vector: VectorValue) = - Function("cosine_distance", fieldName, vector) + FunctionExpr("cosine_distance", fieldName, vector) @JvmStatic - fun dotProduct(vector1: Expr, vector2: Expr) = Function("dot_product", vector1, vector2) + fun dotProduct(vector1: Expr, vector2: Expr) = FunctionExpr("dot_product", vector1, vector2) @JvmStatic fun dotProduct(vector1: Expr, vector2: DoubleArray) = - Function("dot_product", vector1, Constant.vector(vector2)) + FunctionExpr("dot_product", vector1, Constant.vector(vector2)) @JvmStatic - fun dotProduct(vector1: Expr, vector2: VectorValue) = Function("dot_product", vector1, vector2) + fun dotProduct(vector1: Expr, vector2: VectorValue) = FunctionExpr("dot_product", vector1, vector2) @JvmStatic - fun dotProduct(fieldName: String, vector: Expr) = Function("dot_product", fieldName, vector) + fun dotProduct(fieldName: String, vector: Expr) = FunctionExpr("dot_product", fieldName, vector) @JvmStatic fun dotProduct(fieldName: String, vector: DoubleArray) = - Function("dot_product", fieldName, Constant.vector(vector)) + FunctionExpr("dot_product", fieldName, Constant.vector(vector)) @JvmStatic fun dotProduct(fieldName: String, vector: VectorValue) = - Function("dot_product", fieldName, vector) + FunctionExpr("dot_product", fieldName, vector) @JvmStatic fun euclideanDistance(vector1: Expr, vector2: Expr) = - Function("euclidean_distance", vector1, vector2) + FunctionExpr("euclidean_distance", vector1, vector2) @JvmStatic fun euclideanDistance(vector1: Expr, vector2: DoubleArray) = - Function("euclidean_distance", vector1, Constant.vector(vector2)) + FunctionExpr("euclidean_distance", vector1, Constant.vector(vector2)) @JvmStatic fun euclideanDistance(vector1: Expr, vector2: VectorValue) = - Function("euclidean_distance", vector1, vector2) + FunctionExpr("euclidean_distance", vector1, vector2) @JvmStatic fun euclideanDistance(fieldName: String, vector: Expr) = - Function("euclidean_distance", fieldName, vector) + FunctionExpr("euclidean_distance", fieldName, vector) @JvmStatic fun euclideanDistance(fieldName: String, vector: DoubleArray) = - Function("euclidean_distance", fieldName, Constant.vector(vector)) + FunctionExpr("euclidean_distance", fieldName, Constant.vector(vector)) @JvmStatic fun euclideanDistance(fieldName: String, vector: VectorValue) = - Function("euclidean_distance", fieldName, vector) + FunctionExpr("euclidean_distance", fieldName, vector) - @JvmStatic fun vectorLength(vector: Expr) = Function("vector_length", vector) + @JvmStatic fun vectorLength(vector: Expr) = FunctionExpr("vector_length", vector) - @JvmStatic fun vectorLength(fieldName: String) = Function("vector_length", fieldName) + @JvmStatic fun vectorLength(fieldName: String) = FunctionExpr("vector_length", fieldName) - @JvmStatic fun unixMicrosToTimestamp(input: Expr) = Function("unix_micros_to_timestamp", input) + @JvmStatic fun unixMicrosToTimestamp(input: Expr) = FunctionExpr("unix_micros_to_timestamp", input) @JvmStatic - fun unixMicrosToTimestamp(fieldName: String) = Function("unix_micros_to_timestamp", fieldName) + fun unixMicrosToTimestamp(fieldName: String) = FunctionExpr("unix_micros_to_timestamp", fieldName) - @JvmStatic fun timestampToUnixMicros(input: Expr) = Function("timestamp_to_unix_micros", input) + @JvmStatic fun timestampToUnixMicros(input: Expr) = FunctionExpr("timestamp_to_unix_micros", input) @JvmStatic - fun timestampToUnixMicros(fieldName: String) = Function("timestamp_to_unix_micros", fieldName) + fun timestampToUnixMicros(fieldName: String) = FunctionExpr("timestamp_to_unix_micros", fieldName) - @JvmStatic fun unixMillisToTimestamp(input: Expr) = Function("unix_millis_to_timestamp", input) + @JvmStatic fun unixMillisToTimestamp(input: Expr) = FunctionExpr("unix_millis_to_timestamp", input) @JvmStatic - fun unixMillisToTimestamp(fieldName: String) = Function("unix_millis_to_timestamp", fieldName) + fun unixMillisToTimestamp(fieldName: String) = FunctionExpr("unix_millis_to_timestamp", fieldName) - @JvmStatic fun timestampToUnixMillis(input: Expr) = Function("timestamp_to_unix_millis", input) + @JvmStatic fun timestampToUnixMillis(input: Expr) = FunctionExpr("timestamp_to_unix_millis", input) @JvmStatic - fun timestampToUnixMillis(fieldName: String) = Function("timestamp_to_unix_millis", fieldName) + fun timestampToUnixMillis(fieldName: String) = FunctionExpr("timestamp_to_unix_millis", fieldName) @JvmStatic - fun unixSecondsToTimestamp(input: Expr) = Function("unix_seconds_to_timestamp", input) + fun unixSecondsToTimestamp(input: Expr) = FunctionExpr("unix_seconds_to_timestamp", input) @JvmStatic - fun unixSecondsToTimestamp(fieldName: String) = Function("unix_seconds_to_timestamp", fieldName) + fun unixSecondsToTimestamp(fieldName: String) = FunctionExpr("unix_seconds_to_timestamp", fieldName) @JvmStatic - fun timestampToUnixSeconds(input: Expr) = Function("timestamp_to_unix_seconds", input) + fun timestampToUnixSeconds(input: Expr) = FunctionExpr("timestamp_to_unix_seconds", input) @JvmStatic - fun timestampToUnixSeconds(fieldName: String) = Function("timestamp_to_unix_seconds", fieldName) + fun timestampToUnixSeconds(fieldName: String) = FunctionExpr("timestamp_to_unix_seconds", fieldName) @JvmStatic fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr) = - Function("timestamp_add", timestamp, unit, amount) + FunctionExpr("timestamp_add", timestamp, unit, amount) @JvmStatic fun timestampAdd(timestamp: Expr, unit: String, amount: Double) = - Function("timestamp_add", timestamp, unit, amount) + FunctionExpr("timestamp_add", timestamp, unit, amount) @JvmStatic fun timestampAdd(fieldName: String, unit: Expr, amount: Expr) = - Function("timestamp_add", fieldName, unit, amount) + FunctionExpr("timestamp_add", fieldName, unit, amount) @JvmStatic fun timestampAdd(fieldName: String, unit: String, amount: Double) = - Function("timestamp_add", fieldName, unit, amount) + FunctionExpr("timestamp_add", fieldName, unit, amount) @JvmStatic fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr) = - Function("timestamp_sub", timestamp, unit, amount) + FunctionExpr("timestamp_sub", timestamp, unit, amount) @JvmStatic fun timestampSub(timestamp: Expr, unit: String, amount: Double) = - Function("timestamp_sub", timestamp, unit, amount) + FunctionExpr("timestamp_sub", timestamp, unit, amount) @JvmStatic fun timestampSub(fieldName: String, unit: Expr, amount: Expr) = - Function("timestamp_sub", fieldName, unit, amount) + FunctionExpr("timestamp_sub", fieldName, unit, amount) @JvmStatic fun timestampSub(fieldName: String, unit: String, amount: Double) = - Function("timestamp_sub", fieldName, unit, amount) + FunctionExpr("timestamp_sub", fieldName, unit, amount) @JvmStatic fun eq(left: Expr, right: Expr) = BooleanExpr("eq", left, right) @@ -918,23 +918,23 @@ protected constructor(private val name: String, private val params: Array) = - Function("array_concat", array, ListOfExprs(toArrayOfExprOrConstant(arrays))) + FunctionExpr("array_concat", array, ListOfExprs(toArrayOfExprOrConstant(arrays))) @JvmStatic fun arrayConcat(fieldName: String, arrays: List) = - Function("array_concat", fieldName, ListOfExprs(toArrayOfExprOrConstant(arrays))) + FunctionExpr("array_concat", fieldName, ListOfExprs(toArrayOfExprOrConstant(arrays))) - @JvmStatic fun arrayReverse(array: Expr) = Function("array_reverse", array) + @JvmStatic fun arrayReverse(array: Expr) = FunctionExpr("array_reverse", array) - @JvmStatic fun arrayReverse(fieldName: String) = Function("array_reverse", fieldName) + @JvmStatic fun arrayReverse(fieldName: String) = FunctionExpr("array_reverse", fieldName) @JvmStatic fun arrayContains(array: Expr, value: Expr) = BooleanExpr("array_contains", array, value) @@ -966,17 +966,17 @@ protected constructor(private val name: String, private val params: Array) = BooleanExpr("array_contains_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) - @JvmStatic fun arrayLength(array: Expr) = Function("array_length", array) + @JvmStatic fun arrayLength(array: Expr) = FunctionExpr("array_length", array) - @JvmStatic fun arrayLength(fieldName: String) = Function("array_length", fieldName) + @JvmStatic fun arrayLength(fieldName: String) = FunctionExpr("array_length", fieldName) @JvmStatic fun cond(condition: BooleanExpr, then: Expr, otherwise: Expr) = - Function("cond", condition, then, otherwise) + FunctionExpr("cond", condition, then, otherwise) @JvmStatic fun cond(condition: BooleanExpr, then: Any, otherwise: Any) = - Function("cond", condition, then, otherwise) + FunctionExpr("cond", condition, then, otherwise) @JvmStatic fun exists(expr: Expr) = BooleanExpr("exists", expr) } @@ -992,7 +992,7 @@ protected constructor(private val name: String, private val params: Array) : - Function(name, params) { + FunctionExpr(name, params) { internal constructor( name: String, params: List @@ -1015,7 +1015,7 @@ class BooleanExpr internal constructor(name: String, params: Array) : fun not() = not(this) - fun countIf(): AggregateExpr = AggregateExpr.countIf(this) + fun countIf(): AggregateFunction = AggregateFunction.countIf(this) fun cond(then: Expr, otherwise: Expr) = cond(this, then, otherwise) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index bcae5dd66e5..d2a91c3a805 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -18,7 +18,6 @@ import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.Values.encodeValue import com.google.firebase.firestore.pipeline.Field.Companion.of -import com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value @@ -55,7 +54,7 @@ internal constructor( options: InternalOptions = InternalOptions.EMPTY ) : Stage(name, options) { companion object { - @JvmStatic fun of(name: String) = GenericStage(name, emptyList(), InternalOptions.EMPTY) + @JvmStatic fun ofName(name: String) = GenericStage(name, emptyList(), InternalOptions.EMPTY) } override fun self(options: InternalOptions) = GenericStage(name, arguments, options) @@ -71,7 +70,7 @@ internal sealed class GenericArg { companion object { fun from(arg: Any?): GenericArg = when (arg) { - is AggregateExpr -> AggregateArg(arg) + is AggregateFunction -> AggregateArg(arg) is Ordering -> OrderingArg(arg) is Map<*, *> -> MapArg(arg.asIterable().associate { (key, value) -> key as String to from(value) }) @@ -81,7 +80,7 @@ internal sealed class GenericArg { } abstract fun toProto(userDataReader: UserDataReader): Value - data class AggregateArg(val aggregate: AggregateExpr) : GenericArg() { + data class AggregateArg(val aggregate: AggregateFunction) : GenericArg() { override fun toProto(userDataReader: UserDataReader) = aggregate.toProto(userDataReader) } @@ -156,11 +155,11 @@ internal constructor( class AggregateStage internal constructor( - private val accumulators: Map, + private val accumulators: Map, private val groups: Map, options: InternalOptions = InternalOptions.EMPTY ) : Stage("aggregate", options) { - private constructor(accumulators: Map) : this(accumulators, emptyMap()) + private constructor(accumulators: Map) : this(accumulators, emptyMap()) companion object { @JvmStatic fun withAccumulators(vararg accumulators: AggregateWithAlias): AggregateStage { From 9dbce3f33c90891951a65a4f98c9de6026012b4a Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Wed, 9 Apr 2025 22:51:17 -0400 Subject: [PATCH 36/77] Fixups --- .../com/google/firebase/firestore/Pipeline.kt | 303 ++++++++++++++++-- .../firestore/pipeline/expressions.kt | 90 ++++-- .../firebase/firestore/pipeline/stage.kt | 157 +++++++-- 3 files changed, 464 insertions(+), 86 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 25496f498a9..951f0d2f3ec 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -22,6 +22,7 @@ import com.google.firebase.Timestamp import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.pipeline.AddFieldsStage +import com.google.firebase.firestore.pipeline.AggregateFunction import com.google.firebase.firestore.pipeline.AggregateStage import com.google.firebase.firestore.pipeline.AggregateWithAlias import com.google.firebase.firestore.pipeline.BooleanExpr @@ -31,8 +32,10 @@ import com.google.firebase.firestore.pipeline.DatabaseSource import com.google.firebase.firestore.pipeline.DistinctStage import com.google.firebase.firestore.pipeline.DocumentsSource import com.google.firebase.firestore.pipeline.Expr +import com.google.firebase.firestore.pipeline.ExprWithAlias import com.google.firebase.firestore.pipeline.Field import com.google.firebase.firestore.pipeline.FindNearestStage +import com.google.firebase.firestore.pipeline.FunctionExpr import com.google.firebase.firestore.pipeline.GenericArg import com.google.firebase.firestore.pipeline.GenericStage import com.google.firebase.firestore.pipeline.LimitStage @@ -103,67 +106,301 @@ internal constructor( fun genericStage(stage: GenericStage): Pipeline = append(stage) - fun addFields(vararg fields: Selectable): Pipeline = append(AddFieldsStage(fields)) + /** + * Adds new fields to outputs from previous stages. + * + * This stage allows you to compute values on-the-fly based on existing data from previous stages + * or constants. You can use this to create new fields or overwrite existing ones. + * + * The added fields are defined using [Selectable]s, which can be: + * + * - [Field]: References an existing document field. + * - [ExprWithAlias]: Represents the result of a expression with an assigned alias name + * using [Expr.alias] + * + * @param field The first field to add to the documents, specified as a [Selectable]. + * @param additionalFields The fields to add to the documents, specified as [Selectable]s. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun addFields(field: Selectable, vararg additionalFields: Selectable): Pipeline = + append(AddFieldsStage(arrayOf(field, *additionalFields))) fun removeFields(vararg fields: Field): Pipeline = append(RemoveFieldsStage(fields)) fun removeFields(vararg fields: String): Pipeline = append(RemoveFieldsStage(fields.map(Field::of).toTypedArray())) - fun select(vararg fields: Selectable): Pipeline = append(SelectStage(fields)) - - fun select(vararg fields: String): Pipeline = - append(SelectStage(fields.map(Field::of).toTypedArray())) + /** + * Selects or creates a set of fields from the outputs of previous stages. + * + * The selected fields are defined using [Selectable] expressions, which can be: + * + * - [String]: Name of an existing field + * - [Field]: Reference to an existing field. + * - [ExprWithAlias]: Represents the result of a expression with an assigned alias name + * using [Expr.alias] + * + * If no selections are provided, the output of this stage is empty. Use [Pipeline.addFields] + * instead if only additions are desired. + * + * @param selection The first field to include in the output documents, specified as a + * [Selectable] expression. + * @param additionalSelections Optional additional fields to include in the output documents, + * specified as [Selectable] expressions or string values representing field names. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun select(selection: Selectable, vararg additionalSelections: Any): Pipeline = + append( + SelectStage( + arrayOf(selection, *additionalSelections.map(Selectable::toSelectable).toTypedArray()) + ) + ) - fun select(vararg fields: Any): Pipeline = - append(SelectStage(fields.map(Selectable::toSelectable).toTypedArray())) + /** + * Selects or creates a set of fields from the outputs of previous stages. + * + * The selected fields are defined using [Selectable] expressions, which can be: + * + * - [String]: Name of an existing field + * - [Field]: Reference to an existing field. + * - [ExprWithAlias]: Represents the result of a expression with an assigned alias name + * using [Expr.alias] + * + * If no selections are provided, the output of this stage is empty. Use [Pipeline.addFields] + * instead if only additions are desired. + * + * @param fieldName The first field to include in the output documents, specified as a string + * value representing a field names. + * @param additionalSelections Optional additional fields to include in the output documents, + * specified as [Selectable] expressions or string values representing field names. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun select(fieldName: String, vararg additionalSelections: Any): Pipeline = + append( + SelectStage( + arrayOf( + Field.of(fieldName), + *additionalSelections.map(Selectable::toSelectable).toTypedArray() + ) + ) + ) fun sort(vararg orders: Ordering): Pipeline = append(SortStage(orders)) + /** + * Filters the documents from previous stages to only include those matching the specified + * [BooleanExpr]. + * + * This stage allows you to apply conditions to the data, similar to a "WHERE" clause in SQL. + * + * You can filter documents based on their field values, using implementations of + * [BooleanExpr], typically including but not limited to: + * + * - field comparators: [FunctionExpr.eq], [FunctionExpr.lt] (less than), [FunctionExpr.gt] + * (greater than), etc. + * - logical operators: [FunctionExpr.and], [FunctionExpr.or], [FunctionExpr.not], etc. + * - advanced functions: [FunctionExpr.regexMatch], [FunctionExpr.arrayContains[], etc. + * + * @param condition The [BooleanExpr] to apply. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun where(condition: BooleanExpr): Pipeline = append(WhereStage(condition)) + /** + * Skips the first `offset` number of documents from the results of previous stages. + * + * This stage is useful for implementing pagination in your pipelines, allowing you to retrieve + * results in chunks. It is typically used in conjunction with [limit] to control the size + * of each page. + * + * @param offset The number of documents to skip. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun offset(offset: Int): Pipeline = append(OffsetStage(offset)) + /** + * Limits the maximum number of documents returned by previous stages to `limit`. + * + * This stage is particularly useful when you want to retrieve a controlled subset of data + * from a potentially large result set. It's often used for: + * + * - **Pagination:** In combination with [offset] to retrieve specific pages of results. + * - **Limiting Data Retrieval:** To prevent excessive data transfer and improve performance, + * especially when dealing with large collections. + * + * @param limit The maximum number of documents to return. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun limit(limit: Int): Pipeline = append(LimitStage(limit)) - fun distinct(vararg groups: Selectable): Pipeline = append(DistinctStage(groups)) - - fun distinct(vararg groups: String): Pipeline = - append(DistinctStage(groups.map(Field::of).toTypedArray())) + /** + * Returns a set of distinct values from the inputs to this stage. + * + * This stage runs through the results from previous stages to include only results with unique + * combinations of [Expr] values [Field], [FunctionExpr], etc). + * + * The parameters to this stage are defined using [Selectable] expressions or strings: + * + * - [String]: Name of an existing field + * - [Field]: References an existing document field. + * - [ExprWithAlias]: Represents the result of a function with an assigned alias name using + * [Expr.alias] + * + * @param group The [Selectable] expression to consider when determining distinct value + * combinations. + * @param additionalGroups The [Selectable] expressions to consider when determining + * distinct value combinations or [String]s representing field names. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun distinct(group: Selectable, vararg additionalGroups: Any): Pipeline = + append( + DistinctStage(arrayOf(group, *additionalGroups.map(Selectable::toSelectable).toTypedArray())) + ) - fun distinct(vararg groups: Any): Pipeline = - append(DistinctStage(groups.map(Selectable::toSelectable).toTypedArray())) + /** + * Returns a set of distinct values from the inputs to this stage. + * + * This stage runs through the results from previous stages to include only results with unique + * combinations of [Expr] values ([Field], [FunctionExpr], etc). + * + * The parameters to this stage are defined using [Selectable] expressions or strings: + * + * - [String]: Name of an existing field + * - [Field]: References an existing document field. + * - [ExprWithAlias]: Represents the result of a function with an assigned alias name using + * [Expr.alias] + * + * @param groupField The [String] representing field name. + * @param additionalGroups The [Selectable] expressions to consider when determining + * distinct value combinations or [String]s representing field names. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun distinct(groupField: String, vararg additionalGroups: Any): Pipeline = + append( + DistinctStage( + arrayOf( + Field.of(groupField), + *additionalGroups.map(Selectable::toSelectable).toTypedArray() + ) + ) + ) - fun aggregate(vararg accumulators: AggregateWithAlias): Pipeline = - append(AggregateStage.withAccumulators(*accumulators)) + /** + * Performs aggregation operations on the documents from previous stages. + * + * This stage allows you to calculate aggregate values over a set of documents. You define the + * aggregations to perform using [AggregateWithAlias] expressions which are typically + * results of calling [AggregateFunction.alias] on [AggregateFunction] instances. + * + * @param accumulator The first [AggregateWithAlias] expression, wrapping an + * [AggregateFunction] with an alias for the accumulated results. + * @param additionalAccumulators The [AggregateWithAlias] expressions, each wrapping an + * [AggregateFunction] with an alias for the accumulated results. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun aggregate( + accumulator: AggregateWithAlias, + vararg additionalAccumulators: AggregateWithAlias + ): Pipeline = append(AggregateStage.withAccumulators(accumulator, *additionalAccumulators)) + /** + * Performs optionally grouped aggregation operations on the documents from previous stages. + * + * This stage allows you to calculate aggregate values over a set of documents, optionally grouped + * by one or more fields or functions. You can specify: + * + * - **Grouping Fields or Expressions:** One or more fields or functions to group the documents + * by. For each distinct combination of values in these fields, a separate group is created. If no + * grouping fields are provided, a single group containing all documents is used. Not specifying + * groups is the same as putting the entire inputs into one group. + * + * - **AggregateFunctions:** One or more accumulation operations to perform within each group. + * These are defined using [AggregateWithAlias] expressions, which are typically created by + * calling [AggregateFunction.alias] on [AggregateFunction] instances. Each aggregation calculates + * a value (e.g., sum, average, count) based on the documents within its group. + * + * @param aggregateStage An [AggregateStage] object that specifies the grouping fields (if any) + * and the aggregation operations to perform. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun aggregate(aggregateStage: AggregateStage): Pipeline = append(aggregateStage) + /** + * Performs a vector similarity search, ordering the result set by most similar to least + * similar, and returning the first N documents in the result set. + * + * @param vectorField A [Field] that contains vector to search on. + * @param vectorValue The [VectorValue] in array form that is used to measure the distance from + * [vectorField] values in the documents. + * @param distanceMeasure specifies what type of distance is calculated + * when performing the search. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun findNearest( - property: Expr, - vector: DoubleArray, + vectorField: Field, + vectorValue: DoubleArray, distanceMeasure: FindNearestStage.DistanceMeasure, - ) = append(FindNearestStage.of(property, vector, distanceMeasure)) + ): Pipeline = append(FindNearestStage.of(vectorField, vectorValue, distanceMeasure)) + /** + * Performs a vector similarity search, ordering the result set by most similar to least + * similar, and returning the first N documents in the result set. + * + * @param vectorField A [String] specifying the vector field to search on. + * @param vectorValue The [VectorValue] in array form that is used to measure the distance from + * [vectorField] values in the documents. + * @param distanceMeasure specifies what type of distance is calculated + * when performing the search. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun findNearest( - propertyField: String, - vector: DoubleArray, + vectorField: String, + vectorValue: DoubleArray, distanceMeasure: FindNearestStage.DistanceMeasure, - ) = append(FindNearestStage.of(propertyField, vector, distanceMeasure)) + ): Pipeline = append(FindNearestStage.of(vectorField, vectorValue, distanceMeasure)) + /** + * Performs a vector similarity search, ordering the result set by most similar to least + * similar, and returning the first N documents in the result set. + * + * @param vectorField A [Field] that contains vector to search on. + * @param vectorValue The [VectorValue] used to measure the distance from [vectorField] values in + * the documents. + * @param distanceMeasure specifies what type of distance is calculated. + * when performing the search. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun findNearest( - property: Expr, - vector: Expr, + vectorField: Field, + vectorValue: VectorValue, distanceMeasure: FindNearestStage.DistanceMeasure, - ) = append(FindNearestStage.of(property, vector, distanceMeasure)) + ): Pipeline = append(FindNearestStage.of(vectorField, vectorValue, distanceMeasure)) + /** + * Performs a vector similarity search, ordering the result set by most similar to least + * similar, and returning the first N documents in the result set. + * + * @param vectorField A [String] specifying the vector field to search on. + * @param vectorValue The [VectorValue] used to measure the distance from [vectorField] values in + * the documents. + * @param distanceMeasure specifies what type of distance is calculated + * when performing the search. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun findNearest( - propertyField: String, - vector: Expr, + vectorField: String, + vectorValue: VectorValue, distanceMeasure: FindNearestStage.DistanceMeasure, - ) = append(FindNearestStage.of(propertyField, vector, distanceMeasure)) + ): Pipeline = append(FindNearestStage.of(vectorField, vectorValue, distanceMeasure)) - fun findNearest(stage: FindNearestStage) = append(stage) + /** + * Performs a vector similarity search, ordering the result set by most similar to least + * similar, and returning the first N documents in the result set. + * + * @param stage An [FindNearestStage] object that specifies the search parameters. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun findNearest(stage: FindNearestStage): Pipeline = append(stage) fun replace(field: String): Pipeline = replace(Field.of(field)) @@ -244,13 +481,17 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto * @throws [IllegalArgumentException] Thrown if the [aggregateQuery] provided targets a different * project or database than the pipeline. */ - fun createFrom(aggregateQuery: AggregateQuery): Pipeline = - createFrom(aggregateQuery.query) + fun createFrom(aggregateQuery: AggregateQuery): Pipeline { + val aggregateFields = aggregateQuery.aggregateFields + return createFrom(aggregateQuery.query) .aggregate( - *aggregateQuery.aggregateFields + aggregateFields.first().toPipeline(), + *aggregateFields + .drop(1) .map(AggregateField::toPipeline) .toTypedArray() ) + } /** * Set the pipeline's source to the collection specified by the given path. diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 12e7439d745..c8e4de0a3ff 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -342,6 +342,7 @@ abstract class Expr internal constructor() { abstract class Selectable : Expr() { internal abstract fun getAlias(): String + internal abstract fun getExpr(): Expr internal companion object { fun toSelectable(o: Any): Selectable { @@ -358,6 +359,7 @@ abstract class Selectable : Expr() { class ExprWithAlias internal constructor(private val alias: String, private val expr: Expr) : Selectable() { override fun getAlias() = alias + override fun getExpr() = expr override fun toProto(userDataReader: UserDataReader): Value = expr.toProto(userDataReader) } @@ -380,6 +382,7 @@ class Field internal constructor(private val fieldPath: ModelFieldPath) : Select } override fun getAlias(): String = fieldPath.canonicalString() + override fun getExpr(): Expr = this override fun toProto(userDataReader: UserDataReader) = toProto() @@ -426,7 +429,8 @@ protected constructor(private val name: String, private val params: Array) = FunctionExpr("map", elements) @@ -727,14 +744,18 @@ protected constructor(private val name: String, private val params: Array, @@ -161,29 +179,53 @@ internal constructor( ) : Stage("aggregate", options) { private constructor(accumulators: Map) : this(accumulators, emptyMap()) companion object { + + /** + * Create [AggregateStage] with one or more accumulators. + * + * @param accumulator The first [AggregateWithAlias] expression, wrapping an {@link + * AggregateFunction} with an alias for the accumulated results. + * @param additionalAccumulators The [AggregateWithAlias] expressions, each wrapping an + * [AggregateFunction] with an alias for the accumulated results. + * @return Aggregate Stage with specified accumulators. + */ @JvmStatic - fun withAccumulators(vararg accumulators: AggregateWithAlias): AggregateStage { - if (accumulators.isEmpty()) { - throw IllegalArgumentException( - "Must specify at least one accumulator for aggregate() stage. There is a distinct() stage if only distinct group values are needed." - ) - } - return AggregateStage(accumulators.associate { it.alias to it.expr }) + fun withAccumulators( + accumulator: AggregateWithAlias, + vararg additionalAccumulators: AggregateWithAlias + ): AggregateStage { + return AggregateStage( + mapOf(accumulator.alias to accumulator.expr) + .plus(additionalAccumulators.associate { it.alias to it.expr }) + ) } } override fun self(options: InternalOptions) = AggregateStage(accumulators, groups, options) - fun withGroups(vararg groups: Selectable) = - AggregateStage(accumulators, groups.associateBy(Selectable::getAlias)) - - fun withGroups(vararg fields: String) = - AggregateStage(accumulators, fields.associateWith(Field::of)) - - fun withGroups(vararg selectable: Any) = + /** + * Add one or more groups to [AggregateStage] + * + * @param groupField The [String] representing field name. + * @param additionalGroups The [Selectable] expressions to consider when determining + * group value combinations or [String]s representing field names. + * @return Aggregate Stage with specified groups. + */ + fun withGroups(groupField: String, vararg additionalGroups: Any) = withGroups(Field.of(groupField), additionalGroups) + + /** + * Add one or more groups to [AggregateStage] + * + * @param groupField The [Selectable] expression to consider when determining group value + * combinations. + * @param additionalGroups The [Selectable] expressions to consider when determining + * group value combinations or [String]s representing field names. + * @return Aggregate Stage with specified groups. + */ + fun withGroups(group: Selectable, vararg additionalGroups: Any) = AggregateStage( accumulators, - selectable.map(Selectable::toSelectable).associateBy(Selectable::getAlias) + mapOf(group.getAlias() to group.getExpr()).plus(additionalGroups.map(Selectable::toSelectable).associateBy(Selectable::getAlias)) ) override fun args(userDataReader: UserDataReader): Sequence = @@ -203,6 +245,10 @@ internal constructor( sequenceOf(condition.toProto(userDataReader)) } +/** + * Performs a vector similarity search, ordering the result set by most similar to least + * similar, and returning the first N documents in the result set. + */ class FindNearestStage internal constructor( private val property: Expr, @@ -212,21 +258,62 @@ internal constructor( ) : Stage("find_nearest", options) { companion object { - @JvmStatic - fun of(property: Expr, vector: Expr, distanceMeasure: DistanceMeasure) = - FindNearestStage(property, vector, distanceMeasure) + /** + * Create [FindNearestStage]. + * + * @param vectorField A [Field] that contains vector to search on. + * @param vectorValue The [VectorValue] used to measure the distance from [vectorField] values + * in the documents. + * @param distanceMeasure specifies what type of distance is calculated. + * when performing the search. + * @return [FindNearestStage] with specified parameters. + */ @JvmStatic - fun of(property: Expr, vector: DoubleArray, distanceMeasure: DistanceMeasure) = - FindNearestStage(property, Constant.vector(vector), distanceMeasure) - + fun of(vectorField: Field, vectorValue: VectorValue, distanceMeasure: DistanceMeasure) = + FindNearestStage(vectorField, Constant.of(vectorValue), distanceMeasure) + + /** + * Create [FindNearestStage]. + * + * @param vectorField A [Field] that contains vector to search on. + * @param vectorValue The [VectorValue] in array form that is used to measure the distance from + * [vectorField] values in the documents. + * @param distanceMeasure specifies what type of distance is calculated + * when performing the search. + * @return [FindNearestStage] with specified parameters. + */ @JvmStatic - fun of(fieldName: String, vector: Expr, distanceMeasure: DistanceMeasure) = - FindNearestStage(Constant.of(fieldName), vector, distanceMeasure) - + fun of(vectorField: Field, vectorValue: DoubleArray, distanceMeasure: DistanceMeasure) = + FindNearestStage(vectorField, Constant.vector(vectorValue), distanceMeasure) + + /** + * Create [FindNearestStage]. + * + * @param vectorField A [String] specifying the vector field to search on. + * @param vectorValue The [VectorValue] used to measure the distance from [vectorField] values + * in the documents. + * @param distanceMeasure specifies what type of distance is calculated + * when performing the search. + * @return [FindNearestStage] with specified parameters. + */ + @JvmStatic + fun of(vectorField: String, vectorValue: VectorValue, distanceMeasure: DistanceMeasure) = + FindNearestStage(Constant.of(vectorField), Constant.of(vectorValue), distanceMeasure) + + /** + * Create [FindNearestStage]. + * + * @param vectorField A [String] specifying the vector field to search on. + * @param vectorValue The [VectorValue] in array form that is used to measure the distance from + * [vectorField] values in the documents. + * @param distanceMeasure specifies what type of distance is calculated + * when performing the search. + * @return [FindNearestStage] with specified parameters. + */ @JvmStatic - fun of(fieldName: String, vector: DoubleArray, distanceMeasure: DistanceMeasure) = - FindNearestStage(Constant.of(fieldName), Constant.vector(vector), distanceMeasure) + fun of(vectorField: String, vectorValue: DoubleArray, distanceMeasure: DistanceMeasure) = + FindNearestStage(Constant.of(vectorField), Constant.vector(vectorValue), distanceMeasure) } class DistanceMeasure private constructor(internal val proto: Value) { @@ -251,11 +338,29 @@ internal constructor( distanceMeasure.proto ) + /** + * Specifies the upper bound of documents to return. + * + * @param limit must be a positive integer. + * @return [FindNearestStage] with specified [limit]. + */ fun withLimit(limit: Long): FindNearestStage = with("limit", limit) + /** + * Add a field containing the distance to the result. + * + * @param distanceField The [Field] that will be added to the result. + * @return [FindNearestStage] with specified [distanceField]. + */ fun withDistanceField(distanceField: Field): FindNearestStage = with("distance_field", distanceField) + /** + * Add a field containing the distance to the result. + * + * @param distanceField The name of the field that will be added to the result. + * @return [FindNearestStage] with specified [distanceField]. + */ fun withDistanceField(distanceField: String): FindNearestStage = withDistanceField(of(distanceField)) } From 51883b9443cce246425faffd57d33a9bfe7158e6 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Wed, 9 Apr 2025 22:54:31 -0400 Subject: [PATCH 37/77] Comments word wrap --- .../com/google/firebase/firestore/Pipeline.kt | 81 +++++++++---------- .../firebase/firestore/pipeline/stage.kt | 47 +++++------ 2 files changed, 63 insertions(+), 65 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 951f0d2f3ec..8f30947e50c 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -115,8 +115,8 @@ internal constructor( * The added fields are defined using [Selectable]s, which can be: * * - [Field]: References an existing document field. - * - [ExprWithAlias]: Represents the result of a expression with an assigned alias name - * using [Expr.alias] + * - [ExprWithAlias]: Represents the result of a expression with an assigned alias name using + * [Expr.alias] * * @param field The first field to add to the documents, specified as a [Selectable]. * @param additionalFields The fields to add to the documents, specified as [Selectable]s. @@ -137,8 +137,8 @@ internal constructor( * * - [String]: Name of an existing field * - [Field]: Reference to an existing field. - * - [ExprWithAlias]: Represents the result of a expression with an assigned alias name - * using [Expr.alias] + * - [ExprWithAlias]: Represents the result of a expression with an assigned alias name using + * [Expr.alias] * * If no selections are provided, the output of this stage is empty. Use [Pipeline.addFields] * instead if only additions are desired. @@ -163,8 +163,8 @@ internal constructor( * * - [String]: Name of an existing field * - [Field]: Reference to an existing field. - * - [ExprWithAlias]: Represents the result of a expression with an assigned alias name - * using [Expr.alias] + * - [ExprWithAlias]: Represents the result of a expression with an assigned alias name using + * [Expr.alias] * * If no selections are provided, the output of this stage is empty. Use [Pipeline.addFields] * instead if only additions are desired. @@ -193,8 +193,8 @@ internal constructor( * * This stage allows you to apply conditions to the data, similar to a "WHERE" clause in SQL. * - * You can filter documents based on their field values, using implementations of - * [BooleanExpr], typically including but not limited to: + * You can filter documents based on their field values, using implementations of [BooleanExpr], + * typically including but not limited to: * * - field comparators: [FunctionExpr.eq], [FunctionExpr.lt] (less than), [FunctionExpr.gt] * (greater than), etc. @@ -210,8 +210,8 @@ internal constructor( * Skips the first `offset` number of documents from the results of previous stages. * * This stage is useful for implementing pagination in your pipelines, allowing you to retrieve - * results in chunks. It is typically used in conjunction with [limit] to control the size - * of each page. + * results in chunks. It is typically used in conjunction with [limit] to control the size of each + * page. * * @param offset The number of documents to skip. * @return A new [Pipeline] object with this stage appended to the stage list. @@ -221,8 +221,8 @@ internal constructor( /** * Limits the maximum number of documents returned by previous stages to `limit`. * - * This stage is particularly useful when you want to retrieve a controlled subset of data - * from a potentially large result set. It's often used for: + * This stage is particularly useful when you want to retrieve a controlled subset of data from a + * potentially large result set. It's often used for: * * - **Pagination:** In combination with [offset] to retrieve specific pages of results. * - **Limiting Data Retrieval:** To prevent excessive data transfer and improve performance, @@ -248,8 +248,8 @@ internal constructor( * * @param group The [Selectable] expression to consider when determining distinct value * combinations. - * @param additionalGroups The [Selectable] expressions to consider when determining - * distinct value combinations or [String]s representing field names. + * @param additionalGroups The [Selectable] expressions to consider when determining distinct + * value combinations or [String]s representing field names. * @return A new [Pipeline] object with this stage appended to the stage list. */ fun distinct(group: Selectable, vararg additionalGroups: Any): Pipeline = @@ -271,8 +271,8 @@ internal constructor( * [Expr.alias] * * @param groupField The [String] representing field name. - * @param additionalGroups The [Selectable] expressions to consider when determining - * distinct value combinations or [String]s representing field names. + * @param additionalGroups The [Selectable] expressions to consider when determining distinct + * value combinations or [String]s representing field names. * @return A new [Pipeline] object with this stage appended to the stage list. */ fun distinct(groupField: String, vararg additionalGroups: Any): Pipeline = @@ -289,11 +289,11 @@ internal constructor( * Performs aggregation operations on the documents from previous stages. * * This stage allows you to calculate aggregate values over a set of documents. You define the - * aggregations to perform using [AggregateWithAlias] expressions which are typically - * results of calling [AggregateFunction.alias] on [AggregateFunction] instances. + * aggregations to perform using [AggregateWithAlias] expressions which are typically results of + * calling [AggregateFunction.alias] on [AggregateFunction] instances. * - * @param accumulator The first [AggregateWithAlias] expression, wrapping an - * [AggregateFunction] with an alias for the accumulated results. + * @param accumulator The first [AggregateWithAlias] expression, wrapping an [AggregateFunction] + * with an alias for the accumulated results. * @param additionalAccumulators The [AggregateWithAlias] expressions, each wrapping an * [AggregateFunction] with an alias for the accumulated results. * @return A new [Pipeline] object with this stage appended to the stage list. @@ -326,14 +326,14 @@ internal constructor( fun aggregate(aggregateStage: AggregateStage): Pipeline = append(aggregateStage) /** - * Performs a vector similarity search, ordering the result set by most similar to least - * similar, and returning the first N documents in the result set. + * Performs a vector similarity search, ordering the result set by most similar to least similar, + * and returning the first N documents in the result set. * * @param vectorField A [Field] that contains vector to search on. * @param vectorValue The [VectorValue] in array form that is used to measure the distance from * [vectorField] values in the documents. - * @param distanceMeasure specifies what type of distance is calculated - * when performing the search. + * @param distanceMeasure specifies what type of distance is calculated when performing the + * search. * @return A new [Pipeline] object with this stage appended to the stage list. */ fun findNearest( @@ -343,14 +343,14 @@ internal constructor( ): Pipeline = append(FindNearestStage.of(vectorField, vectorValue, distanceMeasure)) /** - * Performs a vector similarity search, ordering the result set by most similar to least - * similar, and returning the first N documents in the result set. + * Performs a vector similarity search, ordering the result set by most similar to least similar, + * and returning the first N documents in the result set. * * @param vectorField A [String] specifying the vector field to search on. * @param vectorValue The [VectorValue] in array form that is used to measure the distance from * [vectorField] values in the documents. - * @param distanceMeasure specifies what type of distance is calculated - * when performing the search. + * @param distanceMeasure specifies what type of distance is calculated when performing the + * search. * @return A new [Pipeline] object with this stage appended to the stage list. */ fun findNearest( @@ -360,14 +360,14 @@ internal constructor( ): Pipeline = append(FindNearestStage.of(vectorField, vectorValue, distanceMeasure)) /** - * Performs a vector similarity search, ordering the result set by most similar to least - * similar, and returning the first N documents in the result set. + * Performs a vector similarity search, ordering the result set by most similar to least similar, + * and returning the first N documents in the result set. * * @param vectorField A [Field] that contains vector to search on. * @param vectorValue The [VectorValue] used to measure the distance from [vectorField] values in * the documents. - * @param distanceMeasure specifies what type of distance is calculated. - * when performing the search. + * @param distanceMeasure specifies what type of distance is calculated. when performing the + * search. * @return A new [Pipeline] object with this stage appended to the stage list. */ fun findNearest( @@ -377,14 +377,14 @@ internal constructor( ): Pipeline = append(FindNearestStage.of(vectorField, vectorValue, distanceMeasure)) /** - * Performs a vector similarity search, ordering the result set by most similar to least - * similar, and returning the first N documents in the result set. + * Performs a vector similarity search, ordering the result set by most similar to least similar, + * and returning the first N documents in the result set. * * @param vectorField A [String] specifying the vector field to search on. * @param vectorValue The [VectorValue] used to measure the distance from [vectorField] values in * the documents. - * @param distanceMeasure specifies what type of distance is calculated - * when performing the search. + * @param distanceMeasure specifies what type of distance is calculated when performing the + * search. * @return A new [Pipeline] object with this stage appended to the stage list. */ fun findNearest( @@ -394,8 +394,8 @@ internal constructor( ): Pipeline = append(FindNearestStage.of(vectorField, vectorValue, distanceMeasure)) /** - * Performs a vector similarity search, ordering the result set by most similar to least - * similar, and returning the first N documents in the result set. + * Performs a vector similarity search, ordering the result set by most similar to least similar, + * and returning the first N documents in the result set. * * @param stage An [FindNearestStage] object that specifies the search parameters. * @return A new [Pipeline] object with this stage appended to the stage list. @@ -486,10 +486,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto return createFrom(aggregateQuery.query) .aggregate( aggregateFields.first().toPipeline(), - *aggregateFields - .drop(1) - .map(AggregateField::toPipeline) - .toTypedArray() + *aggregateFields.drop(1).map(AggregateField::toPipeline).toTypedArray() ) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index f6a0ea2b5e8..2083ecc0837 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -160,16 +160,15 @@ internal constructor( * This stage allows you to calculate aggregate values over a set of documents, optionally grouped * by one or more fields or functions. You can specify: * - * - **Grouping Fields or Expressions:** One or more fields or functions to group the documents - * by. For each distinct combination of values in these fields, a separate group is created. If no + * - **Grouping Fields or Expressions:** One or more fields or functions to group the documents by. + * For each distinct combination of values in these fields, a separate group is created. If no * grouping fields are provided, a single group containing all documents is used. Not specifying * groups is the same as putting the entire inputs into one group. * - * - **AggregateFunctions:** One or more accumulation operations to perform within each group. - * These are defined using [AggregateWithAlias] expressions, which are typically created by - * calling [AggregateFunction.alias] on [AggregateFunction] instances. Each aggregation calculates - * a value (e.g., sum, average, count) based on the documents within its - * group. + * - **AggregateFunctions:** One or more accumulation operations to perform within each group. These + * are defined using [AggregateWithAlias] expressions, which are typically created by calling + * [AggregateFunction.alias] on [AggregateFunction] instances. Each aggregation calculates a value + * (e.g., sum, average, count) based on the documents within its group. */ class AggregateStage internal constructor( @@ -207,25 +206,27 @@ internal constructor( * Add one or more groups to [AggregateStage] * * @param groupField The [String] representing field name. - * @param additionalGroups The [Selectable] expressions to consider when determining - * group value combinations or [String]s representing field names. + * @param additionalGroups The [Selectable] expressions to consider when determining group value + * combinations or [String]s representing field names. * @return Aggregate Stage with specified groups. */ - fun withGroups(groupField: String, vararg additionalGroups: Any) = withGroups(Field.of(groupField), additionalGroups) + fun withGroups(groupField: String, vararg additionalGroups: Any) = + withGroups(Field.of(groupField), additionalGroups) /** * Add one or more groups to [AggregateStage] * * @param groupField The [Selectable] expression to consider when determining group value * combinations. - * @param additionalGroups The [Selectable] expressions to consider when determining - * group value combinations or [String]s representing field names. + * @param additionalGroups The [Selectable] expressions to consider when determining group value + * combinations or [String]s representing field names. * @return Aggregate Stage with specified groups. */ fun withGroups(group: Selectable, vararg additionalGroups: Any) = AggregateStage( accumulators, - mapOf(group.getAlias() to group.getExpr()).plus(additionalGroups.map(Selectable::toSelectable).associateBy(Selectable::getAlias)) + mapOf(group.getAlias() to group.getExpr()) + .plus(additionalGroups.map(Selectable::toSelectable).associateBy(Selectable::getAlias)) ) override fun args(userDataReader: UserDataReader): Sequence = @@ -246,8 +247,8 @@ internal constructor( } /** - * Performs a vector similarity search, ordering the result set by most similar to least - * similar, and returning the first N documents in the result set. + * Performs a vector similarity search, ordering the result set by most similar to least similar, + * and returning the first N documents in the result set. */ class FindNearestStage internal constructor( @@ -265,8 +266,8 @@ internal constructor( * @param vectorField A [Field] that contains vector to search on. * @param vectorValue The [VectorValue] used to measure the distance from [vectorField] values * in the documents. - * @param distanceMeasure specifies what type of distance is calculated. - * when performing the search. + * @param distanceMeasure specifies what type of distance is calculated. when performing the + * search. * @return [FindNearestStage] with specified parameters. */ @JvmStatic @@ -279,8 +280,8 @@ internal constructor( * @param vectorField A [Field] that contains vector to search on. * @param vectorValue The [VectorValue] in array form that is used to measure the distance from * [vectorField] values in the documents. - * @param distanceMeasure specifies what type of distance is calculated - * when performing the search. + * @param distanceMeasure specifies what type of distance is calculated when performing the + * search. * @return [FindNearestStage] with specified parameters. */ @JvmStatic @@ -293,8 +294,8 @@ internal constructor( * @param vectorField A [String] specifying the vector field to search on. * @param vectorValue The [VectorValue] used to measure the distance from [vectorField] values * in the documents. - * @param distanceMeasure specifies what type of distance is calculated - * when performing the search. + * @param distanceMeasure specifies what type of distance is calculated when performing the + * search. * @return [FindNearestStage] with specified parameters. */ @JvmStatic @@ -307,8 +308,8 @@ internal constructor( * @param vectorField A [String] specifying the vector field to search on. * @param vectorValue The [VectorValue] in array form that is used to measure the distance from * [vectorField] values in the documents. - * @param distanceMeasure specifies what type of distance is calculated - * when performing the search. + * @param distanceMeasure specifies what type of distance is calculated when performing the + * search. * @return [FindNearestStage] with specified parameters. */ @JvmStatic From daab5a54db961ea592ced2ece812bb403306deb2 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 10 Apr 2025 19:00:28 -0400 Subject: [PATCH 38/77] Comments and alignment across SDKs --- .../firestore/QueryToPipelineTest.java | 101 ++++++----- .../com/google/firebase/firestore/Pipeline.kt | 171 ++++++++++++++++-- .../firebase/firestore/pipeline/Constant.kt | 84 ++++++++- .../firebase/firestore/pipeline/aggregates.kt | 8 + .../firestore/pipeline/expressions.kt | 110 ++++++++++- .../firebase/firestore/pipeline/stage.kt | 142 ++++++++++++++- 6 files changed, 536 insertions(+), 80 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java index 188b047f739..4bf391df465 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java @@ -68,7 +68,7 @@ public void testLimitQueries() { Query query = collection.limit(2); FirebaseFirestore db = collection.firestore; - PipelineSnapshot set = waitFor(db.pipeline().createFrom(query).execute()); + PipelineSnapshot set = waitFor(db.pipeline().convertFrom(query).execute()); List> data = pipelineSnapshotToValues(set); assertEquals(asList(map("k", "a"), map("k", "b")), data); } @@ -85,7 +85,7 @@ public void testLimitQueriesUsingDescendingSortOrder() { Query query = collection.limit(2).orderBy("sort", Direction.DESCENDING); FirebaseFirestore db = collection.firestore; - PipelineSnapshot set = waitFor(db.pipeline().createFrom(query).execute()); + PipelineSnapshot set = waitFor(db.pipeline().convertFrom(query).execute()); List> data = pipelineSnapshotToValues(set); assertEquals(asList(map("k", "d", "sort", 2L), map("k", "c", "sort", 1L)), data); @@ -98,7 +98,7 @@ public void testLimitToLastMustAlsoHaveExplicitOrderBy() { Query query = collection.limitToLast(2); expectError( - () -> waitFor(db.pipeline().createFrom(query).execute()), + () -> waitFor(db.pipeline().convertFrom(query).execute()), "limitToLast() queries require specifying at least one orderBy() clause"); } @@ -115,33 +115,33 @@ public void testLimitToLastQueriesWithCursors() { Query query = collection.limitToLast(3).orderBy("sort").endBefore(2); FirebaseFirestore db = collection.firestore; - PipelineSnapshot set = waitFor(db.pipeline().createFrom(query).execute()); + PipelineSnapshot set = waitFor(db.pipeline().convertFrom(query).execute()); List> data = pipelineSnapshotToValues(set); assertEquals( asList(map("k", "a", "sort", 0L), map("k", "b", "sort", 1L), map("k", "c", "sort", 1L)), data); query = collection.limitToLast(3).orderBy("sort").endAt(1); - set = waitFor(db.pipeline().createFrom(query).execute()); + set = waitFor(db.pipeline().convertFrom(query).execute()); data = pipelineSnapshotToValues(set); assertEquals( asList(map("k", "a", "sort", 0L), map("k", "b", "sort", 1L), map("k", "c", "sort", 1L)), data); query = collection.limitToLast(3).orderBy("sort").startAt(2); - set = waitFor(db.pipeline().createFrom(query).execute()); + set = waitFor(db.pipeline().convertFrom(query).execute()); data = pipelineSnapshotToValues(set); assertEquals(asList(map("k", "d", "sort", 2L)), data); query = collection.limitToLast(3).orderBy("sort").startAfter(0); - set = waitFor(db.pipeline().createFrom(query).execute()); + set = waitFor(db.pipeline().convertFrom(query).execute()); data = pipelineSnapshotToValues(set); assertEquals( asList(map("k", "b", "sort", 1L), map("k", "c", "sort", 1L), map("k", "d", "sort", 2L)), data); query = collection.limitToLast(3).orderBy("sort").startAfter(-1); - set = waitFor(db.pipeline().createFrom(query).execute()); + set = waitFor(db.pipeline().convertFrom(query).execute()); data = pipelineSnapshotToValues(set); assertEquals( asList(map("k", "b", "sort", 1L), map("k", "c", "sort", 1L), map("k", "d", "sort", 2L)), @@ -163,7 +163,7 @@ public void testKeyOrderIsDescendingForDescendingInequality() { Query query = collection.whereGreaterThan("foo", 21.0).orderBy("foo", Direction.DESCENDING); FirebaseFirestore db = collection.firestore; - PipelineSnapshot result = waitFor(db.pipeline().createFrom(query).execute()); + PipelineSnapshot result = waitFor(db.pipeline().convertFrom(query).execute()); assertEquals(asList("g", "f", "c", "b", "a"), pipelineSnapshotToIds(result)); } @@ -179,7 +179,7 @@ public void testUnaryFilterQueries() { PipelineSnapshot results = waitFor( db.pipeline() - .createFrom(collection.whereEqualTo("null", null).whereEqualTo("nan", Double.NaN)) + .convertFrom(collection.whereEqualTo("null", null).whereEqualTo("nan", Double.NaN)) .execute()); assertEquals(1, results.getResults().size()); PipelineResult result = results.getResults().get(0); @@ -199,7 +199,7 @@ public void testFilterOnInfinity() { PipelineSnapshot results = waitFor( db.pipeline() - .createFrom(collection.whereEqualTo("inf", Double.POSITIVE_INFINITY)) + .convertFrom(collection.whereEqualTo("inf", Double.POSITIVE_INFINITY)) .execute()); assertEquals(1, results.getResults().size()); assertEquals(asList(map("inf", Double.POSITIVE_INFINITY)), pipelineSnapshotToValues(results)); @@ -217,7 +217,7 @@ public void testCanExplicitlySortByDocumentId() { // Ideally this would be descending to validate it's different than // the default, but that requires an extra index PipelineSnapshot docs = - waitFor(db.pipeline().createFrom(collection.orderBy(FieldPath.documentId())).execute()); + waitFor(db.pipeline().convertFrom(collection.orderBy(FieldPath.documentId())).execute()); assertEquals( asList(testDocs.get("a"), testDocs.get("b"), testDocs.get("c")), pipelineSnapshotToValues(docs)); @@ -236,14 +236,14 @@ public void testCanQueryByDocumentId() { PipelineSnapshot docs = waitFor( db.pipeline() - .createFrom(collection.whereEqualTo(FieldPath.documentId(), "ab")) + .convertFrom(collection.whereEqualTo(FieldPath.documentId(), "ab")) .execute()); assertEquals(singletonList(testDocs.get("ab")), pipelineSnapshotToValues(docs)); docs = waitFor( db.pipeline() - .createFrom( + .convertFrom( collection .whereGreaterThan(FieldPath.documentId(), "aa") .whereLessThanOrEqualTo(FieldPath.documentId(), "ba")) @@ -264,7 +264,7 @@ public void testCanQueryByDocumentIdUsingRefs() { PipelineSnapshot docs = waitFor( db.pipeline() - .createFrom( + .convertFrom( collection.whereEqualTo(FieldPath.documentId(), collection.document("ab"))) .execute()); assertEquals(singletonList(testDocs.get("ab")), pipelineSnapshotToValues(docs)); @@ -272,7 +272,7 @@ public void testCanQueryByDocumentIdUsingRefs() { docs = waitFor( db.pipeline() - .createFrom( + .convertFrom( collection .whereGreaterThan(FieldPath.documentId(), collection.document("aa")) .whereLessThanOrEqualTo(FieldPath.documentId(), collection.document("ba"))) @@ -287,9 +287,9 @@ public void testCanQueryWithAndWithoutDocumentKey() { collection.add(map()); Task query1 = db.pipeline() - .createFrom(collection.orderBy(FieldPath.documentId(), Direction.ASCENDING)) + .convertFrom(collection.orderBy(FieldPath.documentId(), Direction.ASCENDING)) .execute(); - Task query2 = db.pipeline().createFrom(collection).execute(); + Task query2 = db.pipeline().convertFrom(collection).execute(); waitFor(query1); waitFor(query2); @@ -327,7 +327,7 @@ public void testQueriesCanUseNotEqualFilters() { expectedDocsMap.remove("j"); PipelineSnapshot snapshot = - waitFor(db.pipeline().createFrom(collection.whereNotEqualTo("zip", 98101L)).execute()); + waitFor(db.pipeline().convertFrom(collection.whereNotEqualTo("zip", 98101L)).execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); // With objects. @@ -338,7 +338,7 @@ public void testQueriesCanUseNotEqualFilters() { snapshot = waitFor( db.pipeline() - .createFrom(collection.whereNotEqualTo("zip", map("code", 500))) + .convertFrom(collection.whereNotEqualTo("zip", map("code", 500))) .execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); @@ -346,7 +346,8 @@ public void testQueriesCanUseNotEqualFilters() { expectedDocsMap = new LinkedHashMap<>(allDocs); expectedDocsMap.remove("i"); expectedDocsMap.remove("j"); - snapshot = waitFor(db.pipeline().createFrom(collection.whereNotEqualTo("zip", null)).execute()); + snapshot = + waitFor(db.pipeline().convertFrom(collection.whereNotEqualTo("zip", null)).execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); // With NaN. @@ -355,7 +356,7 @@ public void testQueriesCanUseNotEqualFilters() { expectedDocsMap.remove("i"); expectedDocsMap.remove("j"); snapshot = - waitFor(db.pipeline().createFrom(collection.whereEqualTo("zip", Double.NaN)).execute()); + waitFor(db.pipeline().convertFrom(collection.whereEqualTo("zip", Double.NaN)).execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); } @@ -376,7 +377,7 @@ public void testQueriesCanUseNotEqualFiltersWithDocIds() { PipelineSnapshot docs = waitFor( db.pipeline() - .createFrom(collection.whereNotEqualTo(FieldPath.documentId(), "aa")) + .convertFrom(collection.whereNotEqualTo(FieldPath.documentId(), "aa")) .execute()); assertEquals(asList(docB, docC, docD), pipelineSnapshotToValues(docs)); } @@ -396,14 +397,16 @@ public void testQueriesCanUseArrayContainsFilters() { // Search for "array" to contain 42 PipelineSnapshot snapshot = - waitFor(db.pipeline().createFrom(collection.whereArrayContains("array", 42L)).execute()); + waitFor(db.pipeline().convertFrom(collection.whereArrayContains("array", 42L)).execute()); assertEquals(asList(docA, docB, docD), pipelineSnapshotToValues(snapshot)); // Note: whereArrayContains() requires a non-null value parameter, so no null test is needed. // With NaN. snapshot = waitFor( - db.pipeline().createFrom(collection.whereArrayContains("array", Double.NaN)).execute()); + db.pipeline() + .convertFrom(collection.whereArrayContains("array", Double.NaN)) + .execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); } @@ -430,7 +433,7 @@ public void testQueriesCanUseInFilters() { PipelineSnapshot snapshot = waitFor( db.pipeline() - .createFrom( + .convertFrom( collection.whereIn("zip", asList(98101L, 98103L, asList(98101L, 98102L)))) .execute()); assertEquals(asList(docA, docC, docG), pipelineSnapshotToValues(snapshot)); @@ -439,30 +442,30 @@ public void testQueriesCanUseInFilters() { snapshot = waitFor( db.pipeline() - .createFrom(collection.whereIn("zip", asList(map("code", 500L)))) + .convertFrom(collection.whereIn("zip", asList(map("code", 500L)))) .execute()); assertEquals(asList(docF), pipelineSnapshotToValues(snapshot)); // With null. - snapshot = waitFor(db.pipeline().createFrom(collection.whereIn("zip", nullList())).execute()); + snapshot = waitFor(db.pipeline().convertFrom(collection.whereIn("zip", nullList())).execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With null and a value. List inputList = nullList(); inputList.add(98101L); - snapshot = waitFor(db.pipeline().createFrom(collection.whereIn("zip", inputList)).execute()); + snapshot = waitFor(db.pipeline().convertFrom(collection.whereIn("zip", inputList)).execute()); assertEquals(asList(docA), pipelineSnapshotToValues(snapshot)); // With NaN. snapshot = - waitFor(db.pipeline().createFrom(collection.whereIn("zip", asList(Double.NaN))).execute()); + waitFor(db.pipeline().convertFrom(collection.whereIn("zip", asList(Double.NaN))).execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With NaN and a value. snapshot = waitFor( db.pipeline() - .createFrom(collection.whereIn("zip", asList(Double.NaN, 98101L))) + .convertFrom(collection.whereIn("zip", asList(Double.NaN, 98101L))) .execute()); assertEquals(asList(docA), pipelineSnapshotToValues(snapshot)); } @@ -484,7 +487,7 @@ public void testQueriesCanUseInFiltersWithDocIds() { PipelineSnapshot docs = waitFor( db.pipeline() - .createFrom(collection.whereIn(FieldPath.documentId(), asList("aa", "ab"))) + .convertFrom(collection.whereIn(FieldPath.documentId(), asList("aa", "ab"))) .execute()); assertEquals(asList(docA, docB), pipelineSnapshotToValues(docs)); } @@ -522,7 +525,7 @@ public void testQueriesCanUseNotInFilters() { PipelineSnapshot snapshot = waitFor( db.pipeline() - .createFrom( + .convertFrom( collection.whereNotIn("zip", asList(98101L, 98103L, asList(98101L, 98102L)))) .execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); @@ -535,13 +538,13 @@ public void testQueriesCanUseNotInFilters() { snapshot = waitFor( db.pipeline() - .createFrom(collection.whereNotIn("zip", asList(map("code", 500L)))) + .convertFrom(collection.whereNotIn("zip", asList(map("code", 500L)))) .execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); // With Null. snapshot = - waitFor(db.pipeline().createFrom(collection.whereNotIn("zip", nullList())).execute()); + waitFor(db.pipeline().convertFrom(collection.whereNotIn("zip", nullList())).execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With NaN. @@ -551,7 +554,7 @@ public void testQueriesCanUseNotInFilters() { expectedDocsMap.remove("j"); snapshot = waitFor( - db.pipeline().createFrom(collection.whereNotIn("zip", asList(Double.NaN))).execute()); + db.pipeline().convertFrom(collection.whereNotIn("zip", asList(Double.NaN))).execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); // With NaN and a number. @@ -563,7 +566,7 @@ public void testQueriesCanUseNotInFilters() { snapshot = waitFor( db.pipeline() - .createFrom(collection.whereNotIn("zip", asList(Float.NaN, 98101L))) + .convertFrom(collection.whereNotIn("zip", asList(Float.NaN, 98101L))) .execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); } @@ -585,7 +588,7 @@ public void testQueriesCanUseNotInFiltersWithDocIds() { PipelineSnapshot docs = waitFor( db.pipeline() - .createFrom(collection.whereNotIn(FieldPath.documentId(), asList("aa", "ab"))) + .convertFrom(collection.whereNotIn(FieldPath.documentId(), asList("aa", "ab"))) .execute()); assertEquals(asList(docC, docD), pipelineSnapshotToValues(docs)); } @@ -613,7 +616,7 @@ public void testQueriesCanUseArrayContainsAnyFilters() { PipelineSnapshot snapshot = waitFor( db.pipeline() - .createFrom(collection.whereArrayContainsAny("array", asList(42L, 43L))) + .convertFrom(collection.whereArrayContainsAny("array", asList(42L, 43L))) .execute()); assertEquals(asList(docA, docB, docD, docE), pipelineSnapshotToValues(snapshot)); @@ -621,7 +624,7 @@ public void testQueriesCanUseArrayContainsAnyFilters() { snapshot = waitFor( db.pipeline() - .createFrom(collection.whereArrayContainsAny("array", asList(map("a", 42L)))) + .convertFrom(collection.whereArrayContainsAny("array", asList(map("a", 42L)))) .execute()); assertEquals(asList(docF), pipelineSnapshotToValues(snapshot)); @@ -629,7 +632,7 @@ public void testQueriesCanUseArrayContainsAnyFilters() { snapshot = waitFor( db.pipeline() - .createFrom(collection.whereArrayContainsAny("array", nullList())) + .convertFrom(collection.whereArrayContainsAny("array", nullList())) .execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); @@ -639,7 +642,7 @@ public void testQueriesCanUseArrayContainsAnyFilters() { snapshot = waitFor( db.pipeline() - .createFrom(collection.whereArrayContainsAny("array", inputList)) + .convertFrom(collection.whereArrayContainsAny("array", inputList)) .execute()); assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); @@ -647,7 +650,7 @@ public void testQueriesCanUseArrayContainsAnyFilters() { snapshot = waitFor( db.pipeline() - .createFrom(collection.whereArrayContainsAny("array", asList(Double.NaN))) + .convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN))) .execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); @@ -655,7 +658,7 @@ public void testQueriesCanUseArrayContainsAnyFilters() { snapshot = waitFor( db.pipeline() - .createFrom(collection.whereArrayContainsAny("array", asList(Double.NaN, 43L))) + .convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN, 43L))) .execute()); assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); } @@ -688,7 +691,7 @@ public void testCollectionGroupQueries() { waitFor(batch.commit()); PipelineSnapshot snapshot = - waitFor(db.pipeline().createFrom(db.collectionGroup(collectionGroup)).execute()); + waitFor(db.pipeline().convertFrom(db.collectionGroup(collectionGroup)).execute()); assertEquals( asList("cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5"), pipelineSnapshotToIds(snapshot)); @@ -720,7 +723,7 @@ public void testCollectionGroupQueriesWithStartAtEndAtWithArbitraryDocumentIds() PipelineSnapshot snapshot = waitFor( db.pipeline() - .createFrom( + .convertFrom( db.collectionGroup(collectionGroup) .orderBy(FieldPath.documentId()) .startAt("a/b") @@ -731,7 +734,7 @@ public void testCollectionGroupQueriesWithStartAtEndAtWithArbitraryDocumentIds() snapshot = waitFor( db.pipeline() - .createFrom( + .convertFrom( db.collectionGroup(collectionGroup) .orderBy(FieldPath.documentId()) .startAfter("a/b") @@ -766,7 +769,7 @@ public void testCollectionGroupQueriesWithWhereFiltersOnArbitraryDocumentIds() { PipelineSnapshot snapshot = waitFor( db.pipeline() - .createFrom( + .convertFrom( db.collectionGroup(collectionGroup) .whereGreaterThanOrEqualTo(FieldPath.documentId(), "a/b") .whereLessThanOrEqualTo(FieldPath.documentId(), "a/b0")) @@ -776,7 +779,7 @@ public void testCollectionGroupQueriesWithWhereFiltersOnArbitraryDocumentIds() { snapshot = waitFor( db.pipeline() - .createFrom( + .convertFrom( db.collectionGroup(collectionGroup) .whereGreaterThan(FieldPath.documentId(), "a/b") .whereLessThan( diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 8f30947e50c..1cf45215a80 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -101,9 +101,34 @@ internal constructor( .addAllStages(stages.map { it.toProtoStage(userDataReader) }) .build() + /** + * Adds a stage to the pipeline by specifying the stage name as an argument. This does not offer + * any type safety on the stage params and requires the caller to know the order (and optionally + * names) of parameters accepted by the stage. + * + * This method provides a way to call stages that are supported by the Firestore backend but that + * are not implemented in the SDK version being used. + * + * For stages with named parameters, use the [GenericStage] class instead. + * + * @param name The unique name of the stage to add. + * @param arguments A list of ordered parameters to configure the stage's behavior. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun genericStage(name: String, vararg arguments: Any): Pipeline = append(GenericStage(name, arguments.map(GenericArg::from))) + /** + * Adds a stage to the pipeline by specifying the stage name as an argument. This does not offer + * any type safety on the stage params and requires the caller to know the order (and optionally + * names) of parameters accepted by the stage. + * + * This method provides a way to call stages that are supported by the Firestore backend but that + * are not implemented in the SDK version being used. + * + * @param stage An [GenericStage] object that specifies stage name and parameters. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun genericStage(stage: GenericStage): Pipeline = append(stage) /** @@ -125,10 +150,27 @@ internal constructor( fun addFields(field: Selectable, vararg additionalFields: Selectable): Pipeline = append(AddFieldsStage(arrayOf(field, *additionalFields))) - fun removeFields(vararg fields: Field): Pipeline = append(RemoveFieldsStage(fields)) + /** + * Remove fields from outputs of previous stages. + * + * @param field The first [Field] to remove. + * @param additionalFields Optional additional [Field]s to remove. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun removeFields(field: Field, vararg additionalFields: Field): Pipeline = + append(RemoveFieldsStage(arrayOf(field, *additionalFields))) - fun removeFields(vararg fields: String): Pipeline = - append(RemoveFieldsStage(fields.map(Field::of).toTypedArray())) + /** + * Remove fields from outputs of previous stages. + * + * @param field The first [String] name of field to remove. + * @param additionalFields Optional additional [String] name of fields to remove. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun removeFields(field: String, vararg additionalFields: String): Pipeline = + append( + RemoveFieldsStage(arrayOf(Field.of(field), *additionalFields.map(Field::of).toTypedArray())) + ) /** * Selects or creates a set of fields from the outputs of previous stages. @@ -185,7 +227,22 @@ internal constructor( ) ) - fun sort(vararg orders: Ordering): Pipeline = append(SortStage(orders)) + /** + * Sorts the documents from previous stages based on one or more [Ordering] criteria. + * + * This stage allows you to order the results of your pipeline. You can specify multiple + * [Ordering] instances to sort by multiple fields in ascending or descending order. If documents + * have the same value for a field used for sorting, the next specified ordering will be used. If + * all orderings result in equal comparison, the documents are considered equal and the order is + * unspecified. + * + * @param order The first [Ordering] instance specifying the sorting criteria. + * @param additionalOrders Optional additional [Ordering] instances specifying the sorting + * criteria. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun sort(order: Ordering, vararg additionalOrders: Ordering): Pipeline = + append(SortStage(arrayOf(order, *additionalOrders))) /** * Filters the documents from previous stages to only include those matching the specified @@ -402,22 +459,112 @@ internal constructor( */ fun findNearest(stage: FindNearestStage): Pipeline = append(stage) + /** + * Fully overwrites all fields in a document with those coming from a nested map. + * + * This stage allows you to emit a map value as a document. Each key of the map becomes a field on + * the document that contains the corresponding value. + * + * @param field The [String] specifying the field name containing the nested map. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun replace(field: String): Pipeline = replace(Field.of(field)) - fun replace(field: Selectable): Pipeline = - append(ReplaceStage(field, ReplaceStage.Mode.FULL_REPLACE)) + /** + * Fully overwrites all fields in a document with those coming from a nested map. + * + * This stage allows you to emit a map value as a document. Each key of the map becomes a field on + * the document that contains the corresponding value. + * + * @param mapValue The [Expr] or [Field] containing the nested map. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun replace(mapValue: Expr): Pipeline = + append(ReplaceStage(mapValue, ReplaceStage.Mode.FULL_REPLACE)) + /** + * Performs a pseudo-random sampling of the input documents. + * + * The [documents] parameter represents the target number of documents to produce and must be a + * non-negative integer value. If the previous stage produces less than size documents, the entire + * previous results are returned. If the previous stage produces more than size, this outputs a + * sample of exactly size entries where any sample is equally likely. + * + * @param documents The number of documents to emit. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun sample(documents: Int): Pipeline = append(SampleStage.withDocLimit(documents)) + /** + * Performs a pseudo-random sampling of the input documents. + * + * @param sample An [SampleStage] object that specifies how sampling is performed. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun sample(sample: SampleStage): Pipeline = append(sample) + /** + * Performs union of all documents from two pipelines, including duplicates. + * + * This stage will pass through documents from previous stage, and also pass through documents + * from previous stage of the `other` Pipeline given in parameter. The order of documents emitted + * from this stage is undefined. + * + * @param other The other [Pipeline] that is part of union. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ fun union(other: Pipeline): Pipeline = append(UnionStage(other)) - fun unnest(field: String, alias: String): Pipeline = unnest(UnnestStage.withField(field, alias)) + /** + * Takes a specified array from the input documents and outputs a document for each element with + * the element stored in a field with name specified by the alias. + * + * For each document emitted by the prior stage, this stage will emit zero or more augmented + * documents. The input array found in the previous stage document field specified by the + * [arrayField] parameter, will for each element of the input array produce an augmented document. + * The element of the input array will be stored in a field with name specified by [alias] + * parameter on the augmented document. + * + * @param arrayField The name of the field containing the array. + * @param alias The name of field to store emitted element of array. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun unnest(arrayField: String, alias: String): Pipeline = + unnest(Field.of(arrayField).alias(alias)) - fun unnest(selectable: Selectable): Pipeline = append(UnnestStage(selectable)) + /** + * Takes a specified array from the input documents and outputs a document for each element with + * the element stored in a field with name specified by the alias. + * + * For each document emitted by the prior stage, this stage will emit zero or more augmented + * documents. The input array is found in parameter [arrayWithAlias], which can be an [Expr] with + * an alias specified via [Expr.alias], or a [Field] that can also have alias specified. For each + * element of the input array, an augmented document will be produced. The element of input array + * will be stored in a field with name specified by the alias of the [arrayWithAlias] parameter. + * If the [arrayWithAlias] is a [Field] with no alias, then the original array field will be + * replaced with the individual element. + * + * @param arrayWithAlias The input array with field alias to store output element of array. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun unnest(arrayWithAlias: Selectable): Pipeline = append(UnnestStage(arrayWithAlias)) - fun unnest(stage: UnnestStage): Pipeline = append(stage) + /** + * Takes a specified array from the input documents and outputs a document for each element with + * the element stored in a field with name specified by the alias. + * + * For each document emitted by the prior stage, this stage will emit zero or more augmented + * documents. The input array specified in the [unnestStage] parameter will for each element of + * the input array produce an augmented document. The element of the input array will be stored in + * a field with a name specified by the [unnestStage] parameter. + * + * Optionally, an index field can also be added to emitted documents. See [UnnestStage] for + * further information. + * + * @param unnestStage An [UnnestStage] object that specifies the search parameters. + * @return A new [Pipeline] object with this stage appended to the stage list. + */ + fun unnest(unnestStage: UnnestStage): Pipeline = append(unnestStage) private inner class ObserverSnapshotTask : PipelineResultObserver { private val userDataWriter = @@ -466,7 +613,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto * @throws [IllegalArgumentException] Thrown if the [query] provided targets a different project * or database than the pipeline. */ - fun createFrom(query: Query): Pipeline { + fun convertFrom(query: Query): Pipeline { if (query.firestore.databaseId != firestore.databaseId) { throw IllegalArgumentException("Provided query is from a different Firestore instance.") } @@ -481,9 +628,9 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto * @throws [IllegalArgumentException] Thrown if the [aggregateQuery] provided targets a different * project or database than the pipeline. */ - fun createFrom(aggregateQuery: AggregateQuery): Pipeline { + fun convertFrom(aggregateQuery: AggregateQuery): Pipeline { val aggregateFields = aggregateQuery.aggregateFields - return createFrom(aggregateQuery.query) + return convertFrom(aggregateQuery.query) .aggregate( aggregateFields.first().toPipeline(), *aggregateFields.drop(1).map(AggregateField::toPipeline).toTypedArray() diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt index 0edf481cf16..1e5c47da1f9 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt @@ -25,6 +25,11 @@ import com.google.firebase.firestore.model.Values.encodeValue import com.google.firestore.v1.Value import java.util.Date +/** + * Represents a constant value that can be used in a Firestore pipeline expression. + * + * You can create a [Constant] instance using the static [of] method: + */ abstract class Constant internal constructor() : Expr() { private class ValueConstant(val value: Value) : Constant() { @@ -38,41 +43,89 @@ abstract class Constant internal constructor() : Expr() { return ValueConstant(value) } + /** + * Create a [Constant] instance for a [String] value. + * + * @param value The [String] value. + * @return A new [Constant] instance. + */ @JvmStatic fun of(value: String): Constant { return ValueConstant(encodeValue(value)) } + /** + * Create a [Constant] instance for a [Number] value. + * + * @param value The [Number] value. + * @return A new [Constant] instance. + */ @JvmStatic fun of(value: Number): Constant { return ValueConstant(encodeValue(value)) } + /** + * Create a [Constant] instance for a [Date] value. + * + * @param value The [Date] value. + * @return A new [Constant] instance. + */ @JvmStatic fun of(value: Date): Constant { return ValueConstant(encodeValue(value)) } + /** + * Create a [Constant] instance for a [Timestamp] value. + * + * @param value The [Timestamp] value. + * @return A new [Constant] instance. + */ @JvmStatic fun of(value: Timestamp): Constant { return ValueConstant(encodeValue(value)) } + /** + * Create a [Constant] instance for a [Boolean] value. + * + * @param value The [Boolean] value. + * @return A new [Constant] instance. + */ @JvmStatic fun of(value: Boolean): Constant { return ValueConstant(encodeValue(value)) } + /** + * Create a [Constant] instance for a [GeoPoint] value. + * + * @param value The [GeoPoint] value. + * @return A new [Constant] instance. + */ @JvmStatic fun of(value: GeoPoint): Constant { return ValueConstant(encodeValue(value)) } + /** + * Create a [Constant] instance for a [Blob] value. + * + * @param value The [Blob] value. + * @return A new [Constant] instance. + */ @JvmStatic fun of(value: Blob): Constant { return ValueConstant(encodeValue(value)) } + /** + * Create a [Constant] instance for a [DocumentReference] value. + * + * @param ref The [DocumentReference] value. + * @return A new [Constant] instance. + */ @JvmStatic fun of(ref: DocumentReference): Constant { return object : Constant() { @@ -83,24 +136,47 @@ abstract class Constant internal constructor() : Expr() { } } + /** + * Create a [Constant] instance for a [VectorValue] value. + * + * @param value The [VectorValue] value. + * @return A new [Constant] instance. + */ @JvmStatic fun of(value: VectorValue): Constant { return ValueConstant(encodeValue(value)) } + /** + * [Constant] instance for a null value. + * + * @return A [Constant] instance. + */ @JvmStatic fun nullValue(): Constant { return NULL } + /** + * Create a vector [Constant] instance for a [DoubleArray] value. + * + * @param vector The [VectorValue] value. + * @return A new [Constant] instance. + */ @JvmStatic - fun vector(value: DoubleArray): Constant { - return ValueConstant(Values.encodeVectorValue(value)) + fun vector(vector: DoubleArray): Constant { + return ValueConstant(Values.encodeVectorValue(vector)) } + /** + * Create a vector [Constant] instance for a [VectorValue] value. + * + * @param vector The [VectorValue] value. + * @return A new [Constant] instance. + */ @JvmStatic - fun vector(value: VectorValue): Constant { - return ValueConstant(encodeValue(value)) + fun vector(vector: VectorValue): Constant { + return ValueConstant(encodeValue(vector)) } } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt index 0461718d7fa..afcb2797df2 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt @@ -20,6 +20,7 @@ import com.google.firestore.v1.Value class AggregateWithAlias internal constructor(internal val alias: String, internal val expr: AggregateFunction) +/** A class that represents an aggregate function. */ class AggregateFunction private constructor(private val name: String, private val params: Array) { private constructor(name: String) : this(name, emptyArray()) @@ -55,6 +56,13 @@ private constructor(private val name: String, private val params: ArrayExample: * - *
{@code // Calculate the total price and assign it the alias "totalPrice" and add it to the
+   * 
 // Calculate the total price and assign it the alias "totalPrice" and add it to the
+   *
    * output. firestore.pipeline().collection("items")
-   * .addFields(Field.of("price").multiply(Field.of("quantity")).as("totalPrice")); }
+ * .addFields(Field.of("price").multiply(Field.of("quantity")).as("totalPrice"));
* * @param alias The alias to assign to this expression. - * @return A new {@code Selectable} (typically an {@link ExprWithAlias}) that wraps this - * ``` - * expression and associates it with the provided alias. - * ``` + * @return A new [Selectable] (typically an [ExprWithAlias]) that wraps this expression and + * associates it with the provided alias. */ open fun alias(alias: String) = ExprWithAlias(alias, this) @@ -340,6 +354,7 @@ abstract class Expr internal constructor() { internal abstract fun toProto(userDataReader: UserDataReader): Value } +/** Expressions that have an alias are [Selectable] */ abstract class Selectable : Expr() { internal abstract fun getAlias(): String internal abstract fun getExpr(): Expr @@ -356,6 +371,7 @@ abstract class Selectable : Expr() { } } +/** Represents an expression that will be given the alias in the output document. */ class ExprWithAlias internal constructor(private val alias: String, private val expr: Expr) : Selectable() { override fun getAlias() = alias @@ -363,10 +379,33 @@ class ExprWithAlias internal constructor(private val alias: String, private val override fun toProto(userDataReader: UserDataReader): Value = expr.toProto(userDataReader) } +/** + * Represents a reference to a field in a Firestore document. + * + * [Field] references are used to access document field values in expressions and to specify fields + * for sorting, filtering, and projecting data in Firestore pipelines. + * + * You can create a [Field] instance using the static [of] method: + */ class Field internal constructor(private val fieldPath: ModelFieldPath) : Selectable() { companion object { + + /** + * An expression that returns the document ID. + * + * @return An [Field] representing the document ID. + */ @JvmField val DOCUMENT_ID: Field = of(FieldPath.documentId()) + /** + * Creates a [Field] instance representing the field at the given path. + * + * The path can be a simple field name (e.g., "name") or a dot-separated path to a nested field + * (e.g., "address.city"). + * + * @param name The path to the field. + * @return A new [Field] instance representing the specified path. + */ @JvmStatic fun of(name: String): Field { if (name == DocumentKey.KEY_FIELD_NAME) { @@ -375,6 +414,15 @@ class Field internal constructor(private val fieldPath: ModelFieldPath) : Select return Field(FieldPath.fromDotSeparatedPath(name).internalPath) } + /** + * Creates a [Field] instance representing the field at the given path. + * + * The path can be a simple field name (e.g., "name") or a dot-separated path to a nested field + * (e.g., "address.city"). + * + * @param fieldPath The [FieldPath] to the field. + * @return A new [Field] instance representing the specified path. + */ @JvmStatic fun of(fieldPath: FieldPath): Field { return Field(fieldPath.internalPath) @@ -382,6 +430,7 @@ class Field internal constructor(private val fieldPath: ModelFieldPath) : Select } override fun getAlias(): String = fieldPath.canonicalString() + override fun getExpr(): Expr = this override fun toProto(userDataReader: UserDataReader) = toProto() @@ -395,6 +444,14 @@ internal class ListOfExprs(private val expressions: Array) : Expr() { encodeValue(expressions.map { it.toProto(userDataReader) }) } +/** + * This class defines the base class for Firestore [Pipeline] functions, which can be evaluated + * within pipeline execution. + * + * Typically, you would not use this class or its children directly. Use either the functions like + * [and], [eq], or the methods on [Expr] ([Expr.eq]), [Expr.lt], etc) to construct new + * [FunctionExpr] instances. + */ open class FunctionExpr protected constructor(private val name: String, private val params: Array) : Expr() { private constructor( @@ -1023,6 +1080,7 @@ protected constructor(private val name: String, private val params: Array) : FunctionExpr(name, params) { internal constructor( @@ -1054,19 +1112,50 @@ class BooleanExpr internal constructor(name: String, params: Array) : fun cond(then: Any, otherwise: Any) = cond(this, then, otherwise) } +/** + * Represents an ordering criterion for sorting documents in a Firestore pipeline. + * + * You create [Ordering] instances using the [ascending] and [descending] helper methods. + */ class Ordering private constructor(val expr: Expr, private val dir: Direction) { companion object { + + /** + * Create an [Ordering] that sorts documents in ascending order based on value of [expr]. + * + * @param expr The order is based on the evaluation of the [Expr]. + * @return A new [Ordering] object with ascending sort by [expr]. + */ @JvmStatic fun ascending(expr: Expr): Ordering = Ordering(expr, Direction.ASCENDING) + /** + * Creates an [Ordering] that sorts documents in ascending order based on field. + * + * @param fieldName The name of field to sort documents. + * @return A new [Ordering] object with ascending sort by field. + */ @JvmStatic fun ascending(fieldName: String): Ordering = Ordering(Field.of(fieldName), Direction.ASCENDING) + /** + * Create an [Ordering] that sorts documents in descending order based on value of [expr]. + * + * @param expr The order is based on the evaluation of the [Expr]. + * @return A new [Ordering] object with descending sort by [expr]. + */ @JvmStatic fun descending(expr: Expr): Ordering = Ordering(expr, Direction.DESCENDING) + /** + * Creates an [Ordering] that sorts documents in descending order based on field. + * + * @param fieldName The name of field to sort documents. + * @return A new [Ordering] object with descending sort by field. + */ @JvmStatic fun descending(fieldName: String): Ordering = Ordering(Field.of(fieldName), Direction.DESCENDING) } + private class Direction private constructor(val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) companion object { @@ -1074,6 +1163,7 @@ class Ordering private constructor(val expr: Expr, private val dir: Direction) { val DESCENDING = Direction("descending") } } + internal fun toProto(userDataReader: UserDataReader): Value = Value.newBuilder() .setMapValue( @@ -1083,6 +1173,14 @@ class Ordering private constructor(val expr: Expr, private val dir: Direction) { ) .build() + /** + * Create an order that is in reverse. + * + * If the previous [Ordering] was ascending, then the new [Ordering] will be descending. Likewise, + * if the previous [Ordering] was descending, then the new [Ordering] will be ascending. + * + * @return New [Ordering] object that is has order reversed. + */ fun reverse(): Ordering = Ordering(expr, if (dir == Direction.ASCENDING) Direction.DESCENDING else Direction.ASCENDING) } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index 2083ecc0837..57293c47bad 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -37,17 +37,60 @@ internal constructor(protected val name: String, internal val options: InternalO protected fun with(key: String, value: Value): T = self(options.with(key, value)) + /** + * Specify named [String] parameter + * + * @param key The name of parameter + * @param value The [String] value of parameter + * @return New stage with named parameter. + */ fun with(key: String, value: String): T = with(key, Values.encodeValue(value)) + /** + * Specify named [Boolean] parameter + * + * @param key The name of parameter + * @param value The [Boolean] value of parameter + * @return New stage with named parameter. + */ fun with(key: String, value: Boolean): T = with(key, Values.encodeValue(value)) + /** + * Specify named [Long] parameter + * + * @param key The name of parameter + * @param value The [Long] value of parameter + * @return New stage with named parameter. + */ fun with(key: String, value: Long): T = with(key, Values.encodeValue(value)) + /** + * Specify named [Double] parameter + * + * @param key The name of parameter + * @param value The [Double] value of parameter + * @return New stage with named parameter. + */ fun with(key: String, value: Double): T = with(key, Values.encodeValue(value)) + /** + * Specify named [Field] parameter + * + * @param key The name of parameter + * @param value The [Field] value of parameter + * @return New stage with named parameter. + */ fun with(key: String, value: Field): T = with(key, value.toProto()) } +/** + * Adds a stage to the pipeline by specifying the stage name as an argument. This does not offer any + * type safety on the stage params and requires the caller to know the order (and optionally names) + * of parameters accepted by the stage. + * + * This class provides a way to call stages that are supported by the Firestore backend but that are + * not implemented in the SDK version being used. + */ class GenericStage internal constructor( name: String, @@ -55,11 +98,23 @@ internal constructor( options: InternalOptions = InternalOptions.EMPTY ) : Stage(name, options) { companion object { + /** + * Specify name of stage + * + * @param name The unique name of the stage to add. + * @return [GenericStage] with specified parameters. + */ @JvmStatic fun ofName(name: String) = GenericStage(name, emptyList(), InternalOptions.EMPTY) } override fun self(options: InternalOptions) = GenericStage(name, arguments, options) + /** + * Specify arguments to stage. + * + * @param arguments A list of ordered parameters to configure the stage's behavior. + * @return [GenericStage] with specified parameters. + */ fun withArguments(vararg arguments: Any): GenericStage = GenericStage(name, arguments.map(GenericArg::from), options) @@ -186,7 +241,7 @@ internal constructor( * AggregateFunction} with an alias for the accumulated results. * @param additionalAccumulators The [AggregateWithAlias] expressions, each wrapping an * [AggregateFunction] with an alias for the accumulated results. - * @return Aggregate Stage with specified accumulators. + * @return [AggregateStage] with specified accumulators. */ @JvmStatic fun withAccumulators( @@ -208,7 +263,7 @@ internal constructor( * @param groupField The [String] representing field name. * @param additionalGroups The [Selectable] expressions to consider when determining group value * combinations or [String]s representing field names. - * @return Aggregate Stage with specified groups. + * @return [AggregateStage] with specified groups. */ fun withGroups(groupField: String, vararg additionalGroups: Any) = withGroups(Field.of(groupField), additionalGroups) @@ -220,7 +275,7 @@ internal constructor( * combinations. * @param additionalGroups The [Selectable] expressions to consider when determining group value * combinations or [String]s representing field names. - * @return Aggregate Stage with specified groups. + * @return [AggregateStage] with specified groups. */ fun withGroups(group: Selectable, vararg additionalGroups: Any) = AggregateStage( @@ -424,7 +479,7 @@ internal constructor( internal class ReplaceStage internal constructor( - private val field: Selectable, + private val mapValue: Expr, private val mode: Mode, options: InternalOptions = InternalOptions.EMPTY ) : Stage("replace", options) { @@ -436,11 +491,19 @@ internal constructor( val MERGE_PREFER_PARENT = Mode("merge_prefer_parent") } } - override fun self(options: InternalOptions) = ReplaceStage(field, mode, options) + override fun self(options: InternalOptions) = ReplaceStage(mapValue, mode, options) override fun args(userDataReader: UserDataReader): Sequence = - sequenceOf(field.toProto(userDataReader), mode.proto) + sequenceOf(mapValue.toProto(userDataReader), mode.proto) } +/** + * Performs a pseudo-random sampling of the input documents. + * + * The documents produced from this stage are non-deterministic, running the same query over the + * same dataset multiple times will produce different results. There are two different ways to + * dictate how the sample is calculated either by specifying a target output size, or by specifying + * a target percentage of the input size. + */ class SampleStage private constructor( private val size: Number, @@ -456,8 +519,29 @@ private constructor( } } companion object { + /** + * Creates [SampleStage] with size limited to percentage of prior stages results. + * + * The [percentage] parameter is the target percentage (between 0.0 & 1.0) of the number of + * input documents to produce. Each input document is independently selected against the given + * percentage. As a result the output size will be approximately documents * [percentage]. + * + * @param percentage The percentage of the prior stages documents to emit. + * @return [SampleStage] with specified [percentage]. + */ @JvmStatic fun withPercentage(percentage: Double) = SampleStage(percentage, Mode.PERCENT) + /** + * Creates [SampleStage] with size limited to number of documents. + * + * The [documents] parameter represents the target number of documents to produce and must be a + * non-negative integer value. If the previous stage produces less than size documents, the + * entire previous results are returned. If the previous stage produces more than size, this + * outputs a sample of exactly size entries where any sample is equally likely. + * + * @param documents The number of documents to emit. + * @return [SampleStage] with specified [documents]. + */ @JvmStatic fun withDocLimit(documents: Int) = SampleStage(documents, Mode.DOCUMENTS) } override fun args(userDataReader: UserDataReader): Sequence = @@ -474,20 +558,60 @@ internal constructor( sequenceOf(Value.newBuilder().setPipelineValue(other.toPipelineProto()).build()) } +/** + * Takes a specified array from the input documents and outputs a document for each element with the + * element stored in a field with name specified by the alias. + */ class UnnestStage internal constructor( private val selectable: Selectable, options: InternalOptions = InternalOptions.EMPTY ) : Stage("unnest", options) { companion object { - @JvmStatic fun withField(selectable: Selectable) = UnnestStage(selectable) + + /** + * Creates [UnnestStage] with input array and alias specified. + * + * For each document emitted by the prior stage, this stage will emit zero or more augmented + * documents. The input array is found in parameter [arrayWithAlias], which can be an [Expr] + * with an alias specified via [Expr.alias], or a [Field] that can also have alias specified. + * For each element of the input array, an augmented document will be produced. The element of + * input array will be stored in a field with name specified by the alias of the + * [arrayWithAlias] parameter. If the [arrayWithAlias] is a [Field] with no alias, then the + * original array field will be replaced with the individual element. + * + * @param arrayWithAlias The input array with field alias to store output element of array. + * @return [SampleStage] with input array and alias specified. + */ + @JvmStatic fun withField(arrayWithAlias: Selectable) = UnnestStage(arrayWithAlias) + + /** + * Creates [UnnestStage] with input array and alias specified. + * + * For each document emitted by the prior stage, this stage will emit zero or more augmented + * documents. The input array found in the previous stage document field specified by the + * [arrayField] parameter, will for each element of the input array produce an augmented + * document. The element of the input array will be stored in a field with name specified by + * [alias] parameter on the augmented document. + * + * @return [SampleStage] with input array and alias specified. + */ @JvmStatic - fun withField(field: String, alias: String): UnnestStage = - UnnestStage(Field.of(field).alias(alias)) + fun withField(arrayField: String, alias: String): UnnestStage = + UnnestStage(Field.of(arrayField).alias(alias)) } override fun self(options: InternalOptions) = UnnestStage(selectable, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(selectable.getAlias()), selectable.toProto(userDataReader)) + /** + * Adds index field to emitted documents + * + * A field with name specified in [indexField] will be added to emitted document. The index is a + * numeric value that corresponds to array index of the element from input array. + * + * @param indexField The field name of index field. + * @return [SampleStage] that includes specified index field. + */ fun withIndexField(indexField: String): UnnestStage = with("index_field", indexField) } From df1e7194900e83ab5be10e99f030faba93a0bbf1 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 10 Apr 2025 19:05:26 -0400 Subject: [PATCH 39/77] api.txt --- firebase-firestore/api.txt | 899 +++++++++++++++++++------------------ 1 file changed, 455 insertions(+), 444 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index c3ef4cac64a..78ce19cd2aa 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -420,49 +420,55 @@ package com.google.firebase.firestore { } public final class Pipeline { - method public com.google.firebase.firestore.Pipeline addFields(com.google.firebase.firestore.pipeline.Selectable... fields); + method public com.google.firebase.firestore.Pipeline addFields(com.google.firebase.firestore.pipeline.Selectable field, com.google.firebase.firestore.pipeline.Selectable... additionalFields); method public com.google.firebase.firestore.Pipeline aggregate(com.google.firebase.firestore.pipeline.AggregateStage aggregateStage); - method public com.google.firebase.firestore.Pipeline aggregate(com.google.firebase.firestore.pipeline.AggregateWithAlias... accumulators); - method public com.google.firebase.firestore.Pipeline distinct(com.google.firebase.firestore.pipeline.Selectable... groups); - method public com.google.firebase.firestore.Pipeline distinct(java.lang.Object... groups); - method public com.google.firebase.firestore.Pipeline distinct(java.lang.String... groups); + method public com.google.firebase.firestore.Pipeline aggregate(com.google.firebase.firestore.pipeline.AggregateWithAlias accumulator, com.google.firebase.firestore.pipeline.AggregateWithAlias... additionalAccumulators); + method public com.google.firebase.firestore.Pipeline distinct(com.google.firebase.firestore.pipeline.Selectable group, java.lang.Object... additionalGroups); + method public com.google.firebase.firestore.Pipeline distinct(String groupField, java.lang.Object... additionalGroups); method public com.google.android.gms.tasks.Task execute(); - method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Expr property, double[] vector, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); - method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Expr property, double[] vector, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure, com.google.firebase.firestore.pipeline.FindNearestOptions options); + method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.FindNearestStage stage); + method public com.google.firebase.firestore.Pipeline findNearest(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.Pipeline findNearest(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public com.google.firebase.firestore.Pipeline genericStage(com.google.firebase.firestore.pipeline.GenericStage stage); method public com.google.firebase.firestore.Pipeline genericStage(String name, java.lang.Object... arguments); method public com.google.firebase.firestore.Pipeline limit(int limit); method public com.google.firebase.firestore.Pipeline offset(int offset); - method public com.google.firebase.firestore.Pipeline removeFields(com.google.firebase.firestore.pipeline.Field... fields); - method public com.google.firebase.firestore.Pipeline removeFields(java.lang.String... fields); - method public com.google.firebase.firestore.Pipeline replace(com.google.firebase.firestore.pipeline.Selectable field); + method public com.google.firebase.firestore.Pipeline removeFields(com.google.firebase.firestore.pipeline.Field field, com.google.firebase.firestore.pipeline.Field... additionalFields); + method public com.google.firebase.firestore.Pipeline removeFields(String field, java.lang.String... additionalFields); + method public com.google.firebase.firestore.Pipeline replace(com.google.firebase.firestore.pipeline.Expr mapValue); method public com.google.firebase.firestore.Pipeline replace(String field); method public com.google.firebase.firestore.Pipeline sample(com.google.firebase.firestore.pipeline.SampleStage sample); method public com.google.firebase.firestore.Pipeline sample(int documents); - method public com.google.firebase.firestore.Pipeline select(com.google.firebase.firestore.pipeline.Selectable... fields); - method public com.google.firebase.firestore.Pipeline select(java.lang.Object... fields); - method public com.google.firebase.firestore.Pipeline select(java.lang.String... fields); - method public com.google.firebase.firestore.Pipeline sort(com.google.firebase.firestore.pipeline.Ordering... orders); + method public com.google.firebase.firestore.Pipeline select(com.google.firebase.firestore.pipeline.Selectable selection, java.lang.Object... additionalSelections); + method public com.google.firebase.firestore.Pipeline select(String fieldName, java.lang.Object... additionalSelections); + method public com.google.firebase.firestore.Pipeline sort(com.google.firebase.firestore.pipeline.Ordering order, com.google.firebase.firestore.pipeline.Ordering... additionalOrders); method public com.google.firebase.firestore.Pipeline union(com.google.firebase.firestore.Pipeline other); - method public com.google.firebase.firestore.Pipeline unnest(com.google.firebase.firestore.pipeline.Selectable selectable); - method public com.google.firebase.firestore.Pipeline unnest(com.google.firebase.firestore.pipeline.Selectable selectable, com.google.firebase.firestore.pipeline.UnnestOptions options); - method public com.google.firebase.firestore.Pipeline unnest(String field, String alias); - method public com.google.firebase.firestore.Pipeline unnest(String field, String alias, com.google.firebase.firestore.pipeline.UnnestOptions options); + method public com.google.firebase.firestore.Pipeline unnest(com.google.firebase.firestore.pipeline.Selectable arrayWithAlias); + method public com.google.firebase.firestore.Pipeline unnest(com.google.firebase.firestore.pipeline.UnnestStage unnestStage); + method public com.google.firebase.firestore.Pipeline unnest(String arrayField, String alias); method public com.google.firebase.firestore.Pipeline where(com.google.firebase.firestore.pipeline.BooleanExpr condition); } public final class PipelineResult { method public Object? get(com.google.firebase.firestore.FieldPath fieldPath); method public Object? get(String field); + method public com.google.firebase.Timestamp? getCreateTime(); method public java.util.Map getData(); method public String? getId(); method public com.google.firebase.firestore.DocumentReference? getRef(); + method public com.google.firebase.Timestamp? getUpdateTime(); + property public final com.google.firebase.Timestamp? createTime; property public final com.google.firebase.firestore.DocumentReference? ref; + property public final com.google.firebase.Timestamp? updateTime; } public final class PipelineSnapshot implements java.lang.Iterable kotlin.jvm.internal.markers.KMappedMarker { + method public com.google.firebase.Timestamp getExecutionTime(); method public java.util.List getResults(); method public java.util.Iterator iterator(); + property public final com.google.firebase.Timestamp executionTime; property public final java.util.List results; } @@ -470,6 +476,8 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline collection(com.google.firebase.firestore.CollectionReference ref); method public com.google.firebase.firestore.Pipeline collection(String path); method public com.google.firebase.firestore.Pipeline collectionGroup(String collectionId); + method public com.google.firebase.firestore.Pipeline convertFrom(com.google.firebase.firestore.AggregateQuery aggregateQuery); + method public com.google.firebase.firestore.Pipeline convertFrom(com.google.firebase.firestore.Query query); method public com.google.firebase.firestore.Pipeline database(); method public com.google.firebase.firestore.Pipeline documents(com.google.firebase.firestore.DocumentReference... documents); method public com.google.firebase.firestore.Pipeline documents(java.lang.String... documents); @@ -502,7 +510,6 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Query orderBy(com.google.firebase.firestore.FieldPath, com.google.firebase.firestore.Query.Direction); method public com.google.firebase.firestore.Query orderBy(String); method public com.google.firebase.firestore.Query orderBy(String, com.google.firebase.firestore.Query.Direction); - method public com.google.firebase.firestore.Pipeline pipeline(); method public com.google.firebase.firestore.Query startAfter(com.google.firebase.firestore.DocumentSnapshot); method public com.google.firebase.firestore.Query startAfter(java.lang.Object!...!); method public com.google.firebase.firestore.Query startAt(com.google.firebase.firestore.DocumentSnapshot); @@ -668,69 +675,59 @@ package com.google.firebase.firestore.ktx { package com.google.firebase.firestore.pipeline { - public abstract class AbstractOptions> { - method public final T with(String key, boolean value); - method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); - method public final T with(String key, double value); - method protected final T with(String key, error.NonExistentClass value); - method public final T with(String key, String value); - method public final T with(String key, long value); - } - - public final class AggregateExpr { - method public com.google.firebase.firestore.pipeline.AggregateWithAlias as(String alias); - method public static com.google.firebase.firestore.pipeline.AggregateExpr avg(com.google.firebase.firestore.pipeline.Expr expr); - method public static com.google.firebase.firestore.pipeline.AggregateExpr avg(String fieldName); - method public static com.google.firebase.firestore.pipeline.AggregateExpr count(com.google.firebase.firestore.pipeline.Expr expr); - method public static com.google.firebase.firestore.pipeline.AggregateExpr count(String fieldName); - method public static com.google.firebase.firestore.pipeline.AggregateExpr countAll(); - method public static com.google.firebase.firestore.pipeline.AggregateExpr countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); - method public static com.google.firebase.firestore.pipeline.AggregateExpr max(com.google.firebase.firestore.pipeline.Expr expr); - method public static com.google.firebase.firestore.pipeline.AggregateExpr max(String fieldName); - method public static com.google.firebase.firestore.pipeline.AggregateExpr min(com.google.firebase.firestore.pipeline.Expr expr); - method public static com.google.firebase.firestore.pipeline.AggregateExpr min(String fieldName); - method public static com.google.firebase.firestore.pipeline.AggregateExpr sum(com.google.firebase.firestore.pipeline.Expr expr); - method public static com.google.firebase.firestore.pipeline.AggregateExpr sum(String fieldName); - field public static final com.google.firebase.firestore.pipeline.AggregateExpr.Companion Companion; - } - - public static final class AggregateExpr.Companion { - method public com.google.firebase.firestore.pipeline.AggregateExpr avg(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.AggregateExpr avg(String fieldName); - method public com.google.firebase.firestore.pipeline.AggregateExpr count(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.AggregateExpr count(String fieldName); - method public com.google.firebase.firestore.pipeline.AggregateExpr countAll(); - method public com.google.firebase.firestore.pipeline.AggregateExpr countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); - method public com.google.firebase.firestore.pipeline.AggregateExpr max(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.AggregateExpr max(String fieldName); - method public com.google.firebase.firestore.pipeline.AggregateExpr min(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.AggregateExpr min(String fieldName); - method public com.google.firebase.firestore.pipeline.AggregateExpr sum(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.AggregateExpr sum(String fieldName); - } - - public final class AggregateStage extends com.google.firebase.firestore.pipeline.Stage { - method public static com.google.firebase.firestore.pipeline.AggregateStage withAccumulators(com.google.firebase.firestore.pipeline.AggregateWithAlias... accumulators); - method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(com.google.firebase.firestore.pipeline.Selectable... groups); - method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(java.lang.Object... selectable); - method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(java.lang.String... fields); + public final class AggregateFunction { + method public com.google.firebase.firestore.pipeline.AggregateWithAlias alias(String alias); + method public static com.google.firebase.firestore.pipeline.AggregateFunction avg(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateFunction avg(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateFunction count(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateFunction count(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateFunction countAll(); + method public static com.google.firebase.firestore.pipeline.AggregateFunction countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); + method public static com.google.firebase.firestore.pipeline.AggregateFunction generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public static com.google.firebase.firestore.pipeline.AggregateFunction max(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateFunction max(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateFunction min(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateFunction min(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateFunction sum(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateFunction sum(String fieldName); + field public static final com.google.firebase.firestore.pipeline.AggregateFunction.Companion Companion; + } + + public static final class AggregateFunction.Companion { + method public com.google.firebase.firestore.pipeline.AggregateFunction avg(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateFunction avg(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateFunction count(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateFunction count(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateFunction countAll(); + method public com.google.firebase.firestore.pipeline.AggregateFunction countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); + method public com.google.firebase.firestore.pipeline.AggregateFunction generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public com.google.firebase.firestore.pipeline.AggregateFunction max(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateFunction max(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateFunction min(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateFunction min(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateFunction sum(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateFunction sum(String fieldName); + } + + public final class AggregateStage extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.AggregateStage withAccumulators(com.google.firebase.firestore.pipeline.AggregateWithAlias accumulator, com.google.firebase.firestore.pipeline.AggregateWithAlias... additionalAccumulators); + method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(com.google.firebase.firestore.pipeline.Selectable group, java.lang.Object... additionalGroups); + method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(String groupField, java.lang.Object... additionalGroups); field public static final com.google.firebase.firestore.pipeline.AggregateStage.Companion Companion; } public static final class AggregateStage.Companion { - method public com.google.firebase.firestore.pipeline.AggregateStage withAccumulators(com.google.firebase.firestore.pipeline.AggregateWithAlias... accumulators); + method public com.google.firebase.firestore.pipeline.AggregateStage withAccumulators(com.google.firebase.firestore.pipeline.AggregateWithAlias accumulator, com.google.firebase.firestore.pipeline.AggregateWithAlias... additionalAccumulators); } public final class AggregateWithAlias { } - public final class BooleanExpr extends com.google.firebase.firestore.pipeline.Function { - method public com.google.firebase.firestore.pipeline.AggregateExpr countIf(); + public final class BooleanExpr extends com.google.firebase.firestore.pipeline.FunctionExpr { + method public com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); + method public com.google.firebase.firestore.pipeline.FunctionExpr cond(Object then, Object otherwise); + method public com.google.firebase.firestore.pipeline.AggregateFunction countIf(); method public static com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); - method public com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.Expr then); - method public com.google.firebase.firestore.pipeline.Function ifThen(Object then); - method public com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr else); - method public com.google.firebase.firestore.pipeline.Function ifThenElse(Object then, Object else); method public com.google.firebase.firestore.pipeline.BooleanExpr not(); field public static final com.google.firebase.firestore.pipeline.BooleanExpr.Companion Companion; } @@ -750,8 +747,8 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Constant of(Number value); method public static final com.google.firebase.firestore.pipeline.Constant of(String value); method public static final com.google.firebase.firestore.pipeline.Constant of(java.util.Date value); - method public static final com.google.firebase.firestore.pipeline.Constant vector(com.google.firebase.firestore.VectorValue value); - method public static final com.google.firebase.firestore.pipeline.Constant vector(double[] value); + method public static final com.google.firebase.firestore.pipeline.Constant vector(com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Constant vector(double[] vector); field public static final com.google.firebase.firestore.pipeline.Constant.Companion Companion; } @@ -766,54 +763,54 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Constant of(Number value); method public com.google.firebase.firestore.pipeline.Constant of(String value); method public com.google.firebase.firestore.pipeline.Constant of(java.util.Date value); - method public com.google.firebase.firestore.pipeline.Constant vector(com.google.firebase.firestore.VectorValue value); - method public com.google.firebase.firestore.pipeline.Constant vector(double[] value); + method public com.google.firebase.firestore.pipeline.Constant vector(com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Constant vector(double[] vector); } public abstract class Expr { - method public final com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.Function add(Object other); - method public final com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr... arrays); - method public final com.google.firebase.firestore.pipeline.Function arrayConcat(java.util.List arrays); + method public final com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr add(Object other); + method public com.google.firebase.firestore.pipeline.ExprWithAlias alias(String alias); + method public final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr... arrays); + method public final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(java.util.List arrays); method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr value); method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(Object value); method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(java.util.List values); method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(java.util.List values); - method public final com.google.firebase.firestore.pipeline.Function arrayLength(); - method public final com.google.firebase.firestore.pipeline.Function arrayReverse(); - method public com.google.firebase.firestore.pipeline.ExprWithAlias as(String alias); + method public final com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(); method public final com.google.firebase.firestore.pipeline.Ordering ascending(); - method public final com.google.firebase.firestore.pipeline.AggregateExpr avg(); - method public final com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr right); - method public final com.google.firebase.firestore.pipeline.Function bitAnd(Object right); - method public final com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr numberExpr); - method public final com.google.firebase.firestore.pipeline.Function bitLeftShift(int number); - method public final com.google.firebase.firestore.pipeline.Function bitNot(); - method public final com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr right); - method public final com.google.firebase.firestore.pipeline.Function bitOr(Object right); - method public final com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr numberExpr); - method public final com.google.firebase.firestore.pipeline.Function bitRightShift(int number); - method public final com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr right); - method public final com.google.firebase.firestore.pipeline.Function bitXor(Object right); - method public final com.google.firebase.firestore.pipeline.Function byteLength(); - method public final com.google.firebase.firestore.pipeline.Function charLength(); - method public final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector); - method public final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.VectorValue vector); - method public final com.google.firebase.firestore.pipeline.Function cosineDistance(double[] vector); + method public final com.google.firebase.firestore.pipeline.AggregateFunction avg(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr right); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(Object right); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr numberExpr); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(int number); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitNot(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr right); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(Object right); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr numberExpr); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(int number); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr right); + method public final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(Object right); + method public final com.google.firebase.firestore.pipeline.FunctionExpr byteLength(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr charLength(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector); + method public final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.VectorValue vector); + method public final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(double[] vector); method public final com.google.firebase.firestore.pipeline.Ordering descending(); - method public final com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.Function divide(Object other); - method public final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector); - method public final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.VectorValue vector); - method public final com.google.firebase.firestore.pipeline.Function dotProduct(double[] vector); + method public final com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr divide(Object other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector); + method public final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.VectorValue vector); + method public final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(double[] vector); method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr suffix); method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String suffix); method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(Object other); method public final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(java.util.List values); - method public final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector); - method public final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.VectorValue vector); - method public final com.google.firebase.firestore.pipeline.Function euclideanDistance(double[] vector); + method public final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector); + method public final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.VectorValue vector); + method public final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(double[] vector); method public final com.google.firebase.firestore.pipeline.BooleanExpr exists(); method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(Object other); @@ -825,22 +822,25 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.BooleanExpr isNull(); method public final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr like(String pattern); - method public final com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.Function logicalMax(Object other); - method public final com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.Function logicalMin(Object other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(Object other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(Object other); method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(Object other); method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(Object other); - method public final com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr key); - method public final com.google.firebase.firestore.pipeline.Function mapGet(String key); - method public final com.google.firebase.firestore.pipeline.AggregateExpr max(); - method public final com.google.firebase.firestore.pipeline.AggregateExpr min(); - method public final com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.Function mod(Object other); - method public final com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.Function multiply(Object other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr key); + method public final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String key); + method public final com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr key); + method public final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String key); + method public final com.google.firebase.firestore.pipeline.AggregateFunction max(); + method public final com.google.firebase.firestore.pipeline.AggregateFunction min(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr mod(Object other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr multiply(Object other); method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr other); method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(Object other); method public final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(java.util.List values); @@ -848,35 +848,35 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String pattern); - method public final com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public final com.google.firebase.firestore.pipeline.Function replaceAll(String find, String replace); - method public final com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public final com.google.firebase.firestore.pipeline.Function replaceFirst(String find, String replace); - method public final com.google.firebase.firestore.pipeline.Function reverse(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(String find, String replace); + method public final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(String find, String replace); + method public final com.google.firebase.firestore.pipeline.FunctionExpr reverse(); method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr prefix); method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String prefix); - method public final com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr... expr); - method public final com.google.firebase.firestore.pipeline.Function strConcat(java.lang.Object... string); - method public final com.google.firebase.firestore.pipeline.Function strConcat(java.lang.String... string); + method public final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr... expr); + method public final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(java.lang.Object... string); + method public final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(java.lang.String... string); method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr substring); method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String substring); - method public final com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.Function subtract(Object other); - method public final com.google.firebase.firestore.pipeline.AggregateExpr sum(); - method public final com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public final com.google.firebase.firestore.pipeline.Function timestampAdd(String unit, double amount); - method public final com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public final com.google.firebase.firestore.pipeline.Function timestampSub(String unit, double amount); - method public final com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(); - method public final com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(); - method public final com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(); - method public final com.google.firebase.firestore.pipeline.Function toLower(); - method public final com.google.firebase.firestore.pipeline.Function toUpper(); - method public final com.google.firebase.firestore.pipeline.Function trim(); - method public final com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(); - method public final com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(); - method public final com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(); - method public final com.google.firebase.firestore.pipeline.Function vectorLength(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr other); + method public final com.google.firebase.firestore.pipeline.FunctionExpr subtract(Object other); + method public final com.google.firebase.firestore.pipeline.AggregateFunction sum(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String unit, double amount); + method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String unit, double amount); + method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr toLower(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr toUpper(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr trim(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(); + method public final com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(); } public final class ExprWithAlias extends com.google.firebase.firestore.pipeline.Selectable { @@ -894,44 +894,45 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Field of(String name); } - public final class FindNearestOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { - method public com.google.firebase.firestore.pipeline.FindNearestOptions withDistanceField(com.google.firebase.firestore.pipeline.Field distanceField); - method public com.google.firebase.firestore.pipeline.FindNearestOptions withDistanceField(String distanceField); - method public com.google.firebase.firestore.pipeline.FindNearestOptions withLimit(long limit); - field public static final com.google.firebase.firestore.pipeline.FindNearestOptions.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.FindNearestOptions DEFAULT; + public final class FindNearestStage extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public static com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public static com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.pipeline.FindNearestStage withDistanceField(com.google.firebase.firestore.pipeline.Field distanceField); + method public com.google.firebase.firestore.pipeline.FindNearestStage withDistanceField(String distanceField); + method public com.google.firebase.firestore.pipeline.FindNearestStage withLimit(long limit); + field public static final com.google.firebase.firestore.pipeline.FindNearestStage.Companion Companion; } - public static final class FindNearestOptions.Companion { - } - - public final class FindNearestStage extends com.google.firebase.firestore.pipeline.Stage { + public static final class FindNearestStage.Companion { + method public com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); } public static final class FindNearestStage.DistanceMeasure { + field public static final error.NonExistentClass COSINE; field public static final com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure.Companion Companion; + field public static final error.NonExistentClass DOT_PRODUCT; + field public static final error.NonExistentClass EUCLIDEAN; } public static final class FindNearestStage.DistanceMeasure.Companion { - method public error.NonExistentClass getCOSINE(); - method public error.NonExistentClass getDOT_PRODUCT(); - method public error.NonExistentClass getEUCLIDEAN(); - property public final error.NonExistentClass COSINE; - property public final error.NonExistentClass DOT_PRODUCT; - property public final error.NonExistentClass EUCLIDEAN; - } - - public class Function extends com.google.firebase.firestore.pipeline.Expr { - ctor protected Function(String name, com.google.firebase.firestore.pipeline.Expr[] params); - method public static final com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Function add(String fieldName, Object other); + } + + public class FunctionExpr extends com.google.firebase.firestore.pipeline.Expr { + ctor protected FunctionExpr(String name, com.google.firebase.firestore.pipeline.Expr[] params); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr add(String fieldName, Object other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); - method public static final com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); - method public static final com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); - method public static final com.google.firebase.firestore.pipeline.Function arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); - method public static final com.google.firebase.firestore.pipeline.Function arrayConcat(String fieldName, java.util.List arrays); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(String fieldName, java.util.List arrays); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, com.google.firebase.firestore.pipeline.Expr value); @@ -940,52 +941,54 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String fieldName, java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String fieldName, java.util.List values); - method public static final com.google.firebase.firestore.pipeline.Function arrayLength(com.google.firebase.firestore.pipeline.Expr array); - method public static final com.google.firebase.firestore.pipeline.Function arrayLength(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function arrayReverse(com.google.firebase.firestore.pipeline.Expr array); - method public static final com.google.firebase.firestore.pipeline.Function arrayReverse(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function bitAnd(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public static final com.google.firebase.firestore.pipeline.Function bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Function bitLeftShift(String fieldName, int number); - method public static final com.google.firebase.firestore.pipeline.Function bitNot(com.google.firebase.firestore.pipeline.Expr left); - method public static final com.google.firebase.firestore.pipeline.Function bitNot(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function bitOr(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public static final com.google.firebase.firestore.pipeline.Function bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Function bitRightShift(String fieldName, int number); - method public static final com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function bitXor(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.Function byteLength(com.google.firebase.firestore.pipeline.Expr value); - method public static final com.google.firebase.firestore.pipeline.Function byteLength(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function charLength(com.google.firebase.firestore.pipeline.Expr value); - method public static final com.google.firebase.firestore.pipeline.Function charLength(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, double[] vector); - method public static final com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Function divide(String fieldName, Object other); - method public static final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public static final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public static final com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public static final com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(com.google.firebase.firestore.pipeline.Expr array); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(com.google.firebase.firestore.pipeline.Expr array); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(String fieldName, int number); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitNot(com.google.firebase.firestore.pipeline.Expr left); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitNot(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(String fieldName, int number); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr byteLength(com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr byteLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr charLength(com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr charLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object otherwise); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr divide(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, double[] vector); method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr suffix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, String suffix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr suffix); @@ -996,14 +999,14 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, java.util.List values); - method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, double[] vector); method public static final com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr expr); - method public static final com.google.firebase.firestore.pipeline.Function generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); @@ -1012,10 +1015,6 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then); - method public static final com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then); - method public static final com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr else); - method public static final com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object else); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(com.google.firebase.firestore.pipeline.Expr expr); @@ -1028,14 +1027,14 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, String pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, String pattern); - method public static final com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Function logicalMax(String fieldName, Object other); - method public static final com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Function logicalMin(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(String fieldName, Object other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); @@ -1044,18 +1043,25 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); - method public static final com.google.firebase.firestore.pipeline.Function mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.Function mapGet(String fieldName, String key); - method public static final com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Function mod(String fieldName, Object other); - method public static final com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Function multiply(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr map(java.util.Map elements); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String fieldName, String key); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(String mapField, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String mapField, String key); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr mod(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr multiply(String fieldName, Object other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); @@ -1072,72 +1078,72 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, String pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, String pattern); - method public static final com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public static final com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); - method public static final com.google.firebase.firestore.pipeline.Function replaceAll(String fieldName, String find, String replace); - method public static final com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public static final com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); - method public static final com.google.firebase.firestore.pipeline.Function replaceFirst(String fieldName, String find, String replace); - method public static final com.google.firebase.firestore.pipeline.Function reverse(com.google.firebase.firestore.pipeline.Expr expr); - method public static final com.google.firebase.firestore.pipeline.Function reverse(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(String fieldName, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(String fieldName, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr reverse(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr reverse(String fieldName); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, String prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); - method public static final com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); - method public static final com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); - method public static final com.google.firebase.firestore.pipeline.Function strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); - method public static final com.google.firebase.firestore.pipeline.Function strConcat(String fieldName, java.lang.Object... rest); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(String fieldName, java.lang.Object... rest); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, String substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); - method public static final com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.Function subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Function subtract(String fieldName, Object other); - method public static final com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public static final com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); - method public static final com.google.firebase.firestore.pipeline.Function timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public static final com.google.firebase.firestore.pipeline.Function timestampAdd(String fieldName, String unit, double amount); - method public static final com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public static final com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); - method public static final com.google.firebase.firestore.pipeline.Function timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public static final com.google.firebase.firestore.pipeline.Function timestampSub(String fieldName, String unit, double amount); - method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function toLower(com.google.firebase.firestore.pipeline.Expr expr); - method public static final com.google.firebase.firestore.pipeline.Function toLower(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function toUpper(com.google.firebase.firestore.pipeline.Expr expr); - method public static final com.google.firebase.firestore.pipeline.Function toUpper(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function trim(com.google.firebase.firestore.pipeline.Expr expr); - method public static final com.google.firebase.firestore.pipeline.Function trim(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Function vectorLength(com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.Function vectorLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr subtract(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String fieldName, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String fieldName, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr toLower(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr toLower(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr toUpper(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr toUpper(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr trim(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr trim(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(String fieldName); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(String fieldName); method public static final com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); - field public static final com.google.firebase.firestore.pipeline.Function.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.FunctionExpr.Companion Companion; } - public static final class Function.Companion { - method public com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function add(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Function add(String fieldName, Object other); + public static final class FunctionExpr.Companion { + method public com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.FunctionExpr add(String fieldName, Object other); method public com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); - method public com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); - method public com.google.firebase.firestore.pipeline.Function arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); - method public com.google.firebase.firestore.pipeline.Function arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); - method public com.google.firebase.firestore.pipeline.Function arrayConcat(String fieldName, java.util.List arrays); + method public com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); + method public com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); + method public com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); + method public com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(String fieldName, java.util.List arrays); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr value); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object value); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, com.google.firebase.firestore.pipeline.Expr value); @@ -1146,52 +1152,54 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String fieldName, java.util.List values); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String fieldName, java.util.List values); - method public com.google.firebase.firestore.pipeline.Function arrayLength(com.google.firebase.firestore.pipeline.Expr array); - method public com.google.firebase.firestore.pipeline.Function arrayLength(String fieldName); - method public com.google.firebase.firestore.pipeline.Function arrayReverse(com.google.firebase.firestore.pipeline.Expr array); - method public com.google.firebase.firestore.pipeline.Function arrayReverse(String fieldName); - method public com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function bitAnd(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.Function bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public com.google.firebase.firestore.pipeline.Function bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.Function bitLeftShift(String fieldName, int number); - method public com.google.firebase.firestore.pipeline.Function bitNot(com.google.firebase.firestore.pipeline.Expr left); - method public com.google.firebase.firestore.pipeline.Function bitNot(String fieldName); - method public com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function bitOr(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.Function bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public com.google.firebase.firestore.pipeline.Function bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.Function bitRightShift(String fieldName, int number); - method public com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function bitXor(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.Function byteLength(com.google.firebase.firestore.pipeline.Expr value); - method public com.google.firebase.firestore.pipeline.Function byteLength(String fieldName); - method public com.google.firebase.firestore.pipeline.Function charLength(com.google.firebase.firestore.pipeline.Expr value); - method public com.google.firebase.firestore.pipeline.Function charLength(String fieldName); - method public com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public com.google.firebase.firestore.pipeline.Function cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.Function cosineDistance(String fieldName, double[] vector); - method public com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function divide(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Function divide(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public com.google.firebase.firestore.pipeline.Function dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.Function dotProduct(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(com.google.firebase.firestore.pipeline.Expr array); + method public com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(com.google.firebase.firestore.pipeline.Expr array); + method public com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(String fieldName, int number); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitNot(com.google.firebase.firestore.pipeline.Expr left); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitNot(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitOr(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(String fieldName, int number); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr bitXor(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr byteLength(com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.FunctionExpr byteLength(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr charLength(com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.FunctionExpr charLength(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); + method public com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object otherwise); + method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.FunctionExpr divide(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, double[] vector); method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr suffix); method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, String suffix); method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr suffix); @@ -1202,14 +1210,14 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, java.util.List values); - method public com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public com.google.firebase.firestore.pipeline.Function euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.Function euclideanDistance(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, double[] vector); method public com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.Function generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public com.google.firebase.firestore.pipeline.FunctionExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); @@ -1218,10 +1226,6 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then); - method public com.google.firebase.firestore.pipeline.Function ifThen(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then); - method public com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr else); - method public com.google.firebase.firestore.pipeline.Function ifThenElse(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object else); method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(com.google.firebase.firestore.pipeline.Expr expr); @@ -1234,14 +1238,14 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, String pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, String pattern); - method public com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Function logicalMax(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Function logicalMin(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(String fieldName, Object other); method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); @@ -1250,18 +1254,25 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); - method public com.google.firebase.firestore.pipeline.Function mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); - method public com.google.firebase.firestore.pipeline.Function mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); - method public com.google.firebase.firestore.pipeline.Function mapGet(String fieldName, String key); - method public com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function mod(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Function mod(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Function multiply(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.FunctionExpr map(java.util.Map elements); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String fieldName, String key); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(String mapField, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String mapField, String key); + method public com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.FunctionExpr mod(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.FunctionExpr multiply(String fieldName, Object other); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); @@ -1278,78 +1289,69 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, String pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, String pattern); - method public com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public com.google.firebase.firestore.pipeline.Function replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); - method public com.google.firebase.firestore.pipeline.Function replaceAll(String fieldName, String find, String replace); - method public com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public com.google.firebase.firestore.pipeline.Function replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); - method public com.google.firebase.firestore.pipeline.Function replaceFirst(String fieldName, String find, String replace); - method public com.google.firebase.firestore.pipeline.Function reverse(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.Function reverse(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(String fieldName, String find, String replace); + method public com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(String fieldName, String find, String replace); + method public com.google.firebase.firestore.pipeline.FunctionExpr reverse(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.FunctionExpr reverse(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, String prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); - method public com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); - method public com.google.firebase.firestore.pipeline.Function strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); - method public com.google.firebase.firestore.pipeline.Function strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); - method public com.google.firebase.firestore.pipeline.Function strConcat(String fieldName, java.lang.Object... rest); + method public com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); + method public com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); + method public com.google.firebase.firestore.pipeline.FunctionExpr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); + method public com.google.firebase.firestore.pipeline.FunctionExpr strConcat(String fieldName, java.lang.Object... rest); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, String substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); - method public com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Function subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Function subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Function subtract(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public com.google.firebase.firestore.pipeline.Function timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); - method public com.google.firebase.firestore.pipeline.Function timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public com.google.firebase.firestore.pipeline.Function timestampAdd(String fieldName, String unit, double amount); - method public com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public com.google.firebase.firestore.pipeline.Function timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); - method public com.google.firebase.firestore.pipeline.Function timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public com.google.firebase.firestore.pipeline.Function timestampSub(String fieldName, String unit, double amount); - method public com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.Function timestampToUnixMicros(String fieldName); - method public com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.Function timestampToUnixMillis(String fieldName); - method public com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.Function timestampToUnixSeconds(String fieldName); - method public com.google.firebase.firestore.pipeline.Function toLower(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.Function toLower(String fieldName); - method public com.google.firebase.firestore.pipeline.Function toUpper(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.Function toUpper(String fieldName); - method public com.google.firebase.firestore.pipeline.Function trim(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.Function trim(String fieldName); - method public com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.Function unixMicrosToTimestamp(String fieldName); - method public com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.Function unixMillisToTimestamp(String fieldName); - method public com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.Function unixSecondsToTimestamp(String fieldName); - method public com.google.firebase.firestore.pipeline.Function vectorLength(com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.Function vectorLength(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.FunctionExpr subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.FunctionExpr subtract(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String fieldName, String unit, double amount); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String fieldName, String unit, double amount); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr toLower(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.FunctionExpr toLower(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr toUpper(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.FunctionExpr toUpper(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr trim(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.FunctionExpr trim(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(String fieldName); + method public com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); } - public final class GenericOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { - field public static final com.google.firebase.firestore.pipeline.GenericOptions.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.GenericOptions DEFAULT; - } - - public static final class GenericOptions.Companion { - } - - public final class GenericStage extends com.google.firebase.firestore.pipeline.Stage { - method public static com.google.firebase.firestore.pipeline.GenericStage of(String name); + public final class GenericStage extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.GenericStage ofName(String name); method public com.google.firebase.firestore.pipeline.GenericStage withArguments(java.lang.Object... arguments); - method public com.google.firebase.firestore.pipeline.GenericStage withOptions(com.google.firebase.firestore.pipeline.GenericOptions options); field public static final com.google.firebase.firestore.pipeline.GenericStage.Companion Companion; } public static final class GenericStage.Companion { - method public com.google.firebase.firestore.pipeline.GenericStage of(String name); + method public com.google.firebase.firestore.pipeline.GenericStage ofName(String name); } public final class Ordering { @@ -1370,7 +1372,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Ordering descending(String fieldName); } - public final class SampleStage extends com.google.firebase.firestore.pipeline.Stage { + public final class SampleStage extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.SampleStage withDocLimit(int documents); method public static com.google.firebase.firestore.pipeline.SampleStage withPercentage(double percentage); field public static final com.google.firebase.firestore.pipeline.SampleStage.Companion Companion; @@ -1396,18 +1398,27 @@ package com.google.firebase.firestore.pipeline { ctor public Selectable(); } - public abstract class Stage { + public abstract class Stage> { method protected final String getName(); + method public final T with(String key, boolean value); + method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); + method public final T with(String key, double value); + method protected final T with(String key, error.NonExistentClass value); + method public final T with(String key, String value); + method public final T with(String key, long value); property protected final String name; } - public final class UnnestOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { - method public com.google.firebase.firestore.pipeline.UnnestOptions withIndexField(String indexField); - field public static final com.google.firebase.firestore.pipeline.UnnestOptions.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.UnnestOptions DEFAULT; + public final class UnnestStage extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.UnnestStage withField(com.google.firebase.firestore.pipeline.Selectable arrayWithAlias); + method public static com.google.firebase.firestore.pipeline.UnnestStage withField(String arrayField, String alias); + method public com.google.firebase.firestore.pipeline.UnnestStage withIndexField(String indexField); + field public static final com.google.firebase.firestore.pipeline.UnnestStage.Companion Companion; } - public static final class UnnestOptions.Companion { + public static final class UnnestStage.Companion { + method public com.google.firebase.firestore.pipeline.UnnestStage withField(com.google.firebase.firestore.pipeline.Selectable arrayWithAlias); + method public com.google.firebase.firestore.pipeline.UnnestStage withField(String arrayField, String alias); } } From 39c9bd7a698070ef5093da5d90b1085f1368cd0a Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 10 Apr 2025 19:23:58 -0400 Subject: [PATCH 40/77] fix --- .../java/com/google/firebase/firestore/core/Query.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index e3045ea2aec..ff832879af3 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -563,15 +563,17 @@ public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataR if (hasLimit()) { // TODO: Handle situation where user enters limit larger than integer. if (limitType == LimitType.LIMIT_TO_FIRST) { - p = p.sort(orderings.toArray(Ordering[]::new)); + p = p.sort(orderings.get(0), orderings.stream().skip(1).toArray(Ordering[]::new)); p = p.limit((int) limit); } else { - p = p.sort(orderings.stream().map(Ordering::reverse).toArray(Ordering[]::new)); + p = p.sort( + orderings.get(0).reverse(), + orderings.stream().skip(1).map(Ordering::reverse).toArray(Ordering[]::new)); p = p.limit((int) limit); - p = p.sort(orderings.toArray(Ordering[]::new)); + p = p.sort(orderings.get(0), orderings.stream().skip(1).toArray(Ordering[]::new)); } } else { - p = p.sort(orderings.toArray(Ordering[]::new)); + p = p.sort(orderings.get(0), orderings.stream().skip(1).toArray(Ordering[]::new)); } return p; From ea780f82116c929506dfa55964cb4ffecf295bab Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 15 Apr 2025 10:40:27 -0400 Subject: [PATCH 41/77] fixups --- .../firebase/firestore/PipelineTest.java | 136 +-- .../testutil/IntegrationTestUtil.java | 2 +- .../firebase/firestore/AggregateField.java | 7 +- .../com/google/firebase/firestore/Pipeline.kt | 27 +- .../firebase/firestore/core/FieldFilter.java | 2 +- .../google/firebase/firestore/core/Query.java | 8 +- .../firebase/firestore/pipeline/Constant.kt | 182 ---- .../firebase/firestore/pipeline/aggregates.kt | 2 +- .../firestore/pipeline/expressions.kt | 848 ++++++++++-------- .../firebase/firestore/pipeline/options.kt | 177 +++- .../firebase/firestore/pipeline/stage.kt | 17 +- 11 files changed, 771 insertions(+), 637 deletions(-) delete mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index cd4fc945221..fbca6febc6b 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -15,25 +15,27 @@ package com.google.firebase.firestore; import static com.google.common.truth.Truth.assertThat; -import static com.google.firebase.firestore.pipeline.FunctionExpr.add; -import static com.google.firebase.firestore.pipeline.FunctionExpr.and; -import static com.google.firebase.firestore.pipeline.FunctionExpr.arrayContains; -import static com.google.firebase.firestore.pipeline.FunctionExpr.arrayContainsAny; -import static com.google.firebase.firestore.pipeline.FunctionExpr.cosineDistance; -import static com.google.firebase.firestore.pipeline.FunctionExpr.endsWith; -import static com.google.firebase.firestore.pipeline.FunctionExpr.eq; -import static com.google.firebase.firestore.pipeline.FunctionExpr.euclideanDistance; -import static com.google.firebase.firestore.pipeline.FunctionExpr.gt; -import static com.google.firebase.firestore.pipeline.FunctionExpr.logicalMax; -import static com.google.firebase.firestore.pipeline.FunctionExpr.lt; -import static com.google.firebase.firestore.pipeline.FunctionExpr.lte; -import static com.google.firebase.firestore.pipeline.FunctionExpr.mapGet; -import static com.google.firebase.firestore.pipeline.FunctionExpr.neq; -import static com.google.firebase.firestore.pipeline.FunctionExpr.not; -import static com.google.firebase.firestore.pipeline.FunctionExpr.or; -import static com.google.firebase.firestore.pipeline.FunctionExpr.startsWith; -import static com.google.firebase.firestore.pipeline.FunctionExpr.strConcat; -import static com.google.firebase.firestore.pipeline.FunctionExpr.subtract; +import static com.google.firebase.firestore.pipeline.Expr.add; +import static com.google.firebase.firestore.pipeline.Expr.and; +import static com.google.firebase.firestore.pipeline.Expr.arrayContains; +import static com.google.firebase.firestore.pipeline.Expr.arrayContainsAny; +import static com.google.firebase.firestore.pipeline.Expr.cosineDistance; +import static com.google.firebase.firestore.pipeline.Expr.endsWith; +import static com.google.firebase.firestore.pipeline.Expr.eq; +import static com.google.firebase.firestore.pipeline.Expr.euclideanDistance; +import static com.google.firebase.firestore.pipeline.Expr.field; +import static com.google.firebase.firestore.pipeline.Expr.gt; +import static com.google.firebase.firestore.pipeline.Expr.logicalMax; +import static com.google.firebase.firestore.pipeline.Expr.lt; +import static com.google.firebase.firestore.pipeline.Expr.lte; +import static com.google.firebase.firestore.pipeline.Expr.mapGet; +import static com.google.firebase.firestore.pipeline.Expr.neq; +import static com.google.firebase.firestore.pipeline.Expr.not; +import static com.google.firebase.firestore.pipeline.Expr.or; +import static com.google.firebase.firestore.pipeline.Expr.startsWith; +import static com.google.firebase.firestore.pipeline.Expr.strConcat; +import static com.google.firebase.firestore.pipeline.Expr.subtract; +import static com.google.firebase.firestore.pipeline.Expr.vector; import static com.google.firebase.firestore.pipeline.Ordering.ascending; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.waitFor; @@ -44,9 +46,7 @@ import com.google.common.truth.Correspondence; import com.google.firebase.firestore.pipeline.AggregateFunction; import com.google.firebase.firestore.pipeline.AggregateStage; -import com.google.firebase.firestore.pipeline.Constant; -import com.google.firebase.firestore.pipeline.Field; -import com.google.firebase.firestore.pipeline.FunctionExpr; +import com.google.firebase.firestore.pipeline.Expr; import com.google.firebase.firestore.pipeline.GenericStage; import com.google.firebase.firestore.testutil.IntegrationTestUtil; import java.util.Collections; @@ -240,11 +240,11 @@ public void aggregateResultsMany() { firestore .pipeline() .collection(randomCol) - .where(FunctionExpr.eq("genre", "Science Fiction")) + .where(eq("genre", "Science Fiction")) .aggregate( AggregateFunction.countAll().alias("count"), AggregateFunction.avg("rating").alias("avgRating"), - Field.of("rating").max().alias("maxRating")) + field("rating").max().alias("maxRating")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -258,12 +258,12 @@ public void groupAndAccumulateResults() { firestore .pipeline() .collection(randomCol) - .where(lt(Field.of("published"), 1984)) + .where(lt(field("published"), 1984)) .aggregate( AggregateStage.withAccumulators(AggregateFunction.avg("rating").alias("avgRating")) .withGroups("genre")) .where(gt("avgRating", 4.3)) - .sort(Field.of("avgRating").descending()) + .sort(field("avgRating").descending()) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -279,13 +279,13 @@ public void groupAndAccumulateResultsGeneric() { firestore .pipeline() .collection(randomCol) - .genericStage("where", lt(Field.of("published"), 1984)) + .genericStage("where", lt(field("published"), 1984)) .genericStage( "aggregate", ImmutableMap.of("avgRating", AggregateFunction.avg("rating")), - ImmutableMap.of("genre", Field.of("genre"))) + ImmutableMap.of("genre", field("genre"))) .genericStage(GenericStage.ofName("where").withArguments(gt("avgRating", 4.3))) - .genericStage("sort", Field.of("avgRating").descending()) + .genericStage("sort", field("avgRating").descending()) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -304,8 +304,8 @@ public void minAndMaxAccumulations() { .collection(randomCol) .aggregate( AggregateFunction.countAll().alias("count"), - Field.of("rating").max().alias("maxRating"), - Field.of("published").min().alias("minPublished")) + field("rating").max().alias("maxRating"), + field("published").min().alias("minPublished")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -320,7 +320,7 @@ public void canSelectFields() { .pipeline() .collection(randomCol) .select("title", "author") - .sort(Field.of("author").ascending()) + .sort(field("author").ascending()) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -431,7 +431,7 @@ public void arrayContainsAllWorks() { firestore .pipeline() .collection(randomCol) - .where(Field.of("tags").arrayContainsAll(ImmutableList.of("adventure", "magic"))) + .where(field("tags").arrayContainsAll(ImmutableList.of("adventure", "magic"))) .select("title") .execute(); assertThat(waitFor(execute).getResults()) @@ -445,7 +445,7 @@ public void arrayLengthWorks() { firestore .pipeline() .collection(randomCol) - .select(Field.of("tags").arrayLength().alias("tagsCount")) + .select(field("tags").arrayLength().alias("tagsCount")) .where(eq("tagsCount", 3)) .execute(); assertThat(waitFor(execute).getResults()).hasSize(10); @@ -460,7 +460,7 @@ public void arrayConcatWorks() { .collection(randomCol) .where(eq("title", "The Hitchhiker's Guide to the Galaxy")) .select( - Field.of("tags") + field("tags") .arrayConcat(ImmutableList.of("newTag1", "newTag2")) .alias("modifiedTags")) .limit(1) @@ -479,7 +479,7 @@ public void testStrConcat() { firestore .pipeline() .collection(randomCol) - .select(Field.of("author").strConcat(" - ", Field.of("title")).alias("bookInfo")) + .select(field("author").strConcat(" - ", field("title")).alias("bookInfo")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -496,7 +496,7 @@ public void testStartsWith() { .collection(randomCol) .where(startsWith("title", "The")) .select("title") - .sort(Field.of("title").ascending()) + .sort(field("title").ascending()) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -515,7 +515,7 @@ public void testEndsWith() { .collection(randomCol) .where(endsWith("title", "y")) .select("title") - .sort(Field.of("title").descending()) + .sort(field("title").descending()) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -530,9 +530,9 @@ public void testLength() { firestore .pipeline() .collection(randomCol) - .select(Field.of("title").charLength().alias("titleLength"), Field.of("title")) + .select(field("title").charLength().alias("titleLength"), field("title")) .where(gt("titleLength", 20)) - .sort(Field.of("title").ascending()) + .sort(field("title").ascending()) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -550,7 +550,7 @@ public void testToLowercase() { firestore .pipeline() .collection(randomCol) - .select(Field.of("title").toLower().alias("lowercaseTitle")) + .select(field("title").toLower().alias("lowercaseTitle")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -565,7 +565,7 @@ public void testToUppercase() { firestore .pipeline() .collection(randomCol) - .select(Field.of("author").toLower().alias("uppercaseAuthor")) + .select(field("author").toLower().alias("uppercaseAuthor")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -580,8 +580,8 @@ public void testTrim() { firestore .pipeline() .collection(randomCol) - .addFields(strConcat(" ", Field.of("title"), " ").alias("spacedTitle")) - .select(Field.of("spacedTitle").trim().alias("trimmedTitle")) + .addFields(strConcat(" ", field("title"), " ").alias("spacedTitle")) + .select(field("spacedTitle").trim().alias("trimmedTitle")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -600,7 +600,7 @@ public void testLike() { firestore .pipeline() .collection(randomCol) - .where(FunctionExpr.like("title", "%Guide%")) + .where(Expr.like("title", "%Guide%")) .select("title") .execute(); assertThat(waitFor(execute).getResults()) @@ -614,7 +614,7 @@ public void testRegexContains() { firestore .pipeline() .collection(randomCol) - .where(FunctionExpr.regexContains("title", "(?i)(the|of)")) + .where(Expr.regexContains("title", "(?i)(the|of)")) .execute(); assertThat(waitFor(execute).getResults()).hasSize(5); } @@ -625,7 +625,7 @@ public void testRegexMatches() { firestore .pipeline() .collection(randomCol) - .where(FunctionExpr.regexContains("title", ".*(?i)(the|of).*")) + .where(Expr.regexContains("title", ".*(?i)(the|of).*")) .execute(); assertThat(waitFor(execute).getResults()).hasSize(5); } @@ -637,10 +637,10 @@ public void testArithmeticOperations() { .pipeline() .collection(randomCol) .select( - add(Field.of("rating"), 1).alias("ratingPlusOne"), - subtract(Field.of("published"), 1900).alias("yearsSince1900"), - Field.of("rating").multiply(10).alias("ratingTimesTen"), - Field.of("rating").divide(2).alias("ratingDividedByTwo")) + add(field("rating"), 1).alias("ratingPlusOne"), + subtract(field("published"), 1900).alias("yearsSince1900"), + field("rating").multiply(10).alias("ratingTimesTen"), + field("rating").divide(2).alias("ratingDividedByTwo")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -662,10 +662,10 @@ public void testComparisonOperators() { .where( and( gt("rating", 4.2), - lte(Field.of("rating"), 4.5), + lte(field("rating"), 4.5), neq("genre", "Science Function"))) .select("rating", "title") - .sort(Field.of("title").ascending()) + .sort(field("title").ascending()) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -684,9 +684,9 @@ public void testLogicalOperators() { .where( or( and(gt("rating", 4.5), eq("genre", "Science Fiction")), - lt(Field.of("published"), 1900))) + lt(field("published"), 1900))) .select("title") - .sort(Field.of("title").ascending()) + .sort(field("title").ascending()) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -702,11 +702,11 @@ public void testChecks() { firestore .pipeline() .collection(randomCol) - .where(not(Field.of("rating").isNan())) + .where(not(field("rating").isNan())) .select( - Field.of("rating").isNull().alias("ratingIsNull"), - Field.of("rating").eq(Constant.nullValue()).alias("ratingEqNull"), - not(Field.of("rating").isNan()).alias("ratingIsNotNan")) + field("rating").isNull().alias("ratingIsNull"), + field("rating").eq(Expr.nullValue()).alias("ratingEqNull"), + not(field("rating").isNan()).alias("ratingIsNotNan")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) @@ -725,10 +725,10 @@ public void testLogicalMax() { firestore .pipeline() .collection(randomCol) - .where(Field.of("author").eq("Douglas Adams")) + .where(field("author").eq("Douglas Adams")) .select( - Field.of("rating").logicalMax(4.5).alias("max_rating"), - logicalMax(Field.of("published"), 1900).alias("max_published")) + field("rating").logicalMax(4.5).alias("max_rating"), + logicalMax(field("published"), 1900).alias("max_published")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -739,7 +739,7 @@ public void testLogicalMax() { @Ignore("Not supported yet") public void testLogicalMin() { Task execute = - firestore.pipeline().collection(randomCol).sort(Field.of("rating").ascending()).execute(); + firestore.pipeline().collection(randomCol).sort(field("rating").ascending()).execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) .containsExactly(ImmutableMap.of("min_rating", 4.2, "min_published", 1900)); @@ -751,7 +751,7 @@ public void testMapGet() { firestore .pipeline() .collection(randomCol) - .select(Field.of("awards").mapGet("hugo").alias("hugoAward"), Field.of("title")) + .select(field("awards").mapGet("hugo").alias("hugoAward"), field("title")) .where(eq("hugoAward", true)) .execute(); assertThat(waitFor(execute).getResults()) @@ -770,10 +770,10 @@ public void testDistanceFunctions() { .pipeline() .collection(randomCol) .select( - cosineDistance(Constant.vector(sourceVector), targetVector).alias("cosineDistance"), - FunctionExpr.dotProduct(Constant.vector(sourceVector), targetVector) + cosineDistance(vector(sourceVector), targetVector).alias("cosineDistance"), + Expr.dotProduct(vector(sourceVector), targetVector) .alias("dotProductDistance"), - euclideanDistance(Constant.vector(sourceVector), targetVector) + euclideanDistance(vector(sourceVector), targetVector) .alias("euclideanDistance")) .limit(1) .execute(); @@ -811,7 +811,7 @@ public void testMapGetWithFieldNameIncludingNotation() { .where(eq("awards.hugo", true)) .select( "title", - Field.of("nestedField.level.1"), + field("nestedField.level.1"), mapGet("nestedField", "level.1").mapGet("level.2").alias("nested")) .execute(); assertThat(waitFor(execute).getResults()) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java index e94fb3baf35..bea8743e0ba 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java @@ -569,7 +569,7 @@ public static void checkOnlineAndOfflineResultsMatch(Query query, String... expe public static void checkQueryAndPipelineResultsMatch(Query query, String... expectedDocs) { QuerySnapshot docsFromQuery = waitFor(query.get(Source.SERVER)); PipelineSnapshot docsFromPipeline = - waitFor(query.getFirestore().pipeline().createFrom(query).execute()); + waitFor(query.getFirestore().pipeline().convertFrom(query).execute()); assertEquals(querySnapshotToIds(docsFromQuery), pipelineSnapshotToIds(docsFromPipeline)); List expected = asList(expectedDocs); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java index d26f82ea7c2..a053a8d038a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/AggregateField.java @@ -14,12 +14,13 @@ package com.google.firebase.firestore; +import static com.google.firebase.firestore.pipeline.Expr.field; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RestrictTo; import com.google.firebase.firestore.pipeline.AggregateFunction; import com.google.firebase.firestore.pipeline.AggregateWithAlias; -import com.google.firebase.firestore.pipeline.Field; import java.util.Objects; /** Represents an aggregation that can be performed by Firestore. */ @@ -218,7 +219,7 @@ private SumAggregateField(@NonNull FieldPath fieldPath) { @NonNull @Override AggregateWithAlias toPipeline() { - return Field.of(getFieldPath()).sum().alias(getAlias()); + return field(getFieldPath()).sum().alias(getAlias()); } } @@ -231,7 +232,7 @@ private AverageAggregateField(@NonNull FieldPath fieldPath) { @NonNull @Override AggregateWithAlias toPipeline() { - return Field.of(getFieldPath()).avg().alias(getAlias()); + return field(getFieldPath()).avg().alias(getAlias()); } } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 1cf45215a80..23ff5a5ba19 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableList import com.google.firebase.Timestamp import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.Values +import com.google.firebase.firestore.pipeline.AbstractOptions import com.google.firebase.firestore.pipeline.AddFieldsStage import com.google.firebase.firestore.pipeline.AggregateFunction import com.google.firebase.firestore.pipeline.AggregateStage @@ -38,9 +39,11 @@ import com.google.firebase.firestore.pipeline.FindNearestStage import com.google.firebase.firestore.pipeline.FunctionExpr import com.google.firebase.firestore.pipeline.GenericArg import com.google.firebase.firestore.pipeline.GenericStage +import com.google.firebase.firestore.pipeline.InternalOptions import com.google.firebase.firestore.pipeline.LimitStage import com.google.firebase.firestore.pipeline.OffsetStage import com.google.firebase.firestore.pipeline.Ordering +import com.google.firebase.firestore.pipeline.PipelineOptions import com.google.firebase.firestore.pipeline.RemoveFieldsStage import com.google.firebase.firestore.pipeline.ReplaceStage import com.google.firebase.firestore.pipeline.SampleStage @@ -72,9 +75,11 @@ internal constructor( return Pipeline(firestore, userDataReader, stages.append(stage)) } - fun execute(): Task { + fun execute(): Task = execute(PipelineOptions.DEFAULT) + + fun execute(options: PipelineOptions): Task { val observerTask = ObserverSnapshotTask() - firestore.callClient { call -> call!!.executePipeline(toProto(), observerTask) } + firestore.callClient { call -> call!!.executePipeline(toProto(options), observerTask) } return observerTask.task } @@ -82,7 +87,7 @@ internal constructor( return DocumentReference(key, firestore) } - private fun toProto(): ExecutePipelineRequest { + private fun toProto(options: PipelineOptions): ExecutePipelineRequest { val database = firestore.databaseId val builder = ExecutePipelineRequest.newBuilder() builder.database = "projects/${database.projectId}/databases/${database.databaseId}" @@ -169,7 +174,7 @@ internal constructor( */ fun removeFields(field: String, vararg additionalFields: String): Pipeline = append( - RemoveFieldsStage(arrayOf(Field.of(field), *additionalFields.map(Field::of).toTypedArray())) + RemoveFieldsStage(arrayOf(Expr.field(field), *additionalFields.map(Expr::field).toTypedArray())) ) /** @@ -221,7 +226,7 @@ internal constructor( append( SelectStage( arrayOf( - Field.of(fieldName), + Expr.field(fieldName), *additionalSelections.map(Selectable::toSelectable).toTypedArray() ) ) @@ -253,10 +258,10 @@ internal constructor( * You can filter documents based on their field values, using implementations of [BooleanExpr], * typically including but not limited to: * - * - field comparators: [FunctionExpr.eq], [FunctionExpr.lt] (less than), [FunctionExpr.gt] + * - field comparators: [Expr.eq], [Expr.lt] (less than), [Expr.gt] * (greater than), etc. - * - logical operators: [FunctionExpr.and], [FunctionExpr.or], [FunctionExpr.not], etc. - * - advanced functions: [FunctionExpr.regexMatch], [FunctionExpr.arrayContains[], etc. + * - logical operators: [Expr.and], [Expr.or], [Expr.not], etc. + * - advanced functions: [Expr.regexMatch], [Expr.arrayContains], etc. * * @param condition The [BooleanExpr] to apply. * @return A new [Pipeline] object with this stage appended to the stage list. @@ -336,7 +341,7 @@ internal constructor( append( DistinctStage( arrayOf( - Field.of(groupField), + Expr.field(groupField), *additionalGroups.map(Selectable::toSelectable).toTypedArray() ) ) @@ -468,7 +473,7 @@ internal constructor( * @param field The [String] specifying the field name containing the nested map. * @return A new [Pipeline] object with this stage appended to the stage list. */ - fun replace(field: String): Pipeline = replace(Field.of(field)) + fun replace(field: String): Pipeline = replace(Expr.field(field)) /** * Fully overwrites all fields in a document with those coming from a nested map. @@ -530,7 +535,7 @@ internal constructor( * @return A new [Pipeline] object with this stage appended to the stage list. */ fun unnest(arrayField: String, alias: String): Pipeline = - unnest(Field.of(arrayField).alias(alias)) + unnest(Expr.field(arrayField).alias(alias)) /** * Takes a specified array from the input documents and outputs a document for each element with diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java index cc3c5402eb6..20dd9ad585a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java @@ -14,7 +14,7 @@ package com.google.firebase.firestore.core; -import static com.google.firebase.firestore.pipeline.FunctionExpr.and; +import static com.google.firebase.firestore.pipeline.Expr.and; import static com.google.firebase.firestore.util.Assert.hardAssert; import static java.lang.Double.isNaN; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index ff832879af3..3607f584a2a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -14,8 +14,8 @@ package com.google.firebase.firestore.core; -import static com.google.firebase.firestore.pipeline.FunctionExpr.and; -import static com.google.firebase.firestore.pipeline.FunctionExpr.or; +import static com.google.firebase.firestore.pipeline.Expr.and; +import static com.google.firebase.firestore.pipeline.Expr.or; import static com.google.firebase.firestore.util.Assert.hardAssert; import androidx.annotation.NonNull; @@ -547,7 +547,7 @@ public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataR p = p.where(fields.get(0).exists()); } else { BooleanExpr[] conditions = - fields.stream().skip(1).map(Expr::exists).toArray(BooleanExpr[]::new); + fields.stream().skip(1).map(Expr.Companion::exists).toArray(BooleanExpr[]::new); p = p.where(and(fields.get(0).exists(), conditions)); } @@ -587,7 +587,7 @@ private static BooleanExpr whereConditionsFromCursor( int last = size - 1; BooleanExpr condition = cmp.apply(fields.get(last), boundPosition.get(last)); if (bound.isInclusive()) { - condition = or(condition, FunctionExpr.eq(fields.get(last), boundPosition.get(last))); + condition = or(condition, Expr.eq(fields.get(last), boundPosition.get(last))); } for (int i = size - 2; i >= 0; i--) { final Field field = fields.get(i); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt deleted file mode 100644 index 1e5c47da1f9..00000000000 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/Constant.kt +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2025 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.firebase.firestore.pipeline - -import com.google.firebase.Timestamp -import com.google.firebase.firestore.Blob -import com.google.firebase.firestore.DocumentReference -import com.google.firebase.firestore.GeoPoint -import com.google.firebase.firestore.UserDataReader -import com.google.firebase.firestore.VectorValue -import com.google.firebase.firestore.model.Values -import com.google.firebase.firestore.model.Values.encodeValue -import com.google.firestore.v1.Value -import java.util.Date - -/** - * Represents a constant value that can be used in a Firestore pipeline expression. - * - * You can create a [Constant] instance using the static [of] method: - */ -abstract class Constant internal constructor() : Expr() { - - private class ValueConstant(val value: Value) : Constant() { - override fun toProto(userDataReader: UserDataReader): Value = value - } - - companion object { - internal val NULL: Constant = ValueConstant(Values.NULL_VALUE) - - internal fun of(value: Value): Constant { - return ValueConstant(value) - } - - /** - * Create a [Constant] instance for a [String] value. - * - * @param value The [String] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun of(value: String): Constant { - return ValueConstant(encodeValue(value)) - } - - /** - * Create a [Constant] instance for a [Number] value. - * - * @param value The [Number] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun of(value: Number): Constant { - return ValueConstant(encodeValue(value)) - } - - /** - * Create a [Constant] instance for a [Date] value. - * - * @param value The [Date] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun of(value: Date): Constant { - return ValueConstant(encodeValue(value)) - } - - /** - * Create a [Constant] instance for a [Timestamp] value. - * - * @param value The [Timestamp] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun of(value: Timestamp): Constant { - return ValueConstant(encodeValue(value)) - } - - /** - * Create a [Constant] instance for a [Boolean] value. - * - * @param value The [Boolean] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun of(value: Boolean): Constant { - return ValueConstant(encodeValue(value)) - } - - /** - * Create a [Constant] instance for a [GeoPoint] value. - * - * @param value The [GeoPoint] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun of(value: GeoPoint): Constant { - return ValueConstant(encodeValue(value)) - } - - /** - * Create a [Constant] instance for a [Blob] value. - * - * @param value The [Blob] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun of(value: Blob): Constant { - return ValueConstant(encodeValue(value)) - } - - /** - * Create a [Constant] instance for a [DocumentReference] value. - * - * @param ref The [DocumentReference] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun of(ref: DocumentReference): Constant { - return object : Constant() { - override fun toProto(userDataReader: UserDataReader): Value { - userDataReader.validateDocumentReference(ref, ::IllegalArgumentException) - return encodeValue(ref) - } - } - } - - /** - * Create a [Constant] instance for a [VectorValue] value. - * - * @param value The [VectorValue] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun of(value: VectorValue): Constant { - return ValueConstant(encodeValue(value)) - } - - /** - * [Constant] instance for a null value. - * - * @return A [Constant] instance. - */ - @JvmStatic - fun nullValue(): Constant { - return NULL - } - - /** - * Create a vector [Constant] instance for a [DoubleArray] value. - * - * @param vector The [VectorValue] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun vector(vector: DoubleArray): Constant { - return ValueConstant(Values.encodeVectorValue(vector)) - } - - /** - * Create a vector [Constant] instance for a [VectorValue] value. - * - * @param vector The [VectorValue] value. - * @return A new [Constant] instance. - */ - @JvmStatic - fun vector(vector: VectorValue): Constant { - return ValueConstant(encodeValue(vector)) - } - } -} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt index afcb2797df2..bdc5707388b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt @@ -25,7 +25,7 @@ class AggregateFunction private constructor(private val name: String, private val params: Array) { private constructor(name: String) : this(name, emptyArray()) private constructor(name: String, expr: Expr) : this(name, arrayOf(expr)) - private constructor(name: String, fieldName: String) : this(name, Field.of(fieldName)) + private constructor(name: String, fieldName: String) : this(name, Expr.field(fieldName)) companion object { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 87c7bca250c..eaa59645cb3 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -23,9 +23,9 @@ import com.google.firebase.firestore.Pipeline import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.VectorValue import com.google.firebase.firestore.model.DocumentKey +import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.FieldPath as ModelFieldPath import com.google.firebase.firestore.model.Values.encodeValue -import com.google.firebase.firestore.pipeline.Constant.Companion.of import com.google.firebase.firestore.util.CustomClassMapper import com.google.firestore.v1.MapValue import com.google.firestore.v1.Value @@ -41,14 +41,17 @@ import kotlin.reflect.KFunction1 * - **Field references:** Access values from document fields. * - **Literals:** Represent constant values (strings, numbers, booleans). * - **Function calls:** Apply functions to one or more expressions. - * - **Aggregations:** Calculate aggregate values (e.g., sum, average) over a set of documents. * * The [Expr] class provides a fluent API for building expressions. You can chain together method * calls to create complex expressions. */ abstract class Expr internal constructor() { - internal companion object { + private class ValueConstant(val value: Value) : Expr() { + override fun toProto(userDataReader: UserDataReader): Value = value + } + + companion object { internal fun toExprOrConstant(value: Any?): Expr = toExpr(value, ::toExprOrConstant) ?: pojoToExprOrConstant(CustomClassMapper.convertToPlainJavaTypes(value)) @@ -58,25 +61,25 @@ abstract class Expr internal constructor() { ?: throw IllegalArgumentException("Unknown type: $value") private fun toExpr(value: Any?, toExpr: KFunction1): Expr? { - if (value == null) return Constant.nullValue() + if (value == null) return NULL return when (value) { is Expr -> value - is String -> of(value) - is Number -> of(value) - is Date -> of(value) - is Timestamp -> of(value) - is Boolean -> of(value) - is GeoPoint -> of(value) - is Blob -> of(value) - is DocumentReference -> of(value) - is VectorValue -> of(value) - is Value -> of(value) + is String -> constant(value) + is Number -> constant(value) + is Date -> constant(value) + is Timestamp -> constant(value) + is Boolean -> constant(value) + is GeoPoint -> constant(value) + is Blob -> constant(value) + is DocumentReference -> constant(value) + is VectorValue -> constant(value) + is Value -> ValueConstant(value) is Map<*, *> -> - FunctionExpr.map( + map( value .flatMap { val key = it.key - if (key is String) listOf(of(key), toExpr(it.value)) + if (key is String) listOf(constant(key), toExpr(it.value)) else throw IllegalArgumentException("Maps with non-string keys are not supported") } .toTypedArray() @@ -91,311 +94,144 @@ abstract class Expr internal constructor() { internal fun toArrayOfExprOrConstant(others: Array): Array = others.map(::toExprOrConstant).toTypedArray() - } - - fun bitAnd(right: Expr) = FunctionExpr.bitAnd(this, right) - - fun bitAnd(right: Any) = FunctionExpr.bitAnd(this, right) - - fun bitOr(right: Expr) = FunctionExpr.bitOr(this, right) - - fun bitOr(right: Any) = FunctionExpr.bitOr(this, right) - - fun bitXor(right: Expr) = FunctionExpr.bitXor(this, right) - - fun bitXor(right: Any) = FunctionExpr.bitXor(this, right) - - fun bitNot() = FunctionExpr.bitNot(this) - - fun bitLeftShift(numberExpr: Expr) = FunctionExpr.bitLeftShift(this, numberExpr) - - fun bitLeftShift(number: Int) = FunctionExpr.bitLeftShift(this, number) - - fun bitRightShift(numberExpr: Expr) = FunctionExpr.bitRightShift(this, numberExpr) - - fun bitRightShift(number: Int) = FunctionExpr.bitRightShift(this, number) - - /** - * Assigns an alias to this expression. - * - *

Aliases are useful for renaming fields in the output of a stage or for giving meaningful - * names to calculated values. - * - *

Example: - * - *

 // Calculate the total price and assign it the alias "totalPrice" and add it to the
-   *
-   * output. firestore.pipeline().collection("items")
-   * .addFields(Field.of("price").multiply(Field.of("quantity")).as("totalPrice")); 
- * - * @param alias The alias to assign to this expression. - * @return A new [Selectable] (typically an [ExprWithAlias]) that wraps this expression and - * associates it with the provided alias. - */ - open fun alias(alias: String) = ExprWithAlias(alias, this) - - /** - * Creates an expression that this expression to another expression. - * - *

Example: - * - *

{@code // Add the value of the 'quantity' field and the 'reserve' field.
-   * Field.of("quantity").add(Field.of("reserve")); }
- * - * @param other The expression to add to this expression. - * @return A new {@code Expr} representing the addition operation. - */ - fun add(other: Expr) = FunctionExpr.add(this, other) - - /** - * Creates an expression that this expression to another expression. - * - *

Example: - * - *

{@code // Add the value of the 'quantity' field and the 'reserve' field.
-   * Field.of("quantity").add(Field.of("reserve")); }
- * - * @param other The constant value to add to this expression. - * @return A new {@code Expr} representing the addition operation. - */ - fun add(other: Any) = FunctionExpr.add(this, other) - - fun subtract(other: Expr) = FunctionExpr.subtract(this, other) - - fun subtract(other: Any) = FunctionExpr.subtract(this, other) - - fun multiply(other: Expr) = FunctionExpr.multiply(this, other) - - fun multiply(other: Any) = FunctionExpr.multiply(this, other) - - fun divide(other: Expr) = FunctionExpr.divide(this, other) - - fun divide(other: Any) = FunctionExpr.divide(this, other) - - fun mod(other: Expr) = FunctionExpr.mod(this, other) - - fun mod(other: Any) = FunctionExpr.mod(this, other) - - fun eqAny(values: List) = FunctionExpr.eqAny(this, values) - - fun notEqAny(values: List) = FunctionExpr.notEqAny(this, values) - - fun isNan() = FunctionExpr.isNan(this) - - fun isNotNan() = FunctionExpr.isNotNan(this) - - fun isNull() = FunctionExpr.isNull(this) - - fun isNotNull() = FunctionExpr.isNotNull(this) - - fun replaceFirst(find: Expr, replace: Expr) = FunctionExpr.replaceFirst(this, find, replace) - - fun replaceFirst(find: String, replace: String) = FunctionExpr.replaceFirst(this, find, replace) - - fun replaceAll(find: Expr, replace: Expr) = FunctionExpr.replaceAll(this, find, replace) - - fun replaceAll(find: String, replace: String) = FunctionExpr.replaceAll(this, find, replace) - - fun charLength() = FunctionExpr.charLength(this) - - fun byteLength() = FunctionExpr.byteLength(this) - - fun like(pattern: Expr) = FunctionExpr.like(this, pattern) - - fun like(pattern: String) = FunctionExpr.like(this, pattern) - - fun regexContains(pattern: Expr) = FunctionExpr.regexContains(this, pattern) - - fun regexContains(pattern: String) = FunctionExpr.regexContains(this, pattern) - - fun regexMatch(pattern: Expr) = FunctionExpr.regexMatch(this, pattern) - - fun regexMatch(pattern: String) = FunctionExpr.regexMatch(this, pattern) - - fun logicalMax(other: Expr) = FunctionExpr.logicalMax(this, other) - - fun logicalMax(other: Any) = FunctionExpr.logicalMax(this, other) - - fun logicalMin(other: Expr) = FunctionExpr.logicalMin(this, other) - - fun logicalMin(other: Any) = FunctionExpr.logicalMin(this, other) - - fun reverse() = FunctionExpr.reverse(this) - - fun strContains(substring: Expr) = FunctionExpr.strContains(this, substring) - - fun strContains(substring: String) = FunctionExpr.strContains(this, substring) - - fun startsWith(prefix: Expr) = FunctionExpr.startsWith(this, prefix) - - fun startsWith(prefix: String) = FunctionExpr.startsWith(this, prefix) - - fun endsWith(suffix: Expr) = FunctionExpr.endsWith(this, suffix) - - fun endsWith(suffix: String) = FunctionExpr.endsWith(this, suffix) - - fun toLower() = FunctionExpr.toLower(this) - - fun toUpper() = FunctionExpr.toUpper(this) - - fun trim() = FunctionExpr.trim(this) - - fun strConcat(vararg expr: Expr) = FunctionExpr.strConcat(this, *expr) - - fun strConcat(vararg string: String) = FunctionExpr.strConcat(this, *string) - - fun strConcat(vararg string: Any) = FunctionExpr.strConcat(this, *string) - - fun mapGet(key: Expr) = FunctionExpr.mapGet(this, key) - - fun mapGet(key: String) = FunctionExpr.mapGet(this, key) - - fun mapMerge(secondMap: Expr, vararg otherMaps: Expr) = - FunctionExpr.mapMerge(this, secondMap, *otherMaps) - - fun mapRemove(key: Expr) = FunctionExpr.mapRemove(this, key) - - fun mapRemove(key: String) = FunctionExpr.mapRemove(this, key) - - fun cosineDistance(vector: Expr) = FunctionExpr.cosineDistance(this, vector) - - fun cosineDistance(vector: DoubleArray) = FunctionExpr.cosineDistance(this, vector) - - fun cosineDistance(vector: VectorValue) = FunctionExpr.cosineDistance(this, vector) - - fun dotProduct(vector: Expr) = FunctionExpr.dotProduct(this, vector) - - fun dotProduct(vector: DoubleArray) = FunctionExpr.dotProduct(this, vector) - - fun dotProduct(vector: VectorValue) = FunctionExpr.dotProduct(this, vector) - - fun euclideanDistance(vector: Expr) = FunctionExpr.euclideanDistance(this, vector) - - fun euclideanDistance(vector: DoubleArray) = FunctionExpr.euclideanDistance(this, vector) - - fun euclideanDistance(vector: VectorValue) = FunctionExpr.euclideanDistance(this, vector) - - fun vectorLength() = FunctionExpr.vectorLength(this) - - fun unixMicrosToTimestamp() = FunctionExpr.unixMicrosToTimestamp(this) - - fun timestampToUnixMicros() = FunctionExpr.timestampToUnixMicros(this) - - fun unixMillisToTimestamp() = FunctionExpr.unixMillisToTimestamp(this) - - fun timestampToUnixMillis() = FunctionExpr.timestampToUnixMillis(this) - - fun unixSecondsToTimestamp() = FunctionExpr.unixSecondsToTimestamp(this) - - fun timestampToUnixSeconds() = FunctionExpr.timestampToUnixSeconds(this) - - fun timestampAdd(unit: Expr, amount: Expr) = FunctionExpr.timestampAdd(this, unit, amount) - - fun timestampAdd(unit: String, amount: Double) = FunctionExpr.timestampAdd(this, unit, amount) - - fun timestampSub(unit: Expr, amount: Expr) = FunctionExpr.timestampSub(this, unit, amount) - - fun timestampSub(unit: String, amount: Double) = FunctionExpr.timestampSub(this, unit, amount) - - fun arrayConcat(vararg arrays: Expr) = FunctionExpr.arrayConcat(this, *arrays) - - fun arrayConcat(arrays: List) = FunctionExpr.arrayConcat(this, arrays) - fun arrayReverse() = FunctionExpr.arrayReverse(this) + private val NULL: Expr = ValueConstant(Values.NULL_VALUE) - fun arrayContains(value: Expr) = FunctionExpr.arrayContains(this, value) - - fun arrayContains(value: Any) = FunctionExpr.arrayContains(this, value) - - fun arrayContainsAll(values: List) = FunctionExpr.arrayContainsAll(this, values) - - fun arrayContainsAny(values: List) = FunctionExpr.arrayContainsAny(this, values) - - fun arrayLength() = FunctionExpr.arrayLength(this) - - fun sum() = AggregateFunction.sum(this) - - fun avg() = AggregateFunction.avg(this) - - fun min() = AggregateFunction.min(this) - - fun max() = AggregateFunction.max(this) - - fun ascending() = Ordering.ascending(this) - - fun descending() = Ordering.descending(this) - - fun eq(other: Expr) = FunctionExpr.eq(this, other) - - fun eq(other: Any) = FunctionExpr.eq(this, other) - - fun neq(other: Expr) = FunctionExpr.neq(this, other) - - fun neq(other: Any) = FunctionExpr.neq(this, other) - - fun gt(other: Expr) = FunctionExpr.gt(this, other) - - fun gt(other: Any) = FunctionExpr.gt(this, other) - - fun gte(other: Expr) = FunctionExpr.gte(this, other) - - fun gte(other: Any) = FunctionExpr.gte(this, other) - - fun lt(other: Expr) = FunctionExpr.lt(this, other) + /** + * Create a constant for a [String] value. + * + * @param value The [String] value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(value: String): Expr { + return ValueConstant(encodeValue(value)) + } - fun lt(other: Any) = FunctionExpr.lt(this, other) + /** + * Create a constant for a [Number] value. + * + * @param value The [Number] value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(value: Number): Expr { + return ValueConstant(encodeValue(value)) + } - fun lte(other: Expr) = FunctionExpr.lte(this, other) + /** + * Create a constant for a [Date] value. + * + * @param value The [Date] value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(value: Date): Expr { + return ValueConstant(encodeValue(value)) + } - fun lte(other: Any) = FunctionExpr.lte(this, other) + /** + * Create a constant for a [Timestamp] value. + * + * @param value The [Timestamp] value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(value: Timestamp): Expr { + return ValueConstant(encodeValue(value)) + } - fun exists() = FunctionExpr.exists(this) + /** + * Create a constant for a [Boolean] value. + * + * @param value The [Boolean] value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(value: Boolean): Expr { + return ValueConstant(encodeValue(value)) + } - internal abstract fun toProto(userDataReader: UserDataReader): Value -} + /** + * Create a constant for a [GeoPoint] value. + * + * @param value The [GeoPoint] value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(value: GeoPoint): Expr { + return ValueConstant(encodeValue(value)) + } -/** Expressions that have an alias are [Selectable] */ -abstract class Selectable : Expr() { - internal abstract fun getAlias(): String - internal abstract fun getExpr(): Expr + /** + * Create a constant for a [Blob] value. + * + * @param value The [Blob] value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(value: Blob): Expr { + return ValueConstant(encodeValue(value)) + } - internal companion object { - fun toSelectable(o: Any): Selectable { - return when (o) { - is Selectable -> o - is String -> Field.of(o) - is FieldPath -> Field.of(o) - else -> throw IllegalArgumentException("Unknown Selectable type: $o") + /** + * Create a constant for a [DocumentReference] value. + * + * @param ref The [DocumentReference] value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(ref: DocumentReference): Expr { + return object : Expr() { + override fun toProto(userDataReader: UserDataReader): Value { + userDataReader.validateDocumentReference(ref, ::IllegalArgumentException) + return encodeValue(ref) + } } } - } -} -/** Represents an expression that will be given the alias in the output document. */ -class ExprWithAlias internal constructor(private val alias: String, private val expr: Expr) : - Selectable() { - override fun getAlias() = alias - override fun getExpr() = expr - override fun toProto(userDataReader: UserDataReader): Value = expr.toProto(userDataReader) -} + /** + * Create a constant for a [VectorValue] value. + * + * @param value The [VectorValue] value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(value: VectorValue): Expr { + return ValueConstant(encodeValue(value)) + } -/** - * Represents a reference to a field in a Firestore document. - * - * [Field] references are used to access document field values in expressions and to specify fields - * for sorting, filtering, and projecting data in Firestore pipelines. - * - * You can create a [Field] instance using the static [of] method: - */ -class Field internal constructor(private val fieldPath: ModelFieldPath) : Selectable() { - companion object { + /** + * Constant for a null value. + * + * @return A [Expr] constant instance. + */ + @JvmStatic + fun nullValue(): Expr { + return NULL + } /** - * An expression that returns the document ID. + * Create a vector constant for a [DoubleArray] value. * - * @return An [Field] representing the document ID. + * @param vector The [VectorValue] value. + * @return A [Expr] constant instance. */ - @JvmField val DOCUMENT_ID: Field = of(FieldPath.documentId()) + @JvmStatic + fun vector(vector: DoubleArray): Expr { + return ValueConstant(Values.encodeVectorValue(vector)) + } + + /** + * Create a vector constant for a [VectorValue] value. + * + * @param vector The [VectorValue] value. + * @return A [Expr] constant instance. + */ + @JvmStatic + fun vector(vector: VectorValue): Expr { + return ValueConstant(encodeValue(vector)) + } /** * Creates a [Field] instance representing the field at the given path. @@ -407,7 +243,7 @@ class Field internal constructor(private val fieldPath: ModelFieldPath) : Select * @return A new [Field] instance representing the specified path. */ @JvmStatic - fun of(name: String): Field { + fun field(name: String): Field { if (name == DocumentKey.KEY_FIELD_NAME) { return Field(ModelFieldPath.KEY_PATH) } @@ -424,47 +260,9 @@ class Field internal constructor(private val fieldPath: ModelFieldPath) : Select * @return A new [Field] instance representing the specified path. */ @JvmStatic - fun of(fieldPath: FieldPath): Field { + fun field(fieldPath: FieldPath): Field { return Field(fieldPath.internalPath) } - } - - override fun getAlias(): String = fieldPath.canonicalString() - - override fun getExpr(): Expr = this - - override fun toProto(userDataReader: UserDataReader) = toProto() - - internal fun toProto(): Value = - Value.newBuilder().setFieldReferenceValue(fieldPath.canonicalString()).build() -} - -internal class ListOfExprs(private val expressions: Array) : Expr() { - override fun toProto(userDataReader: UserDataReader): Value = - encodeValue(expressions.map { it.toProto(userDataReader) }) -} - -/** - * This class defines the base class for Firestore [Pipeline] functions, which can be evaluated - * within pipeline execution. - * - * Typically, you would not use this class or its children directly. Use either the functions like - * [and], [eq], or the methods on [Expr] ([Expr.eq]), [Expr.lt], etc) to construct new - * [FunctionExpr] instances. - */ -open class FunctionExpr -protected constructor(private val name: String, private val params: Array) : Expr() { - private constructor( - name: String, - param: Expr, - vararg params: Any - ) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) - private constructor( - name: String, - fieldName: String, - vararg params: Any - ) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) - companion object { @JvmStatic fun generic(name: String, vararg expr: Expr) = FunctionExpr(name, expr) @@ -781,7 +579,7 @@ protected constructor(private val name: String, private val params: Array) = - map(elements.flatMap { listOf(of(it.key), toExprOrConstant(it.value)) }.toTypedArray()) + map(elements.flatMap { listOf(constant(it.key), toExprOrConstant(it.value)) }.toTypedArray()) @JvmStatic fun mapGet(map: Expr, key: Expr) = FunctionExpr("map_get", map, key) @@ -816,7 +614,7 @@ protected constructor(private val name: String, private val params: ArrayAliases are useful for renaming fields in the output of a stage or for giving meaningful + * names to calculated values. + * + *

Example: + * + *

 // Calculate the total price and assign it the alias "totalPrice" and add it to the
+   *
+   * output. firestore.pipeline().collection("items")
+   * .addFields(Expr.field("price").multiply(Expr.field("quantity")).as("totalPrice")); 
+ * + * @param alias The alias to assign to this expression. + * @return A new [Selectable] (typically an [ExprWithAlias]) that wraps this expression and + * associates it with the provided alias. + */ + open fun alias(alias: String) = ExprWithAlias(alias, this) + + /** + * Creates an expression that this expression to another expression. + * + *

Example: + * + *

{@code // Add the value of the 'quantity' field and the 'reserve' field.
+   * Expr.field("quantity").add(Expr.field("reserve")); }
+ * + * @param other The expression to add to this expression. + * @return A new {@code Expr} representing the addition operation. + */ + fun add(other: Expr) = add(this, other) + + /** + * Creates an expression that this expression to another expression. + * + *

Example: + * + *

{@code // Add the value of the 'quantity' field and the 'reserve' field.
+   * Expr.field("quantity").add(Expr.field("reserve")); }
+ * + * @param other The constant value to add to this expression. + * @return A new {@code Expr} representing the addition operation. + */ + fun add(other: Any) = add(this, other) + + fun subtract(other: Expr) = subtract(this, other) + + fun subtract(other: Any) = subtract(this, other) + + fun multiply(other: Expr) = multiply(this, other) + + fun multiply(other: Any) = multiply(this, other) + + fun divide(other: Expr) = divide(this, other) + + fun divide(other: Any) = divide(this, other) + + fun mod(other: Expr) = mod(this, other) + + fun mod(other: Any) = mod(this, other) + + fun eqAny(values: List) = eqAny(this, values) + + fun notEqAny(values: List) = notEqAny(this, values) + + fun isNan() = isNan(this) + + fun isNotNan() = isNotNan(this) + + fun isNull() = isNull(this) + + fun isNotNull() = isNotNull(this) + + fun replaceFirst(find: Expr, replace: Expr) = replaceFirst(this, find, replace) + + fun replaceFirst(find: String, replace: String) = replaceFirst(this, find, replace) + + fun replaceAll(find: Expr, replace: Expr) = replaceAll(this, find, replace) + + fun replaceAll(find: String, replace: String) = replaceAll(this, find, replace) + + fun charLength() = charLength(this) + + fun byteLength() = byteLength(this) + + fun like(pattern: Expr) = like(this, pattern) + + fun like(pattern: String) = like(this, pattern) + + fun regexContains(pattern: Expr) = regexContains(this, pattern) + + fun regexContains(pattern: String) = regexContains(this, pattern) + + fun regexMatch(pattern: Expr) = regexMatch(this, pattern) + + fun regexMatch(pattern: String) = regexMatch(this, pattern) + + fun logicalMax(other: Expr) = logicalMax(this, other) + + fun logicalMax(other: Any) = logicalMax(this, other) + + fun logicalMin(other: Expr) = logicalMin(this, other) + + fun logicalMin(other: Any) = logicalMin(this, other) + + fun reverse() = reverse(this) + + fun strContains(substring: Expr) = strContains(this, substring) + + fun strContains(substring: String) = strContains(this, substring) + + fun startsWith(prefix: Expr) = startsWith(this, prefix) + + fun startsWith(prefix: String) = startsWith(this, prefix) + + fun endsWith(suffix: Expr) = endsWith(this, suffix) + + fun endsWith(suffix: String) = endsWith(this, suffix) + + fun toLower() = toLower(this) + + fun toUpper() = toUpper(this) + + fun trim() = trim(this) + + fun strConcat(vararg expr: Expr) = Companion.strConcat(this, *expr) + + fun strConcat(vararg string: String) = strConcat(this, *string) + + fun strConcat(vararg string: Any) = Companion.strConcat(this, *string) + + fun mapGet(key: Expr) = mapGet(this, key) + + fun mapGet(key: String) = mapGet(this, key) + + fun mapMerge(secondMap: Expr, vararg otherMaps: Expr) = + Companion.mapMerge(this, secondMap, *otherMaps) + + fun mapRemove(key: Expr) = mapRemove(this, key) + + fun mapRemove(key: String) = mapRemove(this, key) + + fun cosineDistance(vector: Expr) = cosineDistance(this, vector) + + fun cosineDistance(vector: DoubleArray) = cosineDistance(this, vector) + + fun cosineDistance(vector: VectorValue) = cosineDistance(this, vector) + + fun dotProduct(vector: Expr) = dotProduct(this, vector) + + fun dotProduct(vector: DoubleArray) = dotProduct(this, vector) + + fun dotProduct(vector: VectorValue) = dotProduct(this, vector) + + fun euclideanDistance(vector: Expr) = euclideanDistance(this, vector) + + fun euclideanDistance(vector: DoubleArray) = euclideanDistance(this, vector) + + fun euclideanDistance(vector: VectorValue) = euclideanDistance(this, vector) + + fun vectorLength() = vectorLength(this) + + fun unixMicrosToTimestamp() = unixMicrosToTimestamp(this) + + fun timestampToUnixMicros() = timestampToUnixMicros(this) + + fun unixMillisToTimestamp() = unixMillisToTimestamp(this) + + fun timestampToUnixMillis() = timestampToUnixMillis(this) + + fun unixSecondsToTimestamp() = unixSecondsToTimestamp(this) + + fun timestampToUnixSeconds() = timestampToUnixSeconds(this) + + fun timestampAdd(unit: Expr, amount: Expr) = timestampAdd(this, unit, amount) + + fun timestampAdd(unit: String, amount: Double) = timestampAdd(this, unit, amount) + + fun timestampSub(unit: Expr, amount: Expr) = timestampSub(this, unit, amount) + + fun timestampSub(unit: String, amount: Double) = timestampSub(this, unit, amount) + + fun arrayConcat(vararg arrays: Expr) = Companion.arrayConcat(this, *arrays) + + fun arrayConcat(arrays: List) = arrayConcat(this, arrays) + + fun arrayReverse() = arrayReverse(this) + + fun arrayContains(value: Expr) = arrayContains(this, value) + + fun arrayContains(value: Any) = arrayContains(this, value) + + fun arrayContainsAll(values: List) = arrayContainsAll(this, values) + + fun arrayContainsAny(values: List) = arrayContainsAny(this, values) + + fun arrayLength() = arrayLength(this) + + fun sum() = AggregateFunction.sum(this) + + fun avg() = AggregateFunction.avg(this) + + fun min() = AggregateFunction.min(this) + + fun max() = AggregateFunction.max(this) + + fun ascending() = Ordering.ascending(this) + + fun descending() = Ordering.descending(this) + + fun eq(other: Expr) = eq(this, other) + + fun eq(other: Any) = eq(this, other) + + fun neq(other: Expr) = neq(this, other) + + fun neq(other: Any) = neq(this, other) + + fun gt(other: Expr) = gt(this, other) + + fun gt(other: Any) = gt(this, other) + + fun gte(other: Expr) = gte(this, other) + + fun gte(other: Any) = gte(this, other) + + fun lt(other: Expr) = lt(this, other) + + fun lt(other: Any) = lt(this, other) + + fun lte(other: Expr) = lte(this, other) + + fun lte(other: Any) = lte(this, other) + + fun exists() = exists(this) + + internal abstract fun toProto(userDataReader: UserDataReader): Value +} + +/** Expressions that have an alias are [Selectable] */ +abstract class Selectable : Expr() { + internal abstract fun getAlias(): String + internal abstract fun getExpr(): Expr + + internal companion object { + fun toSelectable(o: Any): Selectable { + return when (o) { + is Selectable -> o + is String -> Expr.field(o) + is FieldPath -> Expr.field(o) + else -> throw IllegalArgumentException("Unknown Selectable type: $o") + } + } + } +} + +/** Represents an expression that will be given the alias in the output document. */ +class ExprWithAlias internal constructor(private val alias: String, private val expr: Expr) : + Selectable() { + override fun getAlias() = alias + override fun getExpr() = expr + override fun toProto(userDataReader: UserDataReader): Value = expr.toProto(userDataReader) +} + +/** + * Represents a reference to a field in a Firestore document. + * + * [Field] references are used to access document field values in expressions and to specify fields + * for sorting, filtering, and projecting data in Firestore pipelines. + * + * You can create a [Field] instance using the static [Expr.field] method: + */ +class Field internal constructor(private val fieldPath: ModelFieldPath) : Selectable() { + companion object { + + /** + * An expression that returns the document ID. + * + * @return An [Field] representing the document ID. + */ + @JvmField val DOCUMENT_ID: Field = field(FieldPath.documentId()) + + } + + override fun getAlias(): String = fieldPath.canonicalString() + + override fun getExpr(): Expr = this + + override fun toProto(userDataReader: UserDataReader) = toProto() + + internal fun toProto(): Value = + Value.newBuilder().setFieldReferenceValue(fieldPath.canonicalString()).build() +} + +internal class ListOfExprs(private val expressions: Array) : Expr() { + override fun toProto(userDataReader: UserDataReader): Value = + encodeValue(expressions.map { it.toProto(userDataReader) }) +} + +/** + * This class defines the base class for Firestore [Pipeline] functions, which can be evaluated + * within pipeline execution. + * + * Typically, you would not use this class or its children directly. Use either the functions like + * [and], [eq], or the methods on [Expr] ([Expr.eq]), [Expr.lt], etc) to construct new + * [FunctionExpr] instances. + */ +open class FunctionExpr +internal constructor(private val name: String, private val params: Array) : Expr() { + internal constructor( + name: String, + param: Expr, + vararg params: Any + ) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) + internal constructor( + name: String, + fieldName: String, + vararg params: Any + ) : this(name, arrayOf(Expr.field(fieldName), *toArrayOfExprOrConstant(params))) + override fun toProto(userDataReader: UserDataReader): Value { val builder = com.google.firestore.v1.Function.newBuilder() builder.setName(name) @@ -1096,7 +1236,7 @@ class BooleanExpr internal constructor(name: String, params: Array) : name: String, fieldName: String, vararg params: Any - ) : this(name, arrayOf(Field.of(fieldName), *toArrayOfExprOrConstant(params))) + ) : this(name, arrayOf(Expr.field(fieldName), *toArrayOfExprOrConstant(params))) companion object { @@ -1135,7 +1275,7 @@ class Ordering private constructor(val expr: Expr, private val dir: Direction) { * @return A new [Ordering] object with ascending sort by field. */ @JvmStatic - fun ascending(fieldName: String): Ordering = Ordering(Field.of(fieldName), Direction.ASCENDING) + fun ascending(fieldName: String): Ordering = Ordering(Expr.field(fieldName), Direction.ASCENDING) /** * Create an [Ordering] that sorts documents in descending order based on value of [expr]. @@ -1153,7 +1293,7 @@ class Ordering private constructor(val expr: Expr, private val dir: Direction) { */ @JvmStatic fun descending(fieldName: String): Ordering = - Ordering(Field.of(fieldName), Direction.DESCENDING) + Ordering(Expr.field(fieldName), Direction.DESCENDING) } private class Direction private constructor(val proto: Value) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt index af3853f2f4a..300d770c337 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt @@ -15,6 +15,7 @@ package com.google.firebase.firestore.pipeline import com.google.common.collect.ImmutableMap +import com.google.firebase.firestore.model.Values import com.google.firestore.v1.ArrayValue import com.google.firestore.v1.MapValue import com.google.firestore.v1.Value @@ -27,7 +28,7 @@ import com.google.firestore.v1.Value * `ImmutableMap, Value>` is an implementation detail, not to be exposed, since * more efficient implementations are possible. */ -internal class InternalOptions +class InternalOptions internal constructor(private val options: ImmutableMap) { internal fun with(key: String, value: Value): InternalOptions { val builder = ImmutableMap.builderWithExpectedSize(options.size + 1) @@ -56,11 +57,179 @@ internal constructor(private val options: ImmutableMap) { return Value.newBuilder().setMapValue(mapValue).build() } - internal companion object { - internal val EMPTY: InternalOptions = InternalOptions(ImmutableMap.of()) + companion object { + @JvmField + val EMPTY: InternalOptions = InternalOptions(ImmutableMap.of()) - internal fun of(key: String, value: Value): InternalOptions { + fun of(key: String, value: Value): InternalOptions { return InternalOptions(ImmutableMap.of(key, value)) } } } + +abstract class AbstractOptions> +internal constructor(internal val options: InternalOptions) { + + internal abstract fun self(options: InternalOptions): T + + protected fun with(key: String, value: InternalOptions): T = self(options.with(key, value)) + + protected fun with(key: String, value: Value): T = self(options.with(key, value)) + + /** + * Specify generic [String] option + * + * @param key The option key + * @param value The [String] value of option + * @return A new options object. + */ + fun with(key: String, value: String): T = with(key, Values.encodeValue(value)) + + /** + * Specify generic [Boolean] option + * + * @param key The option key + * @param value The [Boolean] value of option + * @return A new options object. + */ + fun with(key: String, value: Boolean): T = with(key, Values.encodeValue(value)) + + /** + * Specify generic [Long] option + * + * @param key The option key + * @param value The [Long] value of option + * @return A new options object. + */ + fun with(key: String, value: Long): T = with(key, Values.encodeValue(value)) + + /** + * Specify generic [Double] option + * + * @param key The option key + * @param value The [Double] value of option + * @return A new options object. + */ + fun with(key: String, value: Double): T = with(key, Values.encodeValue(value)) + + /** + * Specify generic [Field] option + * + * @param key The option key + * @param value The [Field] value of option + * @return A new options object. + */ + fun with(key: String, value: Field): T = with(key, value.toProto()) + + /** + * Specify [GenericOptions] object + * + * @param key The option key + * @param value The [GenericOptions] object + * @return A new options object. + */ + fun with(key: String, value: GenericOptions): T = with(key, value.options) +} + +class GenericOptions private constructor(options: InternalOptions) : AbstractOptions(options) { + override fun self(options: InternalOptions) = GenericOptions(options) + + companion object { + @JvmField + val DEFAULT: GenericOptions = GenericOptions(InternalOptions.EMPTY) + } +} + +class PipelineOptions private constructor(options: InternalOptions) : AbstractOptions(options) { + + override fun self(options: InternalOptions) = PipelineOptions(options) + + companion object { + @JvmField + val DEFAULT: PipelineOptions = PipelineOptions(InternalOptions.EMPTY) + } + + class IndexMode private constructor(internal val value: String) { + companion object { + @JvmField + val RECOMMENDED = IndexMode("recommended") + } + } + + fun withIndexMode(indexMode: IndexMode): PipelineOptions = + with("index_mode", indexMode.value) + + fun withExplainOptions(options: ExplainOptions): PipelineOptions = + with("explain_options", options.options) +} + +class ExplainOptions private constructor(options: InternalOptions) : AbstractOptions(options) { + override fun self(options: InternalOptions) = ExplainOptions(options) + + companion object { + @JvmField + val DEFAULT = ExplainOptions(InternalOptions.EMPTY) + } + + fun withMode(value: ExplainMode) = with("mode", value.value) + + fun withOutputFormat(value: OutputFormat) = with("output_format", value.value) + + fun withVerbosity(value: Verbosity) = with("verbosity", value.value) + + fun withIndexRecommendation(value: Boolean) = with("index_recommendation", value) + + fun withProfiles(value: Profiles) = with("profiles", value.value) + + fun withRedact(value: Boolean) = with("redact", value) + + class ExplainMode private constructor(internal val value: String) { + companion object { + @JvmField + val EXECUTE = ExplainMode("execute") + + @JvmField + val EXPLAIN = ExplainMode("explain") + + @JvmField + val ANALYZE = ExplainMode("analyze") + } + } + + class OutputFormat private constructor(internal val value: String) { + companion object { + @JvmField + val TEXT = OutputFormat("text") + + @JvmField + val JSON = OutputFormat("json") + + @JvmField + val STRUCT = OutputFormat("struct") + } + } + + class Verbosity private constructor(internal val value: String) { + companion object { + @JvmField + val SUMMARY_ONLY = Verbosity("summary_only") + + @JvmField + val EXECUTION_TREE = Verbosity("execution_tree") + } + } + + class Profiles private constructor(internal val value: String) { + companion object { + @JvmField + val LATENCY = Profiles("latency") + + @JvmField + val RECORDS_COUNT = Profiles("records_count") + + @JvmField + val BYTES_THROUGHPUT = Profiles("bytes_throughput") + } + } +} + diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index 57293c47bad..6eedcb2fd4a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -18,7 +18,8 @@ import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.VectorValue import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.Values.encodeValue -import com.google.firebase.firestore.pipeline.Field.Companion.of +import com.google.firebase.firestore.pipeline.Expr.Companion.constant +import com.google.firebase.firestore.pipeline.Expr.Companion.field import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value @@ -266,7 +267,7 @@ internal constructor( * @return [AggregateStage] with specified groups. */ fun withGroups(groupField: String, vararg additionalGroups: Any) = - withGroups(Field.of(groupField), additionalGroups) + withGroups(Expr.field(groupField), additionalGroups) /** * Add one or more groups to [AggregateStage] @@ -327,7 +328,7 @@ internal constructor( */ @JvmStatic fun of(vectorField: Field, vectorValue: VectorValue, distanceMeasure: DistanceMeasure) = - FindNearestStage(vectorField, Constant.of(vectorValue), distanceMeasure) + FindNearestStage(vectorField, constant(vectorValue), distanceMeasure) /** * Create [FindNearestStage]. @@ -341,7 +342,7 @@ internal constructor( */ @JvmStatic fun of(vectorField: Field, vectorValue: DoubleArray, distanceMeasure: DistanceMeasure) = - FindNearestStage(vectorField, Constant.vector(vectorValue), distanceMeasure) + FindNearestStage(vectorField, Expr.vector(vectorValue), distanceMeasure) /** * Create [FindNearestStage]. @@ -355,7 +356,7 @@ internal constructor( */ @JvmStatic fun of(vectorField: String, vectorValue: VectorValue, distanceMeasure: DistanceMeasure) = - FindNearestStage(Constant.of(vectorField), Constant.of(vectorValue), distanceMeasure) + FindNearestStage(constant(vectorField), constant(vectorValue), distanceMeasure) /** * Create [FindNearestStage]. @@ -369,7 +370,7 @@ internal constructor( */ @JvmStatic fun of(vectorField: String, vectorValue: DoubleArray, distanceMeasure: DistanceMeasure) = - FindNearestStage(Constant.of(vectorField), Constant.vector(vectorValue), distanceMeasure) + FindNearestStage(constant(vectorField), Expr.vector(vectorValue), distanceMeasure) } class DistanceMeasure private constructor(internal val proto: Value) { @@ -418,7 +419,7 @@ internal constructor( * @return [FindNearestStage] with specified [distanceField]. */ fun withDistanceField(distanceField: String): FindNearestStage = - withDistanceField(of(distanceField)) + withDistanceField(field(distanceField)) } internal class LimitStage @@ -598,7 +599,7 @@ internal constructor( */ @JvmStatic fun withField(arrayField: String, alias: String): UnnestStage = - UnnestStage(Field.of(arrayField).alias(alias)) + UnnestStage(Expr.field(arrayField).alias(alias)) } override fun self(options: InternalOptions) = UnnestStage(selectable, options) override fun args(userDataReader: UserDataReader): Sequence = From dd2e9bdb522729844bae04ba6e0c3b154c2e4fbd Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 15 Apr 2025 15:51:41 -0400 Subject: [PATCH 42/77] add named options to CollectionSource and CollectionGroupSource --- .../com/google/firebase/firestore/Pipeline.kt | 57 ++++++++-------- .../google/firebase/firestore/core/Query.java | 9 +-- .../firebase/firestore/pipeline/stage.kt | 68 ++++++++++++++++--- 3 files changed, 94 insertions(+), 40 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 23ff5a5ba19..cc61160f405 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableList import com.google.firebase.Timestamp import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.Values -import com.google.firebase.firestore.pipeline.AbstractOptions import com.google.firebase.firestore.pipeline.AddFieldsStage import com.google.firebase.firestore.pipeline.AggregateFunction import com.google.firebase.firestore.pipeline.AggregateStage @@ -39,7 +38,6 @@ import com.google.firebase.firestore.pipeline.FindNearestStage import com.google.firebase.firestore.pipeline.FunctionExpr import com.google.firebase.firestore.pipeline.GenericArg import com.google.firebase.firestore.pipeline.GenericStage -import com.google.firebase.firestore.pipeline.InternalOptions import com.google.firebase.firestore.pipeline.LimitStage import com.google.firebase.firestore.pipeline.OffsetStage import com.google.firebase.firestore.pipeline.Ordering @@ -54,7 +52,6 @@ import com.google.firebase.firestore.pipeline.Stage import com.google.firebase.firestore.pipeline.UnionStage import com.google.firebase.firestore.pipeline.UnnestStage import com.google.firebase.firestore.pipeline.WhereStage -import com.google.firebase.firestore.util.Preconditions import com.google.firestore.v1.ExecutePipelineRequest import com.google.firestore.v1.StructuredPipeline import com.google.firestore.v1.Value @@ -614,7 +611,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto * Convert the given Query into an equivalent Pipeline. * * @param query A Query to be converted into a Pipeline. - * @return Pipeline that is equivalent to [query] + * @return A new [Pipeline] object that is equivalent to [query] * @throws [IllegalArgumentException] Thrown if the [query] provided targets a different project * or database than the pipeline. */ @@ -629,7 +626,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto * Convert the given Aggregate Query into an equivalent Pipeline. * * @param aggregateQuery An Aggregate Query to be converted into a Pipeline. - * @return Pipeline that is equivalent to [aggregateQuery] + * @return A new [Pipeline] object that is equivalent to [aggregateQuery] * @throws [IllegalArgumentException] Thrown if the [aggregateQuery] provided targets a different * project or database than the pipeline. */ @@ -646,46 +643,50 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto * Set the pipeline's source to the collection specified by the given path. * * @param path A path to a collection that will be the source of this pipeline. - * @return Pipeline with documents from target collection. + * @return A new [Pipeline] object with documents from target collection. */ - fun collection(path: String): Pipeline = - // Validate path by converting to CollectionReference - collection(firestore.collection(path)) + fun collection(path: String): Pipeline = collection(CollectionSource.of(path)) /** - * Set the pipeline's source to the collection specified by the given CollectionReference. + * Set the pipeline's source to the collection specified by the given [CollectionReference]. * - * @param ref A CollectionReference for a collection that will be the source of this pipeline. - * @return Pipeline with documents from target collection. + * @param ref A [CollectionReference] for a collection that will be the source of this pipeline. + * @return A new [Pipeline] object with documents from target collection. * @throws [IllegalArgumentException] Thrown if the [ref] provided targets a different project or * database than the pipeline. */ - fun collection(ref: CollectionReference): Pipeline { - if (ref.firestore.databaseId != firestore.databaseId) { - throw IllegalArgumentException( - "Provided collection reference is from a different Firestore instance." - ) + fun collection(ref: CollectionReference): Pipeline = collection(CollectionSource.of(ref)) + + /** + * Set the pipeline's source to the collection specified by CollectionSource. + * + * @param stage A [CollectionSource] that will be the source of this pipeline. + * @return Pipeline with documents from target collection. + * @throws [IllegalArgumentException] Thrown if the [stage] provided targets a different project + * or database than the pipeline. + */ + fun collection(stage: CollectionSource): Pipeline { + if (stage.firestore != null && stage.firestore.databaseId != firestore.databaseId) { + throw IllegalArgumentException("Provided collection is from a different Firestore instance.") } - return Pipeline(firestore, firestore.userDataReader, CollectionSource(ref.path)) + return Pipeline(firestore, firestore.userDataReader, stage) } /** * Set the pipeline's source to the collection group with the given id. * - * @param collectionid The id of a collection group that will be the source of this pipeline. + * @param collectionId The id of a collection group that will be the source of this pipeline. */ - fun collectionGroup(collectionId: String): Pipeline { - Preconditions.checkNotNull(collectionId, "Provided collection ID must not be null.") - require(!collectionId.contains("/")) { - "Invalid collectionId '$collectionId'. Collection IDs must not contain '/'." - } - return Pipeline(firestore, firestore.userDataReader, CollectionGroupSource(collectionId)) - } + fun collectionGroup(collectionId: String): Pipeline = + pipeline(CollectionGroupSource.of((collectionId))) + + fun pipeline(stage: CollectionGroupSource): Pipeline = + Pipeline(firestore, firestore.userDataReader, stage) /** * Set the pipeline's source to be all documents in this database. * - * @return Pipeline with all documents in this database. + * @return A new [Pipeline] object with all documents in this database. */ fun database(): Pipeline = Pipeline(firestore, firestore.userDataReader, DatabaseSource()) @@ -694,7 +695,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto * * @param documents Paths specifying the individual documents that will be the source of this * pipeline. - * @return Pipeline with [documents]. + * @return A new [Pipeline] object with [documents]. */ fun documents(vararg documents: String): Pipeline = // Validate document path by converting to DocumentReference diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index 3607f584a2a..08c3918b901 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -35,6 +35,7 @@ import com.google.firebase.firestore.pipeline.Expr; import com.google.firebase.firestore.pipeline.Field; import com.google.firebase.firestore.pipeline.FunctionExpr; +import com.google.firebase.firestore.pipeline.InternalOptions; import com.google.firebase.firestore.pipeline.Ordering; import com.google.firebase.firestore.pipeline.Stage; import com.google.firestore.v1.Value; @@ -521,7 +522,7 @@ private synchronized Target toTarget(List orderBys) { @NonNull public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataReader) { - Pipeline p = new Pipeline(firestore, userDataReader, pipelineSource()); + Pipeline p = new Pipeline(firestore, userDataReader, pipelineSource(firestore)); // Filters for (Filter filter : filters) { @@ -598,13 +599,13 @@ private static BooleanExpr whereConditionsFromCursor( } @NonNull - private Stage pipelineSource() { + private Stage pipelineSource(FirebaseFirestore firestore) { if (isDocumentQuery()) { return new DocumentsSource(path.canonicalString()); } else if (isCollectionGroupQuery()) { - return new CollectionGroupSource(collectionGroup); + return CollectionGroupSource.of(collectionGroup); } else { - return new CollectionSource(path.canonicalString()); + return new CollectionSource(path.canonicalString(), firestore, InternalOptions.EMPTY); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index 6eedcb2fd4a..cc930495eb3 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -14,12 +14,16 @@ package com.google.firebase.firestore.pipeline +import com.google.firebase.firestore.CollectionReference +import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.VectorValue +import com.google.firebase.firestore.model.ResourcePath import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.Values.encodeValue import com.google.firebase.firestore.pipeline.Expr.Companion.constant import com.google.firebase.firestore.pipeline.Expr.Companion.field +import com.google.firebase.firestore.util.Preconditions import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value @@ -93,7 +97,7 @@ internal constructor(protected val name: String, internal val options: InternalO * not implemented in the SDK version being used. */ class GenericStage -internal constructor( +private constructor( name: String, private val arguments: List, options: InternalOptions = InternalOptions.EMPTY @@ -168,24 +172,72 @@ internal constructor(options: InternalOptions = InternalOptions.EMPTY) : override fun args(userDataReader: UserDataReader): Sequence = emptySequence() } -internal class CollectionSource -@JvmOverloads -internal constructor(val path: String, options: InternalOptions = InternalOptions.EMPTY) : +class CollectionSource +internal constructor( + private val path: String, + // We validate [firestore.databaseId] when adding to pipeline. + internal val firestore: FirebaseFirestore?, + options: InternalOptions) : Stage("collection", options) { - override fun self(options: InternalOptions): CollectionSource = CollectionSource(path, options) + override fun self(options: InternalOptions): CollectionSource = CollectionSource(path, firestore, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf( Value.newBuilder().setReferenceValue(if (path.startsWith("/")) path else "/" + path).build() ) + companion object { + /** + * Set the pipeline's source to the collection specified by the given path. + * + * @param path A path to a collection that will be the source of this pipeline. + * @return Pipeline with documents from target collection. + */ + @JvmStatic + fun of(path: String): CollectionSource { + // Validate path by converting to ResourcePath + val resourcePath = ResourcePath.fromString(path) + return CollectionSource(resourcePath.canonicalString(), null, InternalOptions.EMPTY) + } + + /** + * Set the pipeline's source to the collection specified by the given CollectionReference. + * + * @param ref A CollectionReference for a collection that will be the source of this pipeline. + * @return Pipeline with documents from target collection. + */ + @JvmStatic + fun of(ref: CollectionReference): CollectionSource { + return CollectionSource(ref.path, ref.firestore, InternalOptions.EMPTY) + } + } + + fun withForceIndex(value: String) = with("force_index", value) } -internal class CollectionGroupSource -@JvmOverloads -internal constructor(val collectionId: String, options: InternalOptions = InternalOptions.EMPTY) : +class CollectionGroupSource +private constructor(private val collectionId: String, options: InternalOptions) : Stage("collection_group", options) { override fun self(options: InternalOptions) = CollectionGroupSource(collectionId, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setReferenceValue("").build(), encodeValue(collectionId)) + + companion object { + + /** + * Set the pipeline's source to the collection group with the given id. + * + * @param collectionId The id of a collection group that will be the source of this pipeline. + */ + @JvmStatic + fun of(collectionId: String): CollectionGroupSource { + Preconditions.checkNotNull(collectionId, "Provided collection ID must not be null.") + require(!collectionId.contains("/")) { + "Invalid collectionId '$collectionId'. Collection IDs must not contain '/'." + } + return CollectionGroupSource(collectionId, InternalOptions.EMPTY) + } + } + + fun withForceIndex(value: String) = with("force_index", value) } internal class DocumentsSource From 0231d720c221e00d4f2c8ea56daacdd62f33cca1 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 15 Apr 2025 16:08:07 -0400 Subject: [PATCH 43/77] spotless, apiTxt, use Expr types. --- firebase-firestore/api.txt | 996 ++++++++++-------- .../firebase/firestore/PipelineTest.java | 11 +- .../com/google/firebase/firestore/Pipeline.kt | 10 +- .../google/firebase/firestore/core/Query.java | 7 +- .../firestore/pipeline/expressions.kt | 292 ++--- .../firebase/firestore/pipeline/options.kt | 64 +- .../firebase/firestore/pipeline/stage.kt | 7 +- 7 files changed, 752 insertions(+), 635 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 78ce19cd2aa..592d2b24ba9 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -426,6 +426,7 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline distinct(com.google.firebase.firestore.pipeline.Selectable group, java.lang.Object... additionalGroups); method public com.google.firebase.firestore.Pipeline distinct(String groupField, java.lang.Object... additionalGroups); method public com.google.android.gms.tasks.Task execute(); + method public com.google.android.gms.tasks.Task execute(com.google.firebase.firestore.pipeline.PipelineOptions options); method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.FindNearestStage stage); @@ -474,6 +475,7 @@ package com.google.firebase.firestore { public final class PipelineSource { method public com.google.firebase.firestore.Pipeline collection(com.google.firebase.firestore.CollectionReference ref); + method public com.google.firebase.firestore.Pipeline collection(com.google.firebase.firestore.pipeline.CollectionSource stage); method public com.google.firebase.firestore.Pipeline collection(String path); method public com.google.firebase.firestore.Pipeline collectionGroup(String collectionId); method public com.google.firebase.firestore.Pipeline convertFrom(com.google.firebase.firestore.AggregateQuery aggregateQuery); @@ -481,6 +483,7 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline database(); method public com.google.firebase.firestore.Pipeline documents(com.google.firebase.firestore.DocumentReference... documents); method public com.google.firebase.firestore.Pipeline documents(java.lang.String... documents); + method public com.google.firebase.firestore.Pipeline pipeline(com.google.firebase.firestore.pipeline.CollectionGroupSource stage); } @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD}) public @interface PropertyName { @@ -675,6 +678,17 @@ package com.google.firebase.firestore.ktx { package com.google.firebase.firestore.pipeline { + public abstract class AbstractOptions> { + method public final T with(String key, boolean value); + method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); + method public final T with(String key, com.google.firebase.firestore.pipeline.GenericOptions value); + method protected final T with(String key, com.google.firebase.firestore.pipeline.InternalOptions value); + method public final T with(String key, double value); + method protected final T with(String key, error.NonExistentClass value); + method public final T with(String key, String value); + method public final T with(String key, long value); + } + public final class AggregateFunction { method public com.google.firebase.firestore.pipeline.AggregateWithAlias alias(String alias); method public static com.google.firebase.firestore.pipeline.AggregateFunction avg(com.google.firebase.firestore.pipeline.Expr expr); @@ -724,8 +738,8 @@ package com.google.firebase.firestore.pipeline { } public final class BooleanExpr extends com.google.firebase.firestore.pipeline.FunctionExpr { - method public com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); - method public com.google.firebase.firestore.pipeline.FunctionExpr cond(Object then, Object otherwise); + method public com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); + method public com.google.firebase.firestore.pipeline.Expr cond(Object then, Object otherwise); method public com.google.firebase.firestore.pipeline.AggregateFunction countIf(); method public static com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public com.google.firebase.firestore.pipeline.BooleanExpr not(); @@ -736,414 +750,425 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); } - public abstract class Constant extends com.google.firebase.firestore.pipeline.Expr { - method public static final com.google.firebase.firestore.pipeline.Constant nullValue(); - method public static final com.google.firebase.firestore.pipeline.Constant of(boolean value); - method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.Blob value); - method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.DocumentReference ref); - method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.GeoPoint value); - method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.VectorValue value); - method public static final com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.Timestamp value); - method public static final com.google.firebase.firestore.pipeline.Constant of(Number value); - method public static final com.google.firebase.firestore.pipeline.Constant of(String value); - method public static final com.google.firebase.firestore.pipeline.Constant of(java.util.Date value); - method public static final com.google.firebase.firestore.pipeline.Constant vector(com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.Constant vector(double[] vector); - field public static final com.google.firebase.firestore.pipeline.Constant.Companion Companion; - } - - public static final class Constant.Companion { - method public com.google.firebase.firestore.pipeline.Constant nullValue(); - method public com.google.firebase.firestore.pipeline.Constant of(boolean value); - method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.Blob value); - method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.DocumentReference ref); - method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.GeoPoint value); - method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.firestore.VectorValue value); - method public com.google.firebase.firestore.pipeline.Constant of(com.google.firebase.Timestamp value); - method public com.google.firebase.firestore.pipeline.Constant of(Number value); - method public com.google.firebase.firestore.pipeline.Constant of(String value); - method public com.google.firebase.firestore.pipeline.Constant of(java.util.Date value); - method public com.google.firebase.firestore.pipeline.Constant vector(com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.Constant vector(double[] vector); + public final class CollectionGroupSource extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.CollectionGroupSource of(String collectionId); + method public error.NonExistentClass withForceIndex(String value); + field public static final com.google.firebase.firestore.pipeline.CollectionGroupSource.Companion Companion; } - public abstract class Expr { - method public final com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr add(Object other); - method public com.google.firebase.firestore.pipeline.ExprWithAlias alias(String alias); - method public final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr... arrays); - method public final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(java.util.List arrays); - method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr value); - method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(Object value); - method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(java.util.List values); - method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(java.util.List values); - method public final com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(); - method public final com.google.firebase.firestore.pipeline.Ordering ascending(); - method public final com.google.firebase.firestore.pipeline.AggregateFunction avg(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr right); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(Object right); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr numberExpr); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(int number); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitNot(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr right); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(Object right); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr numberExpr); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(int number); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr right); - method public final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(Object right); - method public final com.google.firebase.firestore.pipeline.FunctionExpr byteLength(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr charLength(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector); - method public final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.VectorValue vector); - method public final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(double[] vector); - method public final com.google.firebase.firestore.pipeline.Ordering descending(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr divide(Object other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector); - method public final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.VectorValue vector); - method public final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(double[] vector); - method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr suffix); - method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String suffix); - method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(Object other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(java.util.List values); - method public final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector); - method public final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.VectorValue vector); - method public final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(double[] vector); - method public final com.google.firebase.firestore.pipeline.BooleanExpr exists(); - method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(Object other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(Object other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr isNan(); - method public final com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(); - method public final com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(); - method public final com.google.firebase.firestore.pipeline.BooleanExpr isNull(); - method public final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr pattern); - method public final com.google.firebase.firestore.pipeline.BooleanExpr like(String pattern); - method public final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(Object other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(Object other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(Object other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(Object other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr key); - method public final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String key); - method public final com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr key); - method public final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String key); - method public final com.google.firebase.firestore.pipeline.AggregateFunction max(); - method public final com.google.firebase.firestore.pipeline.AggregateFunction min(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr mod(Object other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr multiply(Object other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(Object other); - method public final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(java.util.List values); - method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr pattern); - method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String pattern); - method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr pattern); - method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String pattern); - method public final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(String find, String replace); - method public final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(String find, String replace); - method public final com.google.firebase.firestore.pipeline.FunctionExpr reverse(); - method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr prefix); - method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String prefix); - method public final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr... expr); - method public final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(java.lang.Object... string); - method public final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(java.lang.String... string); - method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr substring); - method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String substring); - method public final com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr other); - method public final com.google.firebase.firestore.pipeline.FunctionExpr subtract(Object other); - method public final com.google.firebase.firestore.pipeline.AggregateFunction sum(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String unit, double amount); - method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String unit, double amount); - method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr toLower(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr toUpper(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr trim(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(); - method public final com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(); + public static final class CollectionGroupSource.Companion { + method public com.google.firebase.firestore.pipeline.CollectionGroupSource of(String collectionId); } - public final class ExprWithAlias extends com.google.firebase.firestore.pipeline.Selectable { + public final class CollectionSource extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.CollectionSource of(com.google.firebase.firestore.CollectionReference ref); + method public static com.google.firebase.firestore.pipeline.CollectionSource of(String path); + method public error.NonExistentClass withForceIndex(String value); + field public static final com.google.firebase.firestore.pipeline.CollectionSource.Companion Companion; } - public final class Field extends com.google.firebase.firestore.pipeline.Selectable { - method public static com.google.firebase.firestore.pipeline.Field of(com.google.firebase.firestore.FieldPath fieldPath); - method public static com.google.firebase.firestore.pipeline.Field of(String name); - field public static final com.google.firebase.firestore.pipeline.Field.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.Field DOCUMENT_ID; + public static final class CollectionSource.Companion { + method public com.google.firebase.firestore.pipeline.CollectionSource of(com.google.firebase.firestore.CollectionReference ref); + method public com.google.firebase.firestore.pipeline.CollectionSource of(String path); } - public static final class Field.Companion { - method public com.google.firebase.firestore.pipeline.Field of(com.google.firebase.firestore.FieldPath fieldPath); - method public com.google.firebase.firestore.pipeline.Field of(String name); + public final class ExplainOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { + method public error.NonExistentClass withIndexRecommendation(boolean value); + method public error.NonExistentClass withMode(com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode value); + method public error.NonExistentClass withOutputFormat(com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat value); + method public error.NonExistentClass withProfiles(com.google.firebase.firestore.pipeline.ExplainOptions.Profiles value); + method public error.NonExistentClass withRedact(boolean value); + method public error.NonExistentClass withVerbosity(com.google.firebase.firestore.pipeline.ExplainOptions.Verbosity value); + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions DEFAULT; } - public final class FindNearestStage extends com.google.firebase.firestore.pipeline.Stage { - method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); - method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); - method public static com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); - method public static com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); - method public com.google.firebase.firestore.pipeline.FindNearestStage withDistanceField(com.google.firebase.firestore.pipeline.Field distanceField); - method public com.google.firebase.firestore.pipeline.FindNearestStage withDistanceField(String distanceField); - method public com.google.firebase.firestore.pipeline.FindNearestStage withLimit(long limit); - field public static final com.google.firebase.firestore.pipeline.FindNearestStage.Companion Companion; + public static final class ExplainOptions.Companion { } - public static final class FindNearestStage.Companion { - method public com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); - method public com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); - method public com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); - method public com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + public static final class ExplainOptions.ExplainMode { + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode ANALYZE; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode EXECUTE; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode EXPLAIN; } - public static final class FindNearestStage.DistanceMeasure { - field public static final error.NonExistentClass COSINE; - field public static final com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure.Companion Companion; - field public static final error.NonExistentClass DOT_PRODUCT; - field public static final error.NonExistentClass EUCLIDEAN; + public static final class ExplainOptions.ExplainMode.Companion { } - public static final class FindNearestStage.DistanceMeasure.Companion { + public static final class ExplainOptions.OutputFormat { + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat JSON; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat STRUCT; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat TEXT; } - public class FunctionExpr extends com.google.firebase.firestore.pipeline.Expr { - ctor protected FunctionExpr(String name, com.google.firebase.firestore.pipeline.Expr[] params); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr add(String fieldName, Object other); + public static final class ExplainOptions.OutputFormat.Companion { + } + + public static final class ExplainOptions.Profiles { + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Profiles BYTES_THROUGHPUT; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Profiles.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Profiles LATENCY; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Profiles RECORDS_COUNT; + } + + public static final class ExplainOptions.Profiles.Companion { + } + + public static final class ExplainOptions.Verbosity { + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Verbosity.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Verbosity EXECUTION_TREE; + field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Verbosity SUMMARY_ONLY; + } + + public static final class ExplainOptions.Verbosity.Companion { + } + + public abstract class Expr { + method public final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr add(Object other); + method public static final com.google.firebase.firestore.pipeline.Expr add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr add(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.ExprWithAlias alias(String alias); method public static final com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(String fieldName, java.util.List arrays); + method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); + method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); + method public final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr... arrays); + method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); + method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(String fieldName, java.util.List arrays); + method public final com.google.firebase.firestore.pipeline.Expr arrayConcat(java.util.List arrays); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object value); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(Object value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, com.google.firebase.firestore.pipeline.Expr value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, Object value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String fieldName, java.util.List values); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String fieldName, java.util.List values); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(com.google.firebase.firestore.pipeline.Expr array); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(com.google.firebase.firestore.pipeline.Expr array); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(String fieldName, int number); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitNot(com.google.firebase.firestore.pipeline.Expr left); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitNot(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitOr(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(String fieldName, int number); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr bitXor(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr byteLength(com.google.firebase.firestore.pipeline.Expr value); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr byteLength(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr charLength(com.google.firebase.firestore.pipeline.Expr value); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr charLength(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object otherwise); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, double[] vector); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr divide(String fieldName, Object other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, double[] vector); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(java.util.List values); + method public final com.google.firebase.firestore.pipeline.Expr arrayLength(); + method public static final com.google.firebase.firestore.pipeline.Expr arrayLength(com.google.firebase.firestore.pipeline.Expr array); + method public static final com.google.firebase.firestore.pipeline.Expr arrayLength(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr arrayReverse(); + method public static final com.google.firebase.firestore.pipeline.Expr arrayReverse(com.google.firebase.firestore.pipeline.Expr array); + method public static final com.google.firebase.firestore.pipeline.Expr arrayReverse(String fieldName); + method public final com.google.firebase.firestore.pipeline.Ordering ascending(); + method public final com.google.firebase.firestore.pipeline.AggregateFunction avg(); + method public final com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr bitAnd(Object right); + method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public final com.google.firebase.firestore.pipeline.Expr bitLeftShift(int number); + method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(String fieldName, int number); + method public final com.google.firebase.firestore.pipeline.Expr bitNot(); + method public static final com.google.firebase.firestore.pipeline.Expr bitNot(com.google.firebase.firestore.pipeline.Expr left); + method public static final com.google.firebase.firestore.pipeline.Expr bitNot(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr bitOr(Object right); + method public static final com.google.firebase.firestore.pipeline.Expr bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr bitOr(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public final com.google.firebase.firestore.pipeline.Expr bitRightShift(int number); + method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(String fieldName, int number); + method public final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr bitXor(Object right); + method public static final com.google.firebase.firestore.pipeline.Expr bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr bitXor(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.Expr byteLength(); + method public static final com.google.firebase.firestore.pipeline.Expr byteLength(com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.Expr byteLength(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr charLength(); + method public static final com.google.firebase.firestore.pipeline.Expr charLength(com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.Expr charLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); + method public static final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object otherwise); + method public static final com.google.firebase.firestore.pipeline.Expr constant(boolean value); + method public static final com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.Blob value); + method public static final com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.DocumentReference ref); + method public static final com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.GeoPoint value); + method public static final com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.VectorValue value); + method public static final com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.Timestamp value); + method public static final com.google.firebase.firestore.pipeline.Expr constant(Number value); + method public static final com.google.firebase.firestore.pipeline.Expr constant(String value); + method public static final com.google.firebase.firestore.pipeline.Expr constant(java.util.Date value); + method public final com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public final com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.VectorValue vector); + method public final com.google.firebase.firestore.pipeline.Expr cosineDistance(double[] vector); + method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, double[] vector); + method public final com.google.firebase.firestore.pipeline.Ordering descending(); + method public final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr divide(Object other); + method public static final com.google.firebase.firestore.pipeline.Expr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr divide(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.VectorValue vector); + method public final com.google.firebase.firestore.pipeline.Expr dotProduct(double[] vector); + method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, double[] vector); + method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr suffix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr suffix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, String suffix); + method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String suffix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr suffix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, String suffix); + method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(Object other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, java.util.List values); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, double[] vector); + method public final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(java.util.List values); + method public final com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public final com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.VectorValue vector); + method public final com.google.firebase.firestore.pipeline.Expr euclideanDistance(double[] vector); + method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, double[] vector); + method public final com.google.firebase.firestore.pipeline.BooleanExpr exists(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Field field(com.google.firebase.firestore.FieldPath fieldPath); + method public static final com.google.firebase.firestore.pipeline.Field field(String name); method public static final com.google.firebase.firestore.pipeline.FunctionExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(Object other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(Object other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isNan(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(String fieldName); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(String fieldName); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isNull(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNull(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNull(String fieldName); + method public final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public final com.google.firebase.firestore.pipeline.BooleanExpr like(String pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, String pattern); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(String fieldName, Object other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr logicalMax(Object other); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMax(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr logicalMin(Object other); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMin(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(Object other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(Object other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr map(java.util.Map elements); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String fieldName, String key); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(String mapField, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String mapField, String key); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr mod(String fieldName, Object other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr multiply(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.Expr map(java.util.Map elements); + method public final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); + method public final com.google.firebase.firestore.pipeline.Expr mapGet(String key); + method public static final com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, String key); + method public static final com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public final com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public static final com.google.firebase.firestore.pipeline.Expr mapMerge(String mapField, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); + method public final com.google.firebase.firestore.pipeline.Expr mapRemove(String key); + method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, String key); + method public final com.google.firebase.firestore.pipeline.AggregateFunction max(); + method public final com.google.firebase.firestore.pipeline.AggregateFunction min(); + method public final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr mod(Object other); + method public static final com.google.firebase.firestore.pipeline.Expr mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr mod(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr multiply(Object other); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(Object other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, Object right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr not(com.google.firebase.firestore.pipeline.BooleanExpr condition); method public static final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); method public static final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(String fieldName, java.util.List values); + method public final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(java.util.List values); + method public static final com.google.firebase.firestore.pipeline.Expr nullValue(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr or(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, String pattern); + method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, String pattern); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(String fieldName, String find, String replace); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(String fieldName, String find, String replace); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr reverse(com.google.firebase.firestore.pipeline.Expr expr); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr reverse(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public final com.google.firebase.firestore.pipeline.Expr replaceAll(String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceAll(String fieldName, String find, String replace); + method public final com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public final com.google.firebase.firestore.pipeline.Expr replaceFirst(String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceFirst(String fieldName, String find, String replace); + method public final com.google.firebase.firestore.pipeline.Expr reverse(); + method public static final com.google.firebase.firestore.pipeline.Expr reverse(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Expr reverse(String fieldName); + method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, String prefix); + method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr strConcat(String fieldName, java.lang.Object... rest); + method public static final com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); + method public static final com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); + method public final com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr... expr); + method public final com.google.firebase.firestore.pipeline.Expr strConcat(java.lang.Object... string); + method public static final com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); + method public static final com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, java.lang.Object... rest); + method public final com.google.firebase.firestore.pipeline.Expr strConcat(java.lang.String... string); + method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, String substring); + method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr subtract(String fieldName, Object other); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String fieldName, String unit, double amount); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String fieldName, String unit, double amount); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr toLower(com.google.firebase.firestore.pipeline.Expr expr); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr toLower(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr toUpper(com.google.firebase.firestore.pipeline.Expr expr); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr toUpper(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr trim(com.google.firebase.firestore.pipeline.Expr expr); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr trim(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(String fieldName); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public static final com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public final com.google.firebase.firestore.pipeline.Expr subtract(Object other); + method public static final com.google.firebase.firestore.pipeline.Expr subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public static final com.google.firebase.firestore.pipeline.Expr subtract(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.AggregateFunction sum(); + method public final com.google.firebase.firestore.pipeline.Expr timestampAdd(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.Expr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.Expr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.Expr timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public final com.google.firebase.firestore.pipeline.Expr timestampAdd(String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.Expr timestampAdd(String fieldName, String unit, double amount); + method public final com.google.firebase.firestore.pipeline.Expr timestampSub(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.Expr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public static final com.google.firebase.firestore.pipeline.Expr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.Expr timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public final com.google.firebase.firestore.pipeline.Expr timestampSub(String unit, double amount); + method public static final com.google.firebase.firestore.pipeline.Expr timestampSub(String fieldName, String unit, double amount); + method public final com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(); + method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(); + method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(); + method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr toLower(); + method public static final com.google.firebase.firestore.pipeline.Expr toLower(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Expr toLower(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr toUpper(); + method public static final com.google.firebase.firestore.pipeline.Expr toUpper(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Expr toUpper(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr trim(); + method public static final com.google.firebase.firestore.pipeline.Expr trim(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Expr trim(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(); + method public static final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(); + method public static final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(); + method public static final com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Expr vector(com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Expr vector(double[] vector); + method public final com.google.firebase.firestore.pipeline.Expr vectorLength(); + method public static final com.google.firebase.firestore.pipeline.Expr vectorLength(com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr vectorLength(String fieldName); method public static final com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); - field public static final com.google.firebase.firestore.pipeline.FunctionExpr.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.Expr.Companion Companion; } - public static final class FunctionExpr.Companion { - method public com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr add(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.FunctionExpr add(String fieldName, Object other); + public static final class Expr.Companion { + method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Expr add(String fieldName, Object other); method public com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); - method public com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); - method public com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); - method public com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); - method public com.google.firebase.firestore.pipeline.FunctionExpr arrayConcat(String fieldName, java.util.List arrays); + method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); + method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); + method public com.google.firebase.firestore.pipeline.Expr arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); + method public com.google.firebase.firestore.pipeline.Expr arrayConcat(String fieldName, java.util.List arrays); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr value); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object value); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, com.google.firebase.firestore.pipeline.Expr value); @@ -1152,54 +1177,63 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String fieldName, java.util.List values); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String fieldName, java.util.List values); - method public com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(com.google.firebase.firestore.pipeline.Expr array); - method public com.google.firebase.firestore.pipeline.FunctionExpr arrayLength(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(com.google.firebase.firestore.pipeline.Expr array); - method public com.google.firebase.firestore.pipeline.FunctionExpr arrayReverse(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitAnd(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitLeftShift(String fieldName, int number); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitNot(com.google.firebase.firestore.pipeline.Expr left); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitNot(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitOr(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitRightShift(String fieldName, int number); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr bitXor(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr byteLength(com.google.firebase.firestore.pipeline.Expr value); - method public com.google.firebase.firestore.pipeline.FunctionExpr byteLength(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr charLength(com.google.firebase.firestore.pipeline.Expr value); - method public com.google.firebase.firestore.pipeline.FunctionExpr charLength(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); - method public com.google.firebase.firestore.pipeline.FunctionExpr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object otherwise); - method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.FunctionExpr cosineDistance(String fieldName, double[] vector); - method public com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr divide(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.FunctionExpr divide(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.FunctionExpr dotProduct(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.Expr arrayLength(com.google.firebase.firestore.pipeline.Expr array); + method public com.google.firebase.firestore.pipeline.Expr arrayLength(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr arrayReverse(com.google.firebase.firestore.pipeline.Expr array); + method public com.google.firebase.firestore.pipeline.Expr arrayReverse(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr bitAnd(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(String fieldName, int number); + method public com.google.firebase.firestore.pipeline.Expr bitNot(com.google.firebase.firestore.pipeline.Expr left); + method public com.google.firebase.firestore.pipeline.Expr bitNot(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr bitOr(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public com.google.firebase.firestore.pipeline.Expr bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Expr bitRightShift(String fieldName, int number); + method public com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr bitXor(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.Expr byteLength(com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.Expr byteLength(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr charLength(com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.Expr charLength(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); + method public com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object otherwise); + method public com.google.firebase.firestore.pipeline.Expr constant(boolean value); + method public com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.Blob value); + method public com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.DocumentReference ref); + method public com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.GeoPoint value); + method public com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.VectorValue value); + method public com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.Timestamp value); + method public com.google.firebase.firestore.pipeline.Expr constant(Number value); + method public com.google.firebase.firestore.pipeline.Expr constant(String value); + method public com.google.firebase.firestore.pipeline.Expr constant(java.util.Date value); + method public com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Expr divide(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, double[] vector); method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr suffix); method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, String suffix); method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr suffix); @@ -1210,13 +1244,15 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, java.util.List values); - method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); - method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); - method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.FunctionExpr euclideanDistance(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); + method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); + method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); + method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, double[] vector); method public com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Field field(com.google.firebase.firestore.FieldPath fieldPath); + method public com.google.firebase.firestore.pipeline.Field field(String name); method public com.google.firebase.firestore.pipeline.FunctionExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); @@ -1238,14 +1274,14 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, String pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, String pattern); - method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMax(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.FunctionExpr logicalMin(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Expr logicalMax(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Expr logicalMin(String fieldName, Object other); method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); @@ -1254,25 +1290,25 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr map(java.util.Map elements); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapGet(String fieldName, String key); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapMerge(String mapField, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr key); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); - method public com.google.firebase.firestore.pipeline.FunctionExpr mapRemove(String mapField, String key); - method public com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr mod(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.FunctionExpr mod(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.FunctionExpr multiply(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr map(java.util.Map elements); + method public com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); + method public com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, String key); + method public com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public com.google.firebase.firestore.pipeline.Expr mapMerge(String mapField, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); + method public com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, String key); + method public com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Expr mod(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Expr multiply(String fieldName, Object other); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); @@ -1280,6 +1316,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr not(com.google.firebase.firestore.pipeline.BooleanExpr condition); method public com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); method public com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(String fieldName, java.util.List values); + method public com.google.firebase.firestore.pipeline.Expr nullValue(); method public com.google.firebase.firestore.pipeline.BooleanExpr or(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); @@ -1289,61 +1326,113 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, String pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, String pattern); - method public com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); - method public com.google.firebase.firestore.pipeline.FunctionExpr replaceAll(String fieldName, String find, String replace); - method public com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); - method public com.google.firebase.firestore.pipeline.FunctionExpr replaceFirst(String fieldName, String find, String replace); - method public com.google.firebase.firestore.pipeline.FunctionExpr reverse(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.FunctionExpr reverse(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public com.google.firebase.firestore.pipeline.Expr replaceAll(String fieldName, String find, String replace); + method public com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public com.google.firebase.firestore.pipeline.Expr replaceFirst(String fieldName, String find, String replace); + method public com.google.firebase.firestore.pipeline.Expr reverse(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Expr reverse(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, String prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); - method public com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); - method public com.google.firebase.firestore.pipeline.FunctionExpr strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); - method public com.google.firebase.firestore.pipeline.FunctionExpr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); - method public com.google.firebase.firestore.pipeline.FunctionExpr strConcat(String fieldName, java.lang.Object... rest); + method public com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); + method public com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); + method public com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); + method public com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, java.lang.Object... rest); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, String substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); - method public com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.FunctionExpr subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.FunctionExpr subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.FunctionExpr subtract(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampAdd(String fieldName, String unit, double amount); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampSub(String fieldName, String unit, double amount); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMicros(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixMillis(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.FunctionExpr timestampToUnixSeconds(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr toLower(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.FunctionExpr toLower(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr toUpper(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.FunctionExpr toUpper(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr trim(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.FunctionExpr trim(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.FunctionExpr unixMicrosToTimestamp(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.FunctionExpr unixMillisToTimestamp(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); - method public com.google.firebase.firestore.pipeline.FunctionExpr unixSecondsToTimestamp(String fieldName); - method public com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.FunctionExpr vectorLength(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); + method public com.google.firebase.firestore.pipeline.Expr subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); + method public com.google.firebase.firestore.pipeline.Expr subtract(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.Expr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public com.google.firebase.firestore.pipeline.Expr timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.Expr timestampAdd(String fieldName, String unit, double amount); + method public com.google.firebase.firestore.pipeline.Expr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.Expr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); + method public com.google.firebase.firestore.pipeline.Expr timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); + method public com.google.firebase.firestore.pipeline.Expr timestampSub(String fieldName, String unit, double amount); + method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr toLower(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Expr toLower(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr toUpper(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Expr toUpper(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr trim(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Expr trim(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr vector(com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Expr vector(double[] vector); + method public com.google.firebase.firestore.pipeline.Expr vectorLength(com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Expr vectorLength(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); } + public final class ExprWithAlias extends com.google.firebase.firestore.pipeline.Selectable { + } + + public final class Field extends com.google.firebase.firestore.pipeline.Selectable { + field public static final com.google.firebase.firestore.pipeline.Field.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.Field DOCUMENT_ID; + } + + public static final class Field.Companion { + } + + public final class FindNearestStage extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public static com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public static com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.pipeline.FindNearestStage withDistanceField(com.google.firebase.firestore.pipeline.Field distanceField); + method public com.google.firebase.firestore.pipeline.FindNearestStage withDistanceField(String distanceField); + method public com.google.firebase.firestore.pipeline.FindNearestStage withLimit(long limit); + field public static final com.google.firebase.firestore.pipeline.FindNearestStage.Companion Companion; + } + + public static final class FindNearestStage.Companion { + method public com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + method public com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); + } + + public static final class FindNearestStage.DistanceMeasure { + field public static final error.NonExistentClass COSINE; + field public static final com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure.Companion Companion; + field public static final error.NonExistentClass DOT_PRODUCT; + field public static final error.NonExistentClass EUCLIDEAN; + } + + public static final class FindNearestStage.DistanceMeasure.Companion { + } + + public class FunctionExpr extends com.google.firebase.firestore.pipeline.Expr { + } + + public final class GenericOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { + field public static final com.google.firebase.firestore.pipeline.GenericOptions.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.GenericOptions DEFAULT; + } + + public static final class GenericOptions.Companion { + } + public final class GenericStage extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.GenericStage ofName(String name); method public com.google.firebase.firestore.pipeline.GenericStage withArguments(java.lang.Object... arguments); @@ -1354,6 +1443,15 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.GenericStage ofName(String name); } + public final class InternalOptions { + field public static final com.google.firebase.firestore.pipeline.InternalOptions.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.InternalOptions EMPTY; + } + + public static final class InternalOptions.Companion { + method public com.google.firebase.firestore.pipeline.InternalOptions of(String key, error.NonExistentClass value); + } + public final class Ordering { method public static com.google.firebase.firestore.pipeline.Ordering ascending(com.google.firebase.firestore.pipeline.Expr expr); method public static com.google.firebase.firestore.pipeline.Ordering ascending(String fieldName); @@ -1372,6 +1470,24 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Ordering descending(String fieldName); } + public final class PipelineOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { + method public com.google.firebase.firestore.pipeline.PipelineOptions withExplainOptions(com.google.firebase.firestore.pipeline.ExplainOptions options); + method public com.google.firebase.firestore.pipeline.PipelineOptions withIndexMode(com.google.firebase.firestore.pipeline.PipelineOptions.IndexMode indexMode); + field public static final com.google.firebase.firestore.pipeline.PipelineOptions.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.PipelineOptions DEFAULT; + } + + public static final class PipelineOptions.Companion { + } + + public static final class PipelineOptions.IndexMode { + field public static final com.google.firebase.firestore.pipeline.PipelineOptions.IndexMode.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.PipelineOptions.IndexMode RECOMMENDED; + } + + public static final class PipelineOptions.IndexMode.Companion { + } + public final class SampleStage extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.SampleStage withDocLimit(int documents); method public static com.google.firebase.firestore.pipeline.SampleStage withPercentage(double percentage); diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index fbca6febc6b..a17dc79ab42 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -660,10 +660,7 @@ public void testComparisonOperators() { .pipeline() .collection(randomCol) .where( - and( - gt("rating", 4.2), - lte(field("rating"), 4.5), - neq("genre", "Science Function"))) + and(gt("rating", 4.2), lte(field("rating"), 4.5), neq("genre", "Science Function"))) .select("rating", "title") .sort(field("title").ascending()) .execute(); @@ -771,10 +768,8 @@ public void testDistanceFunctions() { .collection(randomCol) .select( cosineDistance(vector(sourceVector), targetVector).alias("cosineDistance"), - Expr.dotProduct(vector(sourceVector), targetVector) - .alias("dotProductDistance"), - euclideanDistance(vector(sourceVector), targetVector) - .alias("euclideanDistance")) + Expr.dotProduct(vector(sourceVector), targetVector).alias("dotProductDistance"), + euclideanDistance(vector(sourceVector), targetVector).alias("euclideanDistance")) .limit(1) .execute(); assertThat(waitFor(execute).getResults()) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index cc61160f405..06e4142d81b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -36,7 +36,6 @@ import com.google.firebase.firestore.pipeline.ExprWithAlias import com.google.firebase.firestore.pipeline.Field import com.google.firebase.firestore.pipeline.FindNearestStage import com.google.firebase.firestore.pipeline.FunctionExpr -import com.google.firebase.firestore.pipeline.GenericArg import com.google.firebase.firestore.pipeline.GenericStage import com.google.firebase.firestore.pipeline.LimitStage import com.google.firebase.firestore.pipeline.OffsetStage @@ -118,7 +117,7 @@ internal constructor( * @return A new [Pipeline] object with this stage appended to the stage list. */ fun genericStage(name: String, vararg arguments: Any): Pipeline = - append(GenericStage(name, arguments.map(GenericArg::from))) + append(GenericStage.ofName(name).withArguments(arguments)) /** * Adds a stage to the pipeline by specifying the stage name as an argument. This does not offer @@ -171,7 +170,9 @@ internal constructor( */ fun removeFields(field: String, vararg additionalFields: String): Pipeline = append( - RemoveFieldsStage(arrayOf(Expr.field(field), *additionalFields.map(Expr::field).toTypedArray())) + RemoveFieldsStage( + arrayOf(Expr.field(field), *additionalFields.map(Expr::field).toTypedArray()) + ) ) /** @@ -255,8 +256,7 @@ internal constructor( * You can filter documents based on their field values, using implementations of [BooleanExpr], * typically including but not limited to: * - * - field comparators: [Expr.eq], [Expr.lt] (less than), [Expr.gt] - * (greater than), etc. + * - field comparators: [Expr.eq], [Expr.lt] (less than), [Expr.gt] (greater than), etc. * - logical operators: [Expr.and], [Expr.or], [Expr.not], etc. * - advanced functions: [Expr.regexMatch], [Expr.arrayContains], etc. * diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index 08c3918b901..629135fe888 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -567,9 +567,10 @@ public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataR p = p.sort(orderings.get(0), orderings.stream().skip(1).toArray(Ordering[]::new)); p = p.limit((int) limit); } else { - p = p.sort( - orderings.get(0).reverse(), - orderings.stream().skip(1).map(Ordering::reverse).toArray(Ordering[]::new)); + p = + p.sort( + orderings.get(0).reverse(), + orderings.stream().skip(1).map(Ordering::reverse).toArray(Ordering[]::new)); p = p.limit((int) limit); p = p.sort(orderings.get(0), orderings.stream().skip(1).toArray(Ordering[]::new)); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index eaa59645cb3..c7b13f63aaa 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -23,8 +23,8 @@ import com.google.firebase.firestore.Pipeline import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.VectorValue import com.google.firebase.firestore.model.DocumentKey -import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.FieldPath as ModelFieldPath +import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.Values.encodeValue import com.google.firebase.firestore.util.CustomClassMapper import com.google.firestore.v1.MapValue @@ -280,109 +280,115 @@ abstract class Expr internal constructor() { @JvmStatic fun not(condition: BooleanExpr) = BooleanExpr("not", condition) - @JvmStatic fun bitAnd(left: Expr, right: Expr) = FunctionExpr("bit_and", left, right) + @JvmStatic fun bitAnd(left: Expr, right: Expr): Expr = FunctionExpr("bit_and", left, right) - @JvmStatic fun bitAnd(left: Expr, right: Any) = FunctionExpr("bit_and", left, right) + @JvmStatic fun bitAnd(left: Expr, right: Any): Expr = FunctionExpr("bit_and", left, right) @JvmStatic - fun bitAnd(fieldName: String, right: Expr) = FunctionExpr("bit_and", fieldName, right) + fun bitAnd(fieldName: String, right: Expr): Expr = FunctionExpr("bit_and", fieldName, right) - @JvmStatic fun bitAnd(fieldName: String, right: Any) = FunctionExpr("bit_and", fieldName, right) + @JvmStatic + fun bitAnd(fieldName: String, right: Any): Expr = FunctionExpr("bit_and", fieldName, right) - @JvmStatic fun bitOr(left: Expr, right: Expr) = FunctionExpr("bit_or", left, right) + @JvmStatic fun bitOr(left: Expr, right: Expr): Expr = FunctionExpr("bit_or", left, right) - @JvmStatic fun bitOr(left: Expr, right: Any) = FunctionExpr("bit_or", left, right) + @JvmStatic fun bitOr(left: Expr, right: Any): Expr = FunctionExpr("bit_or", left, right) - @JvmStatic fun bitOr(fieldName: String, right: Expr) = FunctionExpr("bit_or", fieldName, right) + @JvmStatic + fun bitOr(fieldName: String, right: Expr): Expr = FunctionExpr("bit_or", fieldName, right) - @JvmStatic fun bitOr(fieldName: String, right: Any) = FunctionExpr("bit_or", fieldName, right) + @JvmStatic + fun bitOr(fieldName: String, right: Any): Expr = FunctionExpr("bit_or", fieldName, right) - @JvmStatic fun bitXor(left: Expr, right: Expr) = FunctionExpr("bit_xor", left, right) + @JvmStatic fun bitXor(left: Expr, right: Expr): Expr = FunctionExpr("bit_xor", left, right) - @JvmStatic fun bitXor(left: Expr, right: Any) = FunctionExpr("bit_xor", left, right) + @JvmStatic fun bitXor(left: Expr, right: Any): Expr = FunctionExpr("bit_xor", left, right) @JvmStatic - fun bitXor(fieldName: String, right: Expr) = FunctionExpr("bit_xor", fieldName, right) + fun bitXor(fieldName: String, right: Expr): Expr = FunctionExpr("bit_xor", fieldName, right) - @JvmStatic fun bitXor(fieldName: String, right: Any) = FunctionExpr("bit_xor", fieldName, right) + @JvmStatic + fun bitXor(fieldName: String, right: Any): Expr = FunctionExpr("bit_xor", fieldName, right) - @JvmStatic fun bitNot(left: Expr) = FunctionExpr("bit_not", left) + @JvmStatic fun bitNot(left: Expr): Expr = FunctionExpr("bit_not", left) - @JvmStatic fun bitNot(fieldName: String) = FunctionExpr("bit_not", fieldName) + @JvmStatic fun bitNot(fieldName: String): Expr = FunctionExpr("bit_not", fieldName) @JvmStatic - fun bitLeftShift(left: Expr, numberExpr: Expr) = + fun bitLeftShift(left: Expr, numberExpr: Expr): Expr = FunctionExpr("bit_left_shift", left, numberExpr) @JvmStatic - fun bitLeftShift(left: Expr, number: Int) = FunctionExpr("bit_left_shift", left, number) + fun bitLeftShift(left: Expr, number: Int): Expr = FunctionExpr("bit_left_shift", left, number) @JvmStatic - fun bitLeftShift(fieldName: String, numberExpr: Expr) = + fun bitLeftShift(fieldName: String, numberExpr: Expr): Expr = FunctionExpr("bit_left_shift", fieldName, numberExpr) @JvmStatic - fun bitLeftShift(fieldName: String, number: Int) = + fun bitLeftShift(fieldName: String, number: Int): Expr = FunctionExpr("bit_left_shift", fieldName, number) @JvmStatic - fun bitRightShift(left: Expr, numberExpr: Expr) = + fun bitRightShift(left: Expr, numberExpr: Expr): Expr = FunctionExpr("bit_right_shift", left, numberExpr) @JvmStatic - fun bitRightShift(left: Expr, number: Int) = FunctionExpr("bit_right_shift", left, number) + fun bitRightShift(left: Expr, number: Int): Expr = FunctionExpr("bit_right_shift", left, number) @JvmStatic - fun bitRightShift(fieldName: String, numberExpr: Expr) = + fun bitRightShift(fieldName: String, numberExpr: Expr): Expr = FunctionExpr("bit_right_shift", fieldName, numberExpr) @JvmStatic - fun bitRightShift(fieldName: String, number: Int) = + fun bitRightShift(fieldName: String, number: Int): Expr = FunctionExpr("bit_right_shift", fieldName, number) - @JvmStatic fun add(left: Expr, right: Expr) = FunctionExpr("add", left, right) + @JvmStatic fun add(left: Expr, right: Expr): Expr = FunctionExpr("add", left, right) - @JvmStatic fun add(left: Expr, right: Any) = FunctionExpr("add", left, right) + @JvmStatic fun add(left: Expr, right: Any): Expr = FunctionExpr("add", left, right) - @JvmStatic fun add(fieldName: String, other: Expr) = FunctionExpr("add", fieldName, other) + @JvmStatic fun add(fieldName: String, other: Expr): Expr = FunctionExpr("add", fieldName, other) - @JvmStatic fun add(fieldName: String, other: Any) = FunctionExpr("add", fieldName, other) + @JvmStatic fun add(fieldName: String, other: Any): Expr = FunctionExpr("add", fieldName, other) - @JvmStatic fun subtract(left: Expr, right: Expr) = FunctionExpr("subtract", left, right) + @JvmStatic fun subtract(left: Expr, right: Expr): Expr = FunctionExpr("subtract", left, right) - @JvmStatic fun subtract(left: Expr, right: Any) = FunctionExpr("subtract", left, right) + @JvmStatic fun subtract(left: Expr, right: Any): Expr = FunctionExpr("subtract", left, right) @JvmStatic - fun subtract(fieldName: String, other: Expr) = FunctionExpr("subtract", fieldName, other) + fun subtract(fieldName: String, other: Expr): Expr = FunctionExpr("subtract", fieldName, other) @JvmStatic - fun subtract(fieldName: String, other: Any) = FunctionExpr("subtract", fieldName, other) + fun subtract(fieldName: String, other: Any): Expr = FunctionExpr("subtract", fieldName, other) - @JvmStatic fun multiply(left: Expr, right: Expr) = FunctionExpr("multiply", left, right) + @JvmStatic fun multiply(left: Expr, right: Expr): Expr = FunctionExpr("multiply", left, right) - @JvmStatic fun multiply(left: Expr, right: Any) = FunctionExpr("multiply", left, right) + @JvmStatic fun multiply(left: Expr, right: Any): Expr = FunctionExpr("multiply", left, right) @JvmStatic - fun multiply(fieldName: String, other: Expr) = FunctionExpr("multiply", fieldName, other) + fun multiply(fieldName: String, other: Expr): Expr = FunctionExpr("multiply", fieldName, other) @JvmStatic - fun multiply(fieldName: String, other: Any) = FunctionExpr("multiply", fieldName, other) + fun multiply(fieldName: String, other: Any): Expr = FunctionExpr("multiply", fieldName, other) - @JvmStatic fun divide(left: Expr, right: Expr) = FunctionExpr("divide", left, right) + @JvmStatic fun divide(left: Expr, right: Expr): Expr = FunctionExpr("divide", left, right) - @JvmStatic fun divide(left: Expr, right: Any) = FunctionExpr("divide", left, right) + @JvmStatic fun divide(left: Expr, right: Any): Expr = FunctionExpr("divide", left, right) - @JvmStatic fun divide(fieldName: String, other: Expr) = FunctionExpr("divide", fieldName, other) + @JvmStatic + fun divide(fieldName: String, other: Expr): Expr = FunctionExpr("divide", fieldName, other) - @JvmStatic fun divide(fieldName: String, other: Any) = FunctionExpr("divide", fieldName, other) + @JvmStatic + fun divide(fieldName: String, other: Any): Expr = FunctionExpr("divide", fieldName, other) - @JvmStatic fun mod(left: Expr, right: Expr) = FunctionExpr("mod", left, right) + @JvmStatic fun mod(left: Expr, right: Expr): Expr = FunctionExpr("mod", left, right) - @JvmStatic fun mod(left: Expr, right: Any) = FunctionExpr("mod", left, right) + @JvmStatic fun mod(left: Expr, right: Any): Expr = FunctionExpr("mod", left, right) - @JvmStatic fun mod(fieldName: String, other: Expr) = FunctionExpr("mod", fieldName, other) + @JvmStatic fun mod(fieldName: String, other: Expr): Expr = FunctionExpr("mod", fieldName, other) - @JvmStatic fun mod(fieldName: String, other: Any) = FunctionExpr("mod", fieldName, other) + @JvmStatic fun mod(fieldName: String, other: Any): Expr = FunctionExpr("mod", fieldName, other) @JvmStatic fun eqAny(value: Expr, values: List) = @@ -417,36 +423,36 @@ abstract class Expr internal constructor() { @JvmStatic fun isNotNull(fieldName: String) = BooleanExpr("is_not_null", fieldName) @JvmStatic - fun replaceFirst(value: Expr, find: Expr, replace: Expr) = + fun replaceFirst(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_first", value, find, replace) @JvmStatic - fun replaceFirst(value: Expr, find: String, replace: String) = + fun replaceFirst(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_first", value, find, replace) @JvmStatic - fun replaceFirst(fieldName: String, find: String, replace: String) = + fun replaceFirst(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_first", fieldName, find, replace) @JvmStatic - fun replaceAll(value: Expr, find: Expr, replace: Expr) = + fun replaceAll(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_all", value, find, replace) @JvmStatic - fun replaceAll(value: Expr, find: String, replace: String) = + fun replaceAll(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_all", value, find, replace) @JvmStatic - fun replaceAll(fieldName: String, find: String, replace: String) = + fun replaceAll(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_all", fieldName, find, replace) - @JvmStatic fun charLength(value: Expr) = FunctionExpr("char_length", value) + @JvmStatic fun charLength(value: Expr): Expr = FunctionExpr("char_length", value) - @JvmStatic fun charLength(fieldName: String) = FunctionExpr("char_length", fieldName) + @JvmStatic fun charLength(fieldName: String): Expr = FunctionExpr("char_length", fieldName) - @JvmStatic fun byteLength(value: Expr) = FunctionExpr("byte_length", value) + @JvmStatic fun byteLength(value: Expr): Expr = FunctionExpr("byte_length", value) - @JvmStatic fun byteLength(fieldName: String) = FunctionExpr("byte_length", fieldName) + @JvmStatic fun byteLength(fieldName: String): Expr = FunctionExpr("byte_length", fieldName) @JvmStatic fun like(expr: Expr, pattern: Expr) = BooleanExpr("like", expr, pattern) @@ -484,29 +490,37 @@ abstract class Expr internal constructor() { fun regexMatch(fieldName: String, pattern: String) = BooleanExpr("regex_match", fieldName, pattern) - @JvmStatic fun logicalMax(left: Expr, right: Expr) = FunctionExpr("logical_max", left, right) + @JvmStatic + fun logicalMax(left: Expr, right: Expr): Expr = FunctionExpr("logical_max", left, right) - @JvmStatic fun logicalMax(left: Expr, right: Any) = FunctionExpr("logical_max", left, right) + @JvmStatic + fun logicalMax(left: Expr, right: Any): Expr = FunctionExpr("logical_max", left, right) @JvmStatic - fun logicalMax(fieldName: String, other: Expr) = FunctionExpr("logical_max", fieldName, other) + fun logicalMax(fieldName: String, other: Expr): Expr = + FunctionExpr("logical_max", fieldName, other) @JvmStatic - fun logicalMax(fieldName: String, other: Any) = FunctionExpr("logical_max", fieldName, other) + fun logicalMax(fieldName: String, other: Any): Expr = + FunctionExpr("logical_max", fieldName, other) - @JvmStatic fun logicalMin(left: Expr, right: Expr) = FunctionExpr("logical_min", left, right) + @JvmStatic + fun logicalMin(left: Expr, right: Expr): Expr = FunctionExpr("logical_min", left, right) - @JvmStatic fun logicalMin(left: Expr, right: Any) = FunctionExpr("logical_min", left, right) + @JvmStatic + fun logicalMin(left: Expr, right: Any): Expr = FunctionExpr("logical_min", left, right) @JvmStatic - fun logicalMin(fieldName: String, other: Expr) = FunctionExpr("logical_min", fieldName, other) + fun logicalMin(fieldName: String, other: Expr): Expr = + FunctionExpr("logical_min", fieldName, other) @JvmStatic - fun logicalMin(fieldName: String, other: Any) = FunctionExpr("logical_min", fieldName, other) + fun logicalMin(fieldName: String, other: Any): Expr = + FunctionExpr("logical_min", fieldName, other) - @JvmStatic fun reverse(expr: Expr) = FunctionExpr("reverse", expr) + @JvmStatic fun reverse(expr: Expr): Expr = FunctionExpr("reverse", expr) - @JvmStatic fun reverse(fieldName: String) = FunctionExpr("reverse", fieldName) + @JvmStatic fun reverse(fieldName: String): Expr = FunctionExpr("reverse", fieldName) @JvmStatic fun strContains(expr: Expr, substring: Expr) = BooleanExpr("str_contains", expr, substring) @@ -543,217 +557,222 @@ abstract class Expr internal constructor() { @JvmStatic fun endsWith(fieldName: String, suffix: String) = BooleanExpr("ends_with", fieldName, suffix) - @JvmStatic fun toLower(expr: Expr) = FunctionExpr("to_lower", expr) + @JvmStatic fun toLower(expr: Expr): Expr = FunctionExpr("to_lower", expr) @JvmStatic fun toLower( fieldName: String, - ) = FunctionExpr("to_lower", fieldName) + ): Expr = FunctionExpr("to_lower", fieldName) - @JvmStatic fun toUpper(expr: Expr) = FunctionExpr("to_upper", expr) + @JvmStatic fun toUpper(expr: Expr): Expr = FunctionExpr("to_upper", expr) @JvmStatic fun toUpper( fieldName: String, - ) = FunctionExpr("to_upper", fieldName) + ): Expr = FunctionExpr("to_upper", fieldName) - @JvmStatic fun trim(expr: Expr) = FunctionExpr("trim", expr) + @JvmStatic fun trim(expr: Expr): Expr = FunctionExpr("trim", expr) - @JvmStatic fun trim(fieldName: String) = FunctionExpr("trim", fieldName) + @JvmStatic fun trim(fieldName: String): Expr = FunctionExpr("trim", fieldName) @JvmStatic - fun strConcat(first: Expr, vararg rest: Expr) = FunctionExpr("str_concat", first, *rest) + fun strConcat(first: Expr, vararg rest: Expr): Expr = FunctionExpr("str_concat", first, *rest) @JvmStatic - fun strConcat(first: Expr, vararg rest: Any) = FunctionExpr("str_concat", first, *rest) + fun strConcat(first: Expr, vararg rest: Any): Expr = FunctionExpr("str_concat", first, *rest) @JvmStatic - fun strConcat(fieldName: String, vararg rest: Expr) = + fun strConcat(fieldName: String, vararg rest: Expr): Expr = FunctionExpr("str_concat", fieldName, *rest) @JvmStatic - fun strConcat(fieldName: String, vararg rest: Any) = + fun strConcat(fieldName: String, vararg rest: Any): Expr = FunctionExpr("str_concat", fieldName, *rest) - internal fun map(elements: Array) = FunctionExpr("map", elements) + internal fun map(elements: Array): Expr = FunctionExpr("map", elements) @JvmStatic fun map(elements: Map) = map(elements.flatMap { listOf(constant(it.key), toExprOrConstant(it.value)) }.toTypedArray()) - @JvmStatic fun mapGet(map: Expr, key: Expr) = FunctionExpr("map_get", map, key) + @JvmStatic fun mapGet(map: Expr, key: Expr): Expr = FunctionExpr("map_get", map, key) - @JvmStatic fun mapGet(map: Expr, key: String) = FunctionExpr("map_get", map, key) + @JvmStatic fun mapGet(map: Expr, key: String): Expr = FunctionExpr("map_get", map, key) - @JvmStatic fun mapGet(fieldName: String, key: Expr) = FunctionExpr("map_get", fieldName, key) + @JvmStatic + fun mapGet(fieldName: String, key: Expr): Expr = FunctionExpr("map_get", fieldName, key) - @JvmStatic fun mapGet(fieldName: String, key: String) = FunctionExpr("map_get", fieldName, key) + @JvmStatic + fun mapGet(fieldName: String, key: String): Expr = FunctionExpr("map_get", fieldName, key) @JvmStatic - fun mapMerge(firstMap: Expr, secondMap: Expr, vararg otherMaps: Expr) = + fun mapMerge(firstMap: Expr, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", firstMap, secondMap, otherMaps) @JvmStatic - fun mapMerge(mapField: String, secondMap: Expr, vararg otherMaps: Expr) = + fun mapMerge(mapField: String, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", mapField, secondMap, otherMaps) - @JvmStatic fun mapRemove(firstMap: Expr, key: Expr) = FunctionExpr("map_remove", firstMap, key) + @JvmStatic + fun mapRemove(firstMap: Expr, key: Expr): Expr = FunctionExpr("map_remove", firstMap, key) @JvmStatic - fun mapRemove(mapField: String, key: Expr) = FunctionExpr("map_remove", mapField, key) + fun mapRemove(mapField: String, key: Expr): Expr = FunctionExpr("map_remove", mapField, key) @JvmStatic - fun mapRemove(firstMap: Expr, key: String) = FunctionExpr("map_remove", firstMap, key) + fun mapRemove(firstMap: Expr, key: String): Expr = FunctionExpr("map_remove", firstMap, key) @JvmStatic - fun mapRemove(mapField: String, key: String) = FunctionExpr("map_remove", mapField, key) + fun mapRemove(mapField: String, key: String): Expr = FunctionExpr("map_remove", mapField, key) @JvmStatic - fun cosineDistance(vector1: Expr, vector2: Expr) = + fun cosineDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("cosine_distance", vector1, vector2) @JvmStatic - fun cosineDistance(vector1: Expr, vector2: DoubleArray) = + fun cosineDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("cosine_distance", vector1, vector(vector2)) @JvmStatic - fun cosineDistance(vector1: Expr, vector2: VectorValue) = + fun cosineDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("cosine_distance", vector1, vector2) @JvmStatic - fun cosineDistance(fieldName: String, vector: Expr) = + fun cosineDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("cosine_distance", fieldName, vector) @JvmStatic - fun cosineDistance(fieldName: String, vector: DoubleArray) = + fun cosineDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("cosine_distance", fieldName, vector(vector)) @JvmStatic - fun cosineDistance(fieldName: String, vector: VectorValue) = + fun cosineDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("cosine_distance", fieldName, vector) @JvmStatic - fun dotProduct(vector1: Expr, vector2: Expr) = FunctionExpr("dot_product", vector1, vector2) + fun dotProduct(vector1: Expr, vector2: Expr): Expr = + FunctionExpr("dot_product", vector1, vector2) @JvmStatic - fun dotProduct(vector1: Expr, vector2: DoubleArray) = + fun dotProduct(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("dot_product", vector1, vector(vector2)) @JvmStatic - fun dotProduct(vector1: Expr, vector2: VectorValue) = + fun dotProduct(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("dot_product", vector1, vector2) @JvmStatic - fun dotProduct(fieldName: String, vector: Expr) = FunctionExpr("dot_product", fieldName, vector) + fun dotProduct(fieldName: String, vector: Expr): Expr = + FunctionExpr("dot_product", fieldName, vector) @JvmStatic - fun dotProduct(fieldName: String, vector: DoubleArray) = + fun dotProduct(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("dot_product", fieldName, vector(vector)) @JvmStatic - fun dotProduct(fieldName: String, vector: VectorValue) = + fun dotProduct(fieldName: String, vector: VectorValue): Expr = FunctionExpr("dot_product", fieldName, vector) @JvmStatic - fun euclideanDistance(vector1: Expr, vector2: Expr) = + fun euclideanDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("euclidean_distance", vector1, vector2) @JvmStatic - fun euclideanDistance(vector1: Expr, vector2: DoubleArray) = + fun euclideanDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("euclidean_distance", vector1, vector(vector2)) @JvmStatic - fun euclideanDistance(vector1: Expr, vector2: VectorValue) = + fun euclideanDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("euclidean_distance", vector1, vector2) @JvmStatic - fun euclideanDistance(fieldName: String, vector: Expr) = + fun euclideanDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("euclidean_distance", fieldName, vector) @JvmStatic - fun euclideanDistance(fieldName: String, vector: DoubleArray) = + fun euclideanDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("euclidean_distance", fieldName, vector(vector)) @JvmStatic - fun euclideanDistance(fieldName: String, vector: VectorValue) = + fun euclideanDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("euclidean_distance", fieldName, vector) - @JvmStatic fun vectorLength(vector: Expr) = FunctionExpr("vector_length", vector) + @JvmStatic fun vectorLength(vector: Expr): Expr = FunctionExpr("vector_length", vector) - @JvmStatic fun vectorLength(fieldName: String) = FunctionExpr("vector_length", fieldName) + @JvmStatic fun vectorLength(fieldName: String): Expr = FunctionExpr("vector_length", fieldName) @JvmStatic - fun unixMicrosToTimestamp(input: Expr) = FunctionExpr("unix_micros_to_timestamp", input) + fun unixMicrosToTimestamp(input: Expr): Expr = FunctionExpr("unix_micros_to_timestamp", input) @JvmStatic - fun unixMicrosToTimestamp(fieldName: String) = + fun unixMicrosToTimestamp(fieldName: String): Expr = FunctionExpr("unix_micros_to_timestamp", fieldName) @JvmStatic - fun timestampToUnixMicros(input: Expr) = FunctionExpr("timestamp_to_unix_micros", input) + fun timestampToUnixMicros(input: Expr): Expr = FunctionExpr("timestamp_to_unix_micros", input) @JvmStatic - fun timestampToUnixMicros(fieldName: String) = + fun timestampToUnixMicros(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_micros", fieldName) @JvmStatic - fun unixMillisToTimestamp(input: Expr) = FunctionExpr("unix_millis_to_timestamp", input) + fun unixMillisToTimestamp(input: Expr): Expr = FunctionExpr("unix_millis_to_timestamp", input) @JvmStatic - fun unixMillisToTimestamp(fieldName: String) = + fun unixMillisToTimestamp(fieldName: String): Expr = FunctionExpr("unix_millis_to_timestamp", fieldName) @JvmStatic - fun timestampToUnixMillis(input: Expr) = FunctionExpr("timestamp_to_unix_millis", input) + fun timestampToUnixMillis(input: Expr): Expr = FunctionExpr("timestamp_to_unix_millis", input) @JvmStatic - fun timestampToUnixMillis(fieldName: String) = + fun timestampToUnixMillis(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_millis", fieldName) @JvmStatic - fun unixSecondsToTimestamp(input: Expr) = FunctionExpr("unix_seconds_to_timestamp", input) + fun unixSecondsToTimestamp(input: Expr): Expr = FunctionExpr("unix_seconds_to_timestamp", input) @JvmStatic - fun unixSecondsToTimestamp(fieldName: String) = + fun unixSecondsToTimestamp(fieldName: String): Expr = FunctionExpr("unix_seconds_to_timestamp", fieldName) @JvmStatic - fun timestampToUnixSeconds(input: Expr) = FunctionExpr("timestamp_to_unix_seconds", input) + fun timestampToUnixSeconds(input: Expr): Expr = FunctionExpr("timestamp_to_unix_seconds", input) @JvmStatic - fun timestampToUnixSeconds(fieldName: String) = + fun timestampToUnixSeconds(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_seconds", fieldName) @JvmStatic - fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr) = + fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) @JvmStatic - fun timestampAdd(timestamp: Expr, unit: String, amount: Double) = + fun timestampAdd(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) @JvmStatic - fun timestampAdd(fieldName: String, unit: Expr, amount: Expr) = + fun timestampAdd(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) @JvmStatic - fun timestampAdd(fieldName: String, unit: String, amount: Double) = + fun timestampAdd(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) @JvmStatic - fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr) = + fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) @JvmStatic - fun timestampSub(timestamp: Expr, unit: String, amount: Double) = + fun timestampSub(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) @JvmStatic - fun timestampSub(fieldName: String, unit: Expr, amount: Expr) = + fun timestampSub(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) @JvmStatic - fun timestampSub(fieldName: String, unit: String, amount: Double) = + fun timestampSub(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) @JvmStatic fun eq(left: Expr, right: Expr) = BooleanExpr("eq", left, right) @@ -805,23 +824,24 @@ abstract class Expr internal constructor() { @JvmStatic fun lte(fieldName: String, right: Any) = BooleanExpr("lte", fieldName, right) @JvmStatic - fun arrayConcat(array: Expr, vararg arrays: Expr) = FunctionExpr("array_concat", array, *arrays) + fun arrayConcat(array: Expr, vararg arrays: Expr): Expr = + FunctionExpr("array_concat", array, *arrays) @JvmStatic - fun arrayConcat(fieldName: String, vararg arrays: Expr) = + fun arrayConcat(fieldName: String, vararg arrays: Expr): Expr = FunctionExpr("array_concat", fieldName, *arrays) @JvmStatic - fun arrayConcat(array: Expr, arrays: List) = + fun arrayConcat(array: Expr, arrays: List): Expr = FunctionExpr("array_concat", array, ListOfExprs(toArrayOfExprOrConstant(arrays))) @JvmStatic - fun arrayConcat(fieldName: String, arrays: List) = + fun arrayConcat(fieldName: String, arrays: List): Expr = FunctionExpr("array_concat", fieldName, ListOfExprs(toArrayOfExprOrConstant(arrays))) - @JvmStatic fun arrayReverse(array: Expr) = FunctionExpr("array_reverse", array) + @JvmStatic fun arrayReverse(array: Expr): Expr = FunctionExpr("array_reverse", array) - @JvmStatic fun arrayReverse(fieldName: String) = FunctionExpr("array_reverse", fieldName) + @JvmStatic fun arrayReverse(fieldName: String): Expr = FunctionExpr("array_reverse", fieldName) @JvmStatic fun arrayContains(array: Expr, value: Expr) = BooleanExpr("array_contains", array, value) @@ -853,16 +873,16 @@ abstract class Expr internal constructor() { fun arrayContainsAny(fieldName: String, values: List) = BooleanExpr("array_contains_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) - @JvmStatic fun arrayLength(array: Expr) = FunctionExpr("array_length", array) + @JvmStatic fun arrayLength(array: Expr): Expr = FunctionExpr("array_length", array) - @JvmStatic fun arrayLength(fieldName: String) = FunctionExpr("array_length", fieldName) + @JvmStatic fun arrayLength(fieldName: String): Expr = FunctionExpr("array_length", fieldName) @JvmStatic - fun cond(condition: BooleanExpr, then: Expr, otherwise: Expr) = + fun cond(condition: BooleanExpr, then: Expr, otherwise: Expr): Expr = FunctionExpr("cond", condition, then, otherwise) @JvmStatic - fun cond(condition: BooleanExpr, then: Any, otherwise: Any) = + fun cond(condition: BooleanExpr, then: Any, otherwise: Any): Expr = FunctionExpr("cond", condition, then, otherwise) @JvmStatic fun exists(expr: Expr) = BooleanExpr("exists", expr) @@ -1171,7 +1191,6 @@ class Field internal constructor(private val fieldPath: ModelFieldPath) : Select * @return An [Field] representing the document ID. */ @JvmField val DOCUMENT_ID: Field = field(FieldPath.documentId()) - } override fun getAlias(): String = fieldPath.canonicalString() @@ -1275,7 +1294,8 @@ class Ordering private constructor(val expr: Expr, private val dir: Direction) { * @return A new [Ordering] object with ascending sort by field. */ @JvmStatic - fun ascending(fieldName: String): Ordering = Ordering(Expr.field(fieldName), Direction.ASCENDING) + fun ascending(fieldName: String): Ordering = + Ordering(Expr.field(fieldName), Direction.ASCENDING) /** * Create an [Ordering] that sorts documents in descending order based on value of [expr]. diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt index 300d770c337..27d5375f3ab 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt @@ -28,8 +28,7 @@ import com.google.firestore.v1.Value * `ImmutableMap, Value>` is an implementation detail, not to be exposed, since * more efficient implementations are possible. */ -class InternalOptions -internal constructor(private val options: ImmutableMap) { +class InternalOptions internal constructor(private val options: ImmutableMap) { internal fun with(key: String, value: Value): InternalOptions { val builder = ImmutableMap.builderWithExpectedSize(options.size + 1) builder.putAll(options) @@ -58,8 +57,7 @@ internal constructor(private val options: ImmutableMap) { } companion object { - @JvmField - val EMPTY: InternalOptions = InternalOptions(ImmutableMap.of()) + @JvmField val EMPTY: InternalOptions = InternalOptions(ImmutableMap.of()) fun of(key: String, value: Value): InternalOptions { return InternalOptions(ImmutableMap.of(key, value)) @@ -131,44 +129,42 @@ internal constructor(internal val options: InternalOptions) { fun with(key: String, value: GenericOptions): T = with(key, value.options) } -class GenericOptions private constructor(options: InternalOptions) : AbstractOptions(options) { +class GenericOptions private constructor(options: InternalOptions) : + AbstractOptions(options) { override fun self(options: InternalOptions) = GenericOptions(options) companion object { - @JvmField - val DEFAULT: GenericOptions = GenericOptions(InternalOptions.EMPTY) + @JvmField val DEFAULT: GenericOptions = GenericOptions(InternalOptions.EMPTY) } } -class PipelineOptions private constructor(options: InternalOptions) : AbstractOptions(options) { +class PipelineOptions private constructor(options: InternalOptions) : + AbstractOptions(options) { override fun self(options: InternalOptions) = PipelineOptions(options) companion object { - @JvmField - val DEFAULT: PipelineOptions = PipelineOptions(InternalOptions.EMPTY) + @JvmField val DEFAULT: PipelineOptions = PipelineOptions(InternalOptions.EMPTY) } class IndexMode private constructor(internal val value: String) { companion object { - @JvmField - val RECOMMENDED = IndexMode("recommended") + @JvmField val RECOMMENDED = IndexMode("recommended") } } - fun withIndexMode(indexMode: IndexMode): PipelineOptions = - with("index_mode", indexMode.value) + fun withIndexMode(indexMode: IndexMode): PipelineOptions = with("index_mode", indexMode.value) fun withExplainOptions(options: ExplainOptions): PipelineOptions = with("explain_options", options.options) } -class ExplainOptions private constructor(options: InternalOptions) : AbstractOptions(options) { +class ExplainOptions private constructor(options: InternalOptions) : + AbstractOptions(options) { override fun self(options: InternalOptions) = ExplainOptions(options) companion object { - @JvmField - val DEFAULT = ExplainOptions(InternalOptions.EMPTY) + @JvmField val DEFAULT = ExplainOptions(InternalOptions.EMPTY) } fun withMode(value: ExplainMode) = with("mode", value.value) @@ -185,51 +181,39 @@ class ExplainOptions private constructor(options: InternalOptions) : AbstractOpt class ExplainMode private constructor(internal val value: String) { companion object { - @JvmField - val EXECUTE = ExplainMode("execute") + @JvmField val EXECUTE = ExplainMode("execute") - @JvmField - val EXPLAIN = ExplainMode("explain") + @JvmField val EXPLAIN = ExplainMode("explain") - @JvmField - val ANALYZE = ExplainMode("analyze") + @JvmField val ANALYZE = ExplainMode("analyze") } } class OutputFormat private constructor(internal val value: String) { companion object { - @JvmField - val TEXT = OutputFormat("text") + @JvmField val TEXT = OutputFormat("text") - @JvmField - val JSON = OutputFormat("json") + @JvmField val JSON = OutputFormat("json") - @JvmField - val STRUCT = OutputFormat("struct") + @JvmField val STRUCT = OutputFormat("struct") } } class Verbosity private constructor(internal val value: String) { companion object { - @JvmField - val SUMMARY_ONLY = Verbosity("summary_only") + @JvmField val SUMMARY_ONLY = Verbosity("summary_only") - @JvmField - val EXECUTION_TREE = Verbosity("execution_tree") + @JvmField val EXECUTION_TREE = Verbosity("execution_tree") } } class Profiles private constructor(internal val value: String) { companion object { - @JvmField - val LATENCY = Profiles("latency") + @JvmField val LATENCY = Profiles("latency") - @JvmField - val RECORDS_COUNT = Profiles("records_count") + @JvmField val RECORDS_COUNT = Profiles("records_count") - @JvmField - val BYTES_THROUGHPUT = Profiles("bytes_throughput") + @JvmField val BYTES_THROUGHPUT = Profiles("bytes_throughput") } } } - diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index cc930495eb3..e3d02d19652 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -177,9 +177,10 @@ internal constructor( private val path: String, // We validate [firestore.databaseId] when adding to pipeline. internal val firestore: FirebaseFirestore?, - options: InternalOptions) : - Stage("collection", options) { - override fun self(options: InternalOptions): CollectionSource = CollectionSource(path, firestore, options) + options: InternalOptions +) : Stage("collection", options) { + override fun self(options: InternalOptions): CollectionSource = + CollectionSource(path, firestore, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf( Value.newBuilder().setReferenceValue(if (path.startsWith("/")) path else "/" + path).build() From 356e8839d436e992d35adac17008a0317d4d379d Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 22 Apr 2025 15:48:57 -0400 Subject: [PATCH 44/77] Comments --- .../firestore/pipeline/expressions.kt | 917 +++++++++++++++++- 1 file changed, 912 insertions(+), 5 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index c7b13f63aaa..aba07b76fcb 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -145,11 +145,24 @@ abstract class Expr internal constructor() { * Create a constant for a [Boolean] value. * * @param value The [Boolean] value. - * @return A new [Expr] constant instance. + * @return A new [BooleanExpr] constant instance. */ @JvmStatic - fun constant(value: Boolean): Expr { - return ValueConstant(encodeValue(value)) + fun constant(value: Boolean): BooleanExpr { + val encodedValue = encodeValue(value) + return object : BooleanExpr("N/A", emptyArray()) { + override fun toProto(userDataReader: UserDataReader): Value { + return encodedValue + } + + override fun hashCode(): Int { + return encodedValue.hashCode() + } + + override fun toString(): String { + return "constant($value)" + } + } } /** @@ -266,14 +279,35 @@ abstract class Expr internal constructor() { @JvmStatic fun generic(name: String, vararg expr: Expr) = FunctionExpr(name, expr) + /** + * Creates an expression that performs a logical 'AND' operation. + * + * @param condition The first [BooleanExpr]. + * @param conditions Addition [BooleanExpr]s. + * @return A new [BooleanExpr] representing the local 'AND' operation. + */ @JvmStatic fun and(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("and", condition, *conditions) + /** + * Creates an expression that performs a logical 'OR' operation. + * + * @param condition The first [BooleanExpr]. + * @param conditions Addition [BooleanExpr]s. + * @return A new [BooleanExpr] representing the local 'OR' operation. + */ @JvmStatic fun or(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("or", condition, *conditions) + /** + * Creates an expression that performs a logical 'XOR' operation. + * + * @param condition The first [BooleanExpr]. + * @param conditions Addition [BooleanExpr]s. + * @return A new [BooleanExpr] representing the local 'XOR' operation. + */ @JvmStatic fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("xor", condition, *conditions) @@ -344,570 +378,1143 @@ abstract class Expr internal constructor() { fun bitRightShift(fieldName: String, number: Int): Expr = FunctionExpr("bit_right_shift", fieldName, number) + /** + * + */ @JvmStatic fun add(left: Expr, right: Expr): Expr = FunctionExpr("add", left, right) + /** + * + */ @JvmStatic fun add(left: Expr, right: Any): Expr = FunctionExpr("add", left, right) + /** + * + */ @JvmStatic fun add(fieldName: String, other: Expr): Expr = FunctionExpr("add", fieldName, other) + /** + * + */ @JvmStatic fun add(fieldName: String, other: Any): Expr = FunctionExpr("add", fieldName, other) + /** + * + */ @JvmStatic fun subtract(left: Expr, right: Expr): Expr = FunctionExpr("subtract", left, right) + /** + * + */ @JvmStatic fun subtract(left: Expr, right: Any): Expr = FunctionExpr("subtract", left, right) + /** + * + */ @JvmStatic fun subtract(fieldName: String, other: Expr): Expr = FunctionExpr("subtract", fieldName, other) + /** + * + */ @JvmStatic fun subtract(fieldName: String, other: Any): Expr = FunctionExpr("subtract", fieldName, other) + /** + * + */ @JvmStatic fun multiply(left: Expr, right: Expr): Expr = FunctionExpr("multiply", left, right) + /** + * + */ @JvmStatic fun multiply(left: Expr, right: Any): Expr = FunctionExpr("multiply", left, right) + /** + * + */ @JvmStatic fun multiply(fieldName: String, other: Expr): Expr = FunctionExpr("multiply", fieldName, other) + /** + * + */ @JvmStatic fun multiply(fieldName: String, other: Any): Expr = FunctionExpr("multiply", fieldName, other) + /** + * + */ @JvmStatic fun divide(left: Expr, right: Expr): Expr = FunctionExpr("divide", left, right) + /** + * + */ @JvmStatic fun divide(left: Expr, right: Any): Expr = FunctionExpr("divide", left, right) + /** + * + */ @JvmStatic fun divide(fieldName: String, other: Expr): Expr = FunctionExpr("divide", fieldName, other) + /** + * + */ @JvmStatic fun divide(fieldName: String, other: Any): Expr = FunctionExpr("divide", fieldName, other) + /** + * + */ @JvmStatic fun mod(left: Expr, right: Expr): Expr = FunctionExpr("mod", left, right) + /** + * + */ @JvmStatic fun mod(left: Expr, right: Any): Expr = FunctionExpr("mod", left, right) + /** + * + */ @JvmStatic fun mod(fieldName: String, other: Expr): Expr = FunctionExpr("mod", fieldName, other) + /** + * + */ @JvmStatic fun mod(fieldName: String, other: Any): Expr = FunctionExpr("mod", fieldName, other) + /** + * + */ @JvmStatic fun eqAny(value: Expr, values: List) = BooleanExpr("eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) + /** + * + */ @JvmStatic fun eqAny(fieldName: String, values: List) = BooleanExpr("eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + /** + * + */ @JvmStatic fun notEqAny(value: Expr, values: List) = BooleanExpr("not_eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) + /** + * + */ @JvmStatic fun notEqAny(fieldName: String, values: List) = BooleanExpr("not_eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + /** + * + */ @JvmStatic fun isNan(expr: Expr) = BooleanExpr("is_nan", expr) + /** + * + */ @JvmStatic fun isNan(fieldName: String) = BooleanExpr("is_nan", fieldName) + /** + * + */ @JvmStatic fun isNotNan(expr: Expr) = BooleanExpr("is_not_nan", expr) + /** + * + */ @JvmStatic fun isNotNan(fieldName: String) = BooleanExpr("is_not_nan", fieldName) + /** + * + */ @JvmStatic fun isNull(expr: Expr) = BooleanExpr("is_null", expr) + /** + * + */ @JvmStatic fun isNull(fieldName: String) = BooleanExpr("is_null", fieldName) + /** + * + */ @JvmStatic fun isNotNull(expr: Expr) = BooleanExpr("is_not_null", expr) + /** + * + */ @JvmStatic fun isNotNull(fieldName: String) = BooleanExpr("is_not_null", fieldName) + /** + * + */ @JvmStatic fun replaceFirst(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_first", value, find, replace) + /** + * + */ @JvmStatic fun replaceFirst(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_first", value, find, replace) + /** + * + */ @JvmStatic fun replaceFirst(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_first", fieldName, find, replace) + /** + * + */ @JvmStatic fun replaceAll(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_all", value, find, replace) + /** + * + */ @JvmStatic fun replaceAll(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_all", value, find, replace) + /** + * + */ @JvmStatic fun replaceAll(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_all", fieldName, find, replace) + /** + * + */ @JvmStatic fun charLength(value: Expr): Expr = FunctionExpr("char_length", value) + /** + * + */ @JvmStatic fun charLength(fieldName: String): Expr = FunctionExpr("char_length", fieldName) + /** + * + */ @JvmStatic fun byteLength(value: Expr): Expr = FunctionExpr("byte_length", value) + /** + * + */ @JvmStatic fun byteLength(fieldName: String): Expr = FunctionExpr("byte_length", fieldName) + /** + * + */ @JvmStatic fun like(expr: Expr, pattern: Expr) = BooleanExpr("like", expr, pattern) + /** + * + */ @JvmStatic fun like(expr: Expr, pattern: String) = BooleanExpr("like", expr, pattern) + /** + * + */ @JvmStatic fun like(fieldName: String, pattern: Expr) = BooleanExpr("like", fieldName, pattern) + /** + * + */ @JvmStatic fun like(fieldName: String, pattern: String) = BooleanExpr("like", fieldName, pattern) + /** + * + */ @JvmStatic fun regexContains(expr: Expr, pattern: Expr) = BooleanExpr("regex_contains", expr, pattern) + /** + * + */ @JvmStatic fun regexContains(expr: Expr, pattern: String) = BooleanExpr("regex_contains", expr, pattern) + /** + * + */ @JvmStatic fun regexContains(fieldName: String, pattern: Expr) = BooleanExpr("regex_contains", fieldName, pattern) + /** + * + */ @JvmStatic fun regexContains(fieldName: String, pattern: String) = BooleanExpr("regex_contains", fieldName, pattern) + /** + * + */ @JvmStatic fun regexMatch(expr: Expr, pattern: Expr) = BooleanExpr("regex_match", expr, pattern) + /** + * + */ @JvmStatic fun regexMatch(expr: Expr, pattern: String) = BooleanExpr("regex_match", expr, pattern) + /** + * + */ @JvmStatic fun regexMatch(fieldName: String, pattern: Expr) = BooleanExpr("regex_match", fieldName, pattern) + /** + * + */ @JvmStatic fun regexMatch(fieldName: String, pattern: String) = BooleanExpr("regex_match", fieldName, pattern) + /** + * + */ @JvmStatic fun logicalMax(left: Expr, right: Expr): Expr = FunctionExpr("logical_max", left, right) + /** + * + */ @JvmStatic fun logicalMax(left: Expr, right: Any): Expr = FunctionExpr("logical_max", left, right) + /** + * + */ @JvmStatic fun logicalMax(fieldName: String, other: Expr): Expr = FunctionExpr("logical_max", fieldName, other) + /** + * + */ @JvmStatic fun logicalMax(fieldName: String, other: Any): Expr = FunctionExpr("logical_max", fieldName, other) + /** + * + */ @JvmStatic fun logicalMin(left: Expr, right: Expr): Expr = FunctionExpr("logical_min", left, right) + /** + * + */ @JvmStatic fun logicalMin(left: Expr, right: Any): Expr = FunctionExpr("logical_min", left, right) + /** + * + */ @JvmStatic fun logicalMin(fieldName: String, other: Expr): Expr = FunctionExpr("logical_min", fieldName, other) + /** + * + */ @JvmStatic fun logicalMin(fieldName: String, other: Any): Expr = FunctionExpr("logical_min", fieldName, other) + /** + * + */ @JvmStatic fun reverse(expr: Expr): Expr = FunctionExpr("reverse", expr) + /** + * + */ @JvmStatic fun reverse(fieldName: String): Expr = FunctionExpr("reverse", fieldName) + /** + * + */ @JvmStatic fun strContains(expr: Expr, substring: Expr) = BooleanExpr("str_contains", expr, substring) + /** + * + */ @JvmStatic fun strContains(expr: Expr, substring: String) = BooleanExpr("str_contains", expr, substring) + /** + * + */ @JvmStatic fun strContains(fieldName: String, substring: Expr) = BooleanExpr("str_contains", fieldName, substring) + /** + * + */ @JvmStatic fun strContains(fieldName: String, substring: String) = BooleanExpr("str_contains", fieldName, substring) + /** + * + */ @JvmStatic fun startsWith(expr: Expr, prefix: Expr) = BooleanExpr("starts_with", expr, prefix) + /** + * + */ @JvmStatic fun startsWith(expr: Expr, prefix: String) = BooleanExpr("starts_with", expr, prefix) + /** + * + */ @JvmStatic fun startsWith(fieldName: String, prefix: Expr) = BooleanExpr("starts_with", fieldName, prefix) + /** + * + */ @JvmStatic fun startsWith(fieldName: String, prefix: String) = BooleanExpr("starts_with", fieldName, prefix) + /** + * + */ @JvmStatic fun endsWith(expr: Expr, suffix: Expr) = BooleanExpr("ends_with", expr, suffix) + /** + * + */ @JvmStatic fun endsWith(expr: Expr, suffix: String) = BooleanExpr("ends_with", expr, suffix) + /** + * + */ @JvmStatic fun endsWith(fieldName: String, suffix: Expr) = BooleanExpr("ends_with", fieldName, suffix) + /** + * + */ @JvmStatic fun endsWith(fieldName: String, suffix: String) = BooleanExpr("ends_with", fieldName, suffix) + /** + * + */ @JvmStatic fun toLower(expr: Expr): Expr = FunctionExpr("to_lower", expr) + /** + * + */ @JvmStatic fun toLower( fieldName: String, ): Expr = FunctionExpr("to_lower", fieldName) + /** + * + */ @JvmStatic fun toUpper(expr: Expr): Expr = FunctionExpr("to_upper", expr) - @JvmStatic + /** + * + */ + @JvmStatic fun toUpper( fieldName: String, ): Expr = FunctionExpr("to_upper", fieldName) + /** + * + */ @JvmStatic fun trim(expr: Expr): Expr = FunctionExpr("trim", expr) + /** + * + */ @JvmStatic fun trim(fieldName: String): Expr = FunctionExpr("trim", fieldName) + /** + * + */ @JvmStatic fun strConcat(first: Expr, vararg rest: Expr): Expr = FunctionExpr("str_concat", first, *rest) + /** + * + */ @JvmStatic fun strConcat(first: Expr, vararg rest: Any): Expr = FunctionExpr("str_concat", first, *rest) + /** + * + */ @JvmStatic fun strConcat(fieldName: String, vararg rest: Expr): Expr = FunctionExpr("str_concat", fieldName, *rest) + /** + * + */ @JvmStatic fun strConcat(fieldName: String, vararg rest: Any): Expr = FunctionExpr("str_concat", fieldName, *rest) internal fun map(elements: Array): Expr = FunctionExpr("map", elements) + /** + * + */ @JvmStatic fun map(elements: Map) = map(elements.flatMap { listOf(constant(it.key), toExprOrConstant(it.value)) }.toTypedArray()) + /** + * + */ @JvmStatic fun mapGet(map: Expr, key: Expr): Expr = FunctionExpr("map_get", map, key) + /** + * + */ @JvmStatic fun mapGet(map: Expr, key: String): Expr = FunctionExpr("map_get", map, key) + /** + * + */ @JvmStatic fun mapGet(fieldName: String, key: Expr): Expr = FunctionExpr("map_get", fieldName, key) + /** + * + */ @JvmStatic fun mapGet(fieldName: String, key: String): Expr = FunctionExpr("map_get", fieldName, key) + /** + * + */ @JvmStatic fun mapMerge(firstMap: Expr, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", firstMap, secondMap, otherMaps) + /** + * + */ @JvmStatic fun mapMerge(mapField: String, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", mapField, secondMap, otherMaps) + /** + * + */ @JvmStatic fun mapRemove(firstMap: Expr, key: Expr): Expr = FunctionExpr("map_remove", firstMap, key) + /** + * + */ @JvmStatic fun mapRemove(mapField: String, key: Expr): Expr = FunctionExpr("map_remove", mapField, key) + /** + * + */ @JvmStatic fun mapRemove(firstMap: Expr, key: String): Expr = FunctionExpr("map_remove", firstMap, key) + /** + * + */ @JvmStatic fun mapRemove(mapField: String, key: String): Expr = FunctionExpr("map_remove", mapField, key) + /** + * + */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("cosine_distance", vector1, vector2) + /** + * + */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("cosine_distance", vector1, vector(vector2)) + /** + * + */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("cosine_distance", vector1, vector2) + /** + * + */ @JvmStatic fun cosineDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("cosine_distance", fieldName, vector) + /** + * + */ @JvmStatic fun cosineDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("cosine_distance", fieldName, vector(vector)) + /** + * + */ @JvmStatic fun cosineDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("cosine_distance", fieldName, vector) + /** + * + */ @JvmStatic fun dotProduct(vector1: Expr, vector2: Expr): Expr = FunctionExpr("dot_product", vector1, vector2) + /** + * + */ @JvmStatic fun dotProduct(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("dot_product", vector1, vector(vector2)) + /** + * + */ @JvmStatic fun dotProduct(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("dot_product", vector1, vector2) + /** + * + */ @JvmStatic fun dotProduct(fieldName: String, vector: Expr): Expr = FunctionExpr("dot_product", fieldName, vector) + /** + * + */ @JvmStatic fun dotProduct(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("dot_product", fieldName, vector(vector)) + /** + * + */ @JvmStatic fun dotProduct(fieldName: String, vector: VectorValue): Expr = FunctionExpr("dot_product", fieldName, vector) + /** + * + */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("euclidean_distance", vector1, vector2) + /** + * + */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("euclidean_distance", vector1, vector(vector2)) + /** + * + */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("euclidean_distance", vector1, vector2) + /** + * + */ @JvmStatic fun euclideanDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("euclidean_distance", fieldName, vector) + /** + * + */ @JvmStatic fun euclideanDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("euclidean_distance", fieldName, vector(vector)) + /** + * + */ @JvmStatic fun euclideanDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("euclidean_distance", fieldName, vector) + /** + * + */ @JvmStatic fun vectorLength(vector: Expr): Expr = FunctionExpr("vector_length", vector) + /** + * + */ @JvmStatic fun vectorLength(fieldName: String): Expr = FunctionExpr("vector_length", fieldName) + /** + * + */ @JvmStatic fun unixMicrosToTimestamp(input: Expr): Expr = FunctionExpr("unix_micros_to_timestamp", input) + /** + * + */ @JvmStatic fun unixMicrosToTimestamp(fieldName: String): Expr = FunctionExpr("unix_micros_to_timestamp", fieldName) + /** + * + */ @JvmStatic fun timestampToUnixMicros(input: Expr): Expr = FunctionExpr("timestamp_to_unix_micros", input) + /** + * + */ @JvmStatic fun timestampToUnixMicros(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_micros", fieldName) + /** + * + */ @JvmStatic fun unixMillisToTimestamp(input: Expr): Expr = FunctionExpr("unix_millis_to_timestamp", input) + /** + * + */ @JvmStatic fun unixMillisToTimestamp(fieldName: String): Expr = FunctionExpr("unix_millis_to_timestamp", fieldName) + /** + * + */ @JvmStatic fun timestampToUnixMillis(input: Expr): Expr = FunctionExpr("timestamp_to_unix_millis", input) + /** + * + */ @JvmStatic fun timestampToUnixMillis(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_millis", fieldName) + /** + * + */ @JvmStatic fun unixSecondsToTimestamp(input: Expr): Expr = FunctionExpr("unix_seconds_to_timestamp", input) + /** + * + */ @JvmStatic fun unixSecondsToTimestamp(fieldName: String): Expr = FunctionExpr("unix_seconds_to_timestamp", fieldName) + /** + * + */ @JvmStatic fun timestampToUnixSeconds(input: Expr): Expr = FunctionExpr("timestamp_to_unix_seconds", input) + /** + * + */ @JvmStatic fun timestampToUnixSeconds(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_seconds", fieldName) + /** + * + */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) + /** + * + */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) + /** + * + */ @JvmStatic fun timestampAdd(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) + /** + * + */ @JvmStatic fun timestampAdd(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) + /** + * + */ @JvmStatic fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) + /** + * + */ @JvmStatic fun timestampSub(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) + /** + * + */ @JvmStatic fun timestampSub(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) + /** + * + */ @JvmStatic fun timestampSub(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) + /** + * + */ @JvmStatic fun eq(left: Expr, right: Expr) = BooleanExpr("eq", left, right) + /** + * + */ @JvmStatic fun eq(left: Expr, right: Any) = BooleanExpr("eq", left, right) + /** + * + */ @JvmStatic fun eq(fieldName: String, right: Expr) = BooleanExpr("eq", fieldName, right) + /** + * + */ @JvmStatic fun eq(fieldName: String, right: Any) = BooleanExpr("eq", fieldName, right) + /** + * + */ @JvmStatic fun neq(left: Expr, right: Expr) = BooleanExpr("neq", left, right) + /** + * + */ @JvmStatic fun neq(left: Expr, right: Any) = BooleanExpr("neq", left, right) + /** + * + */ @JvmStatic fun neq(fieldName: String, right: Expr) = BooleanExpr("neq", fieldName, right) + /** + * + */ @JvmStatic fun neq(fieldName: String, right: Any) = BooleanExpr("neq", fieldName, right) + /** + * + */ @JvmStatic fun gt(left: Expr, right: Expr) = BooleanExpr("gt", left, right) + /** + * + */ @JvmStatic fun gt(left: Expr, right: Any) = BooleanExpr("gt", left, right) + /** + * + */ @JvmStatic fun gt(fieldName: String, right: Expr) = BooleanExpr("gt", fieldName, right) + /** + * + */ @JvmStatic fun gt(fieldName: String, right: Any) = BooleanExpr("gt", fieldName, right) + /** + * + */ @JvmStatic fun gte(left: Expr, right: Expr) = BooleanExpr("gte", left, right) + /** + * + */ @JvmStatic fun gte(left: Expr, right: Any) = BooleanExpr("gte", left, right) + /** + * + */ @JvmStatic fun gte(fieldName: String, right: Expr) = BooleanExpr("gte", fieldName, right) + /** + * + */ @JvmStatic fun gte(fieldName: String, right: Any) = BooleanExpr("gte", fieldName, right) + /** + * + */ @JvmStatic fun lt(left: Expr, right: Expr) = BooleanExpr("lt", left, right) + /** + * + */ @JvmStatic fun lt(left: Expr, right: Any) = BooleanExpr("lt", left, right) + /** + * + */ @JvmStatic fun lt(fieldName: String, right: Expr) = BooleanExpr("lt", fieldName, right) + /** + * + */ @JvmStatic fun lt(fieldName: String, right: Any) = BooleanExpr("lt", fieldName, right) + /** + * + */ @JvmStatic fun lte(left: Expr, right: Expr) = BooleanExpr("lte", left, right) + /** + * + */ @JvmStatic fun lte(left: Expr, right: Any) = BooleanExpr("lte", left, right) + /** + * + */ @JvmStatic fun lte(fieldName: String, right: Expr) = BooleanExpr("lte", fieldName, right) + /** + * + */ @JvmStatic fun lte(fieldName: String, right: Any) = BooleanExpr("lte", fieldName, right) + /** + * + */ @JvmStatic fun arrayConcat(array: Expr, vararg arrays: Expr): Expr = FunctionExpr("array_concat", array, *arrays) + /** + * + */ @JvmStatic fun arrayConcat(fieldName: String, vararg arrays: Expr): Expr = FunctionExpr("array_concat", fieldName, *arrays) + /** + * + */ @JvmStatic fun arrayConcat(array: Expr, arrays: List): Expr = FunctionExpr("array_concat", array, ListOfExprs(toArrayOfExprOrConstant(arrays))) + /** + * + */ @JvmStatic fun arrayConcat(fieldName: String, arrays: List): Expr = FunctionExpr("array_concat", fieldName, ListOfExprs(toArrayOfExprOrConstant(arrays))) + /** + * + */ @JvmStatic fun arrayReverse(array: Expr): Expr = FunctionExpr("array_reverse", array) + /** + * + */ @JvmStatic fun arrayReverse(fieldName: String): Expr = FunctionExpr("array_reverse", fieldName) + /** + * + */ @JvmStatic fun arrayContains(array: Expr, value: Expr) = BooleanExpr("array_contains", array, value) + /** + * + */ @JvmStatic fun arrayContains(fieldName: String, value: Expr) = BooleanExpr("array_contains", fieldName, value) + /** + * + */ @JvmStatic fun arrayContains(array: Expr, value: Any) = BooleanExpr("array_contains", array, value) + /** + * + */ @JvmStatic fun arrayContains(fieldName: String, value: Any) = BooleanExpr("array_contains", fieldName, value) + /** + * + */ @JvmStatic fun arrayContainsAll(array: Expr, values: List) = BooleanExpr("array_contains_all", array, ListOfExprs(toArrayOfExprOrConstant(values))) + /** + * + */ @JvmStatic fun arrayContainsAll(fieldName: String, values: List) = BooleanExpr("array_contains_all", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + /** + * + */ @JvmStatic fun arrayContainsAny(array: Expr, values: List) = BooleanExpr("array_contains_any", array, ListOfExprs(toArrayOfExprOrConstant(values))) + /** + * + */ @JvmStatic fun arrayContainsAny(fieldName: String, values: List) = BooleanExpr("array_contains_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + /** + * + */ @JvmStatic fun arrayLength(array: Expr): Expr = FunctionExpr("array_length", array) + /** + * + */ @JvmStatic fun arrayLength(fieldName: String): Expr = FunctionExpr("array_length", fieldName) + /** + * + */ @JvmStatic fun cond(condition: BooleanExpr, then: Expr, otherwise: Expr): Expr = FunctionExpr("cond", condition, then, otherwise) + /** + * + */ @JvmStatic fun cond(condition: BooleanExpr, then: Any, otherwise: Any): Expr = FunctionExpr("cond", condition, then, otherwise) + /** + * + */ @JvmStatic fun exists(expr: Expr) = BooleanExpr("exists", expr) } + /** + * + */ fun bitAnd(right: Expr) = bitAnd(this, right) + /** + * + */ fun bitAnd(right: Any) = bitAnd(this, right) + /** + * + */ fun bitOr(right: Expr) = bitOr(this, right) + /** + * + */ fun bitOr(right: Any) = bitOr(this, right) + /** + * + */ fun bitXor(right: Expr) = bitXor(this, right) + /** + * + */ fun bitXor(right: Any) = bitXor(this, right) + /** + * + */ fun bitNot() = bitNot(this) + /** + * + */ fun bitLeftShift(numberExpr: Expr) = bitLeftShift(this, numberExpr) + /** + * + */ fun bitLeftShift(number: Int) = bitLeftShift(this, number) + /** + * + */ fun bitRightShift(numberExpr: Expr) = bitRightShift(this, numberExpr) + /** + * + */ fun bitRightShift(number: Int) = bitRightShift(this, number) /** @@ -955,195 +1562,480 @@ abstract class Expr internal constructor() { */ fun add(other: Any) = add(this, other) + /** + * + */ fun subtract(other: Expr) = subtract(this, other) + /** + * + */ fun subtract(other: Any) = subtract(this, other) + /** + * + */ fun multiply(other: Expr) = multiply(this, other) + /** + * + */ fun multiply(other: Any) = multiply(this, other) + /** + * + */ fun divide(other: Expr) = divide(this, other) + /** + * + */ fun divide(other: Any) = divide(this, other) + /** + * + */ fun mod(other: Expr) = mod(this, other) + /** + * + */ fun mod(other: Any) = mod(this, other) + /** + * + */ fun eqAny(values: List) = eqAny(this, values) + /** + * + */ fun notEqAny(values: List) = notEqAny(this, values) + /** + * + */ fun isNan() = isNan(this) + /** + * + */ fun isNotNan() = isNotNan(this) + /** + * + */ fun isNull() = isNull(this) + /** + * + */ fun isNotNull() = isNotNull(this) + /** + * + */ fun replaceFirst(find: Expr, replace: Expr) = replaceFirst(this, find, replace) + /** + * + */ fun replaceFirst(find: String, replace: String) = replaceFirst(this, find, replace) + /** + * + */ fun replaceAll(find: Expr, replace: Expr) = replaceAll(this, find, replace) + /** + * + */ fun replaceAll(find: String, replace: String) = replaceAll(this, find, replace) + /** + * + */ fun charLength() = charLength(this) + /** + * + */ fun byteLength() = byteLength(this) + /** + * + */ fun like(pattern: Expr) = like(this, pattern) + /** + * + */ fun like(pattern: String) = like(this, pattern) + /** + * + */ fun regexContains(pattern: Expr) = regexContains(this, pattern) + /** + * + */ fun regexContains(pattern: String) = regexContains(this, pattern) + /** + * + */ fun regexMatch(pattern: Expr) = regexMatch(this, pattern) + /** + * + */ fun regexMatch(pattern: String) = regexMatch(this, pattern) + /** + * + */ fun logicalMax(other: Expr) = logicalMax(this, other) + /** + * + */ fun logicalMax(other: Any) = logicalMax(this, other) + /** + * + */ fun logicalMin(other: Expr) = logicalMin(this, other) + /** + * + */ fun logicalMin(other: Any) = logicalMin(this, other) + /** + * + */ fun reverse() = reverse(this) + /** + * + */ fun strContains(substring: Expr) = strContains(this, substring) + /** + * + */ fun strContains(substring: String) = strContains(this, substring) + /** + * + */ fun startsWith(prefix: Expr) = startsWith(this, prefix) + /** + * + */ fun startsWith(prefix: String) = startsWith(this, prefix) + /** + * + */ fun endsWith(suffix: Expr) = endsWith(this, suffix) + /** + * + */ fun endsWith(suffix: String) = endsWith(this, suffix) + /** + * + */ fun toLower() = toLower(this) + /** + * + */ fun toUpper() = toUpper(this) + /** + * + */ fun trim() = trim(this) + /** + * + */ fun strConcat(vararg expr: Expr) = Companion.strConcat(this, *expr) + /** + * + */ fun strConcat(vararg string: String) = strConcat(this, *string) + /** + * + */ fun strConcat(vararg string: Any) = Companion.strConcat(this, *string) + /** + * + */ fun mapGet(key: Expr) = mapGet(this, key) + /** + * + */ fun mapGet(key: String) = mapGet(this, key) + /** + * + */ fun mapMerge(secondMap: Expr, vararg otherMaps: Expr) = Companion.mapMerge(this, secondMap, *otherMaps) + /** + * + */ fun mapRemove(key: Expr) = mapRemove(this, key) + /** + * + */ fun mapRemove(key: String) = mapRemove(this, key) + /** + * + */ fun cosineDistance(vector: Expr) = cosineDistance(this, vector) + /** + * + */ fun cosineDistance(vector: DoubleArray) = cosineDistance(this, vector) + /** + * + */ fun cosineDistance(vector: VectorValue) = cosineDistance(this, vector) + /** + * + */ fun dotProduct(vector: Expr) = dotProduct(this, vector) + /** + * + */ fun dotProduct(vector: DoubleArray) = dotProduct(this, vector) + /** + * + */ fun dotProduct(vector: VectorValue) = dotProduct(this, vector) + /** + * + */ fun euclideanDistance(vector: Expr) = euclideanDistance(this, vector) + /** + * + */ fun euclideanDistance(vector: DoubleArray) = euclideanDistance(this, vector) + /** + * + */ fun euclideanDistance(vector: VectorValue) = euclideanDistance(this, vector) + /** + * + */ fun vectorLength() = vectorLength(this) + /** + * + */ fun unixMicrosToTimestamp() = unixMicrosToTimestamp(this) + /** + * + */ fun timestampToUnixMicros() = timestampToUnixMicros(this) + /** + * + */ fun unixMillisToTimestamp() = unixMillisToTimestamp(this) + /** + * + */ fun timestampToUnixMillis() = timestampToUnixMillis(this) + /** + * + */ fun unixSecondsToTimestamp() = unixSecondsToTimestamp(this) + /** + * + */ fun timestampToUnixSeconds() = timestampToUnixSeconds(this) + /** + * + */ fun timestampAdd(unit: Expr, amount: Expr) = timestampAdd(this, unit, amount) + /** + * + */ fun timestampAdd(unit: String, amount: Double) = timestampAdd(this, unit, amount) + /** + * + */ fun timestampSub(unit: Expr, amount: Expr) = timestampSub(this, unit, amount) + /** + * + */ fun timestampSub(unit: String, amount: Double) = timestampSub(this, unit, amount) + /** + * + */ fun arrayConcat(vararg arrays: Expr) = Companion.arrayConcat(this, *arrays) + /** + * + */ fun arrayConcat(arrays: List) = arrayConcat(this, arrays) + /** + * + */ fun arrayReverse() = arrayReverse(this) + /** + * + */ fun arrayContains(value: Expr) = arrayContains(this, value) + /** + * + */ fun arrayContains(value: Any) = arrayContains(this, value) + /** + * + */ fun arrayContainsAll(values: List) = arrayContainsAll(this, values) + /** + * + */ fun arrayContainsAny(values: List) = arrayContainsAny(this, values) + /** + * + */ fun arrayLength() = arrayLength(this) + /** + * + */ fun sum() = AggregateFunction.sum(this) + /** + * + */ fun avg() = AggregateFunction.avg(this) + /** + * + */ fun min() = AggregateFunction.min(this) + /** + * + */ fun max() = AggregateFunction.max(this) + /** + * + */ fun ascending() = Ordering.ascending(this) + /** + * + */ fun descending() = Ordering.descending(this) + /** + * + */ fun eq(other: Expr) = eq(this, other) + /** + * + */ fun eq(other: Any) = eq(this, other) + /** + * + */ fun neq(other: Expr) = neq(this, other) + /** + * + */ fun neq(other: Any) = neq(this, other) + /** + * + */ fun gt(other: Expr) = gt(this, other) + /** + * + */ fun gt(other: Any) = gt(this, other) + /** + * + */ fun gte(other: Expr) = gte(this, other) + /** + * + */ fun gte(other: Any) = gte(this, other) + /** + * + */ fun lt(other: Expr) = lt(this, other) + /** + * + */ fun lt(other: Any) = lt(this, other) + /** + * + */ fun lte(other: Expr) = lte(this, other) + /** + * + */ fun lte(other: Any) = lte(this, other) + /** + * + */ fun exists() = exists(this) internal abstract fun toProto(userDataReader: UserDataReader): Value @@ -1240,7 +2132,7 @@ internal constructor(private val name: String, private val params: Array) : +open class BooleanExpr internal constructor(name: String, params: Array) : FunctionExpr(name, params) { internal constructor( name: String, @@ -1259,15 +2151,30 @@ class BooleanExpr internal constructor(name: String, params: Array) : companion object { + /** + * + */ @JvmStatic fun generic(name: String, vararg expr: Expr) = BooleanExpr(name, expr) } + /** + * + */ fun not() = not(this) + /** + * + */ fun countIf(): AggregateFunction = AggregateFunction.countIf(this) + /** + * + */ fun cond(then: Expr, otherwise: Expr) = cond(this, then, otherwise) + /** + * + */ fun cond(then: Any, otherwise: Any) = cond(this, then, otherwise) } From ed24e71331c5b139218d2e1dd6623a4c0c5ecc80 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Wed, 23 Apr 2025 15:59:03 -0400 Subject: [PATCH 45/77] Comments --- .../firestore/pipeline/expressions.kt | 557 +++++------------- 1 file changed, 143 insertions(+), 414 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index aba07b76fcb..0d6c041bb92 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -26,6 +26,7 @@ import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.FieldPath as ModelFieldPath import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.Values.encodeValue +import com.google.firebase.firestore.pipeline.Expr.Companion.field import com.google.firebase.firestore.util.CustomClassMapper import com.google.firestore.v1.MapValue import com.google.firestore.v1.Value @@ -284,7 +285,7 @@ abstract class Expr internal constructor() { * * @param condition The first [BooleanExpr]. * @param conditions Addition [BooleanExpr]s. - * @return A new [BooleanExpr] representing the local 'AND' operation. + * @return A new [BooleanExpr] representing the logical 'AND' operation. */ @JvmStatic fun and(condition: BooleanExpr, vararg conditions: BooleanExpr) = @@ -295,7 +296,7 @@ abstract class Expr internal constructor() { * * @param condition The first [BooleanExpr]. * @param conditions Addition [BooleanExpr]s. - * @return A new [BooleanExpr] representing the local 'OR' operation. + * @return A new [BooleanExpr] representing the logical 'OR' operation. */ @JvmStatic fun or(condition: BooleanExpr, vararg conditions: BooleanExpr) = @@ -306,7 +307,7 @@ abstract class Expr internal constructor() { * * @param condition The first [BooleanExpr]. * @param conditions Addition [BooleanExpr]s. - * @return A new [BooleanExpr] representing the local 'XOR' operation. + * @return A new [BooleanExpr] representing the logical 'XOR' operation. */ @JvmStatic fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = @@ -379,453 +380,405 @@ abstract class Expr internal constructor() { FunctionExpr("bit_right_shift", fieldName, number) /** + * Creates an expression that adds this expression to another expression. * + * @param first The first expression to add. + * @param second The second expression to add to first expression. + * @param others Additional expression or literal to add. + * @return A new [Expr] representing the addition operation. */ - @JvmStatic fun add(left: Expr, right: Expr): Expr = FunctionExpr("add", left, right) + @JvmStatic + fun add(first: Expr, second: Expr, vararg others: Any): Expr = + FunctionExpr("add", first, second, *others) /** + * Creates an expression that adds this expression to another expression. * + * @param first The first expression to add. + * @param second The second expression or literal to add to first expression. + * @param others Additional expression or literal to add. + * @return A new [Expr] representing the addition operation. */ - @JvmStatic fun add(left: Expr, right: Any): Expr = FunctionExpr("add", left, right) + @JvmStatic + fun add(first: Expr, second: Any, vararg others: Any): Expr = + FunctionExpr("add", first, second, *others) /** + * Creates an expression that adds a field's value to an expression. * + * @param fieldName The name of the field containing the value to add. + * @param second The second expression to add to field value. + * @param others Additional expression or literal to add. */ - @JvmStatic fun add(fieldName: String, other: Expr): Expr = FunctionExpr("add", fieldName, other) + @JvmStatic + fun add(fieldName: String, second: Expr, vararg others: Any): Expr = + FunctionExpr("add", fieldName, second, *others) /** + * Creates an expression that adds a field's value to an expression. * + * @param fieldName The name of the field containing the value to add. + * @param second The second expression or literal to add to field value. + * @param others Additional expression or literal to add. */ - @JvmStatic fun add(fieldName: String, other: Any): Expr = FunctionExpr("add", fieldName, other) + @JvmStatic + fun add(fieldName: String, second: Any, vararg others: Any): Expr = + FunctionExpr("add", fieldName, second, *others) /** - * */ @JvmStatic fun subtract(left: Expr, right: Expr): Expr = FunctionExpr("subtract", left, right) /** - * */ @JvmStatic fun subtract(left: Expr, right: Any): Expr = FunctionExpr("subtract", left, right) /** - * */ @JvmStatic fun subtract(fieldName: String, other: Expr): Expr = FunctionExpr("subtract", fieldName, other) /** - * */ @JvmStatic fun subtract(fieldName: String, other: Any): Expr = FunctionExpr("subtract", fieldName, other) /** - * */ @JvmStatic fun multiply(left: Expr, right: Expr): Expr = FunctionExpr("multiply", left, right) /** - * */ @JvmStatic fun multiply(left: Expr, right: Any): Expr = FunctionExpr("multiply", left, right) /** - * */ @JvmStatic fun multiply(fieldName: String, other: Expr): Expr = FunctionExpr("multiply", fieldName, other) /** - * */ @JvmStatic fun multiply(fieldName: String, other: Any): Expr = FunctionExpr("multiply", fieldName, other) /** - * */ @JvmStatic fun divide(left: Expr, right: Expr): Expr = FunctionExpr("divide", left, right) /** - * */ @JvmStatic fun divide(left: Expr, right: Any): Expr = FunctionExpr("divide", left, right) /** - * */ @JvmStatic fun divide(fieldName: String, other: Expr): Expr = FunctionExpr("divide", fieldName, other) /** - * */ @JvmStatic fun divide(fieldName: String, other: Any): Expr = FunctionExpr("divide", fieldName, other) /** - * */ @JvmStatic fun mod(left: Expr, right: Expr): Expr = FunctionExpr("mod", left, right) /** - * */ @JvmStatic fun mod(left: Expr, right: Any): Expr = FunctionExpr("mod", left, right) /** - * */ @JvmStatic fun mod(fieldName: String, other: Expr): Expr = FunctionExpr("mod", fieldName, other) /** - * */ @JvmStatic fun mod(fieldName: String, other: Any): Expr = FunctionExpr("mod", fieldName, other) /** - * */ @JvmStatic fun eqAny(value: Expr, values: List) = BooleanExpr("eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) /** - * */ @JvmStatic fun eqAny(fieldName: String, values: List) = BooleanExpr("eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) /** - * */ @JvmStatic fun notEqAny(value: Expr, values: List) = BooleanExpr("not_eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) /** - * */ @JvmStatic fun notEqAny(fieldName: String, values: List) = BooleanExpr("not_eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) /** - * */ @JvmStatic fun isNan(expr: Expr) = BooleanExpr("is_nan", expr) /** - * */ @JvmStatic fun isNan(fieldName: String) = BooleanExpr("is_nan", fieldName) /** - * */ @JvmStatic fun isNotNan(expr: Expr) = BooleanExpr("is_not_nan", expr) /** - * */ @JvmStatic fun isNotNan(fieldName: String) = BooleanExpr("is_not_nan", fieldName) /** - * */ @JvmStatic fun isNull(expr: Expr) = BooleanExpr("is_null", expr) /** - * */ @JvmStatic fun isNull(fieldName: String) = BooleanExpr("is_null", fieldName) /** - * */ @JvmStatic fun isNotNull(expr: Expr) = BooleanExpr("is_not_null", expr) /** - * */ @JvmStatic fun isNotNull(fieldName: String) = BooleanExpr("is_not_null", fieldName) /** - * */ @JvmStatic fun replaceFirst(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_first", value, find, replace) /** - * */ @JvmStatic fun replaceFirst(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_first", value, find, replace) /** - * */ @JvmStatic fun replaceFirst(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_first", fieldName, find, replace) /** - * */ @JvmStatic fun replaceAll(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_all", value, find, replace) /** - * */ @JvmStatic fun replaceAll(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_all", value, find, replace) /** - * */ @JvmStatic fun replaceAll(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_all", fieldName, find, replace) /** - * */ @JvmStatic fun charLength(value: Expr): Expr = FunctionExpr("char_length", value) /** - * */ @JvmStatic fun charLength(fieldName: String): Expr = FunctionExpr("char_length", fieldName) /** - * */ @JvmStatic fun byteLength(value: Expr): Expr = FunctionExpr("byte_length", value) /** - * */ @JvmStatic fun byteLength(fieldName: String): Expr = FunctionExpr("byte_length", fieldName) /** - * */ @JvmStatic fun like(expr: Expr, pattern: Expr) = BooleanExpr("like", expr, pattern) /** - * */ @JvmStatic fun like(expr: Expr, pattern: String) = BooleanExpr("like", expr, pattern) /** - * */ @JvmStatic fun like(fieldName: String, pattern: Expr) = BooleanExpr("like", fieldName, pattern) /** - * */ @JvmStatic fun like(fieldName: String, pattern: String) = BooleanExpr("like", fieldName, pattern) /** - * */ @JvmStatic fun regexContains(expr: Expr, pattern: Expr) = BooleanExpr("regex_contains", expr, pattern) /** - * */ @JvmStatic fun regexContains(expr: Expr, pattern: String) = BooleanExpr("regex_contains", expr, pattern) /** - * */ @JvmStatic fun regexContains(fieldName: String, pattern: Expr) = BooleanExpr("regex_contains", fieldName, pattern) /** - * */ @JvmStatic fun regexContains(fieldName: String, pattern: String) = BooleanExpr("regex_contains", fieldName, pattern) /** - * */ @JvmStatic fun regexMatch(expr: Expr, pattern: Expr) = BooleanExpr("regex_match", expr, pattern) /** - * */ @JvmStatic fun regexMatch(expr: Expr, pattern: String) = BooleanExpr("regex_match", expr, pattern) /** - * */ @JvmStatic fun regexMatch(fieldName: String, pattern: Expr) = BooleanExpr("regex_match", fieldName, pattern) /** - * */ @JvmStatic fun regexMatch(fieldName: String, pattern: String) = BooleanExpr("regex_match", fieldName, pattern) /** - * */ @JvmStatic fun logicalMax(left: Expr, right: Expr): Expr = FunctionExpr("logical_max", left, right) /** - * */ @JvmStatic fun logicalMax(left: Expr, right: Any): Expr = FunctionExpr("logical_max", left, right) /** - * */ @JvmStatic fun logicalMax(fieldName: String, other: Expr): Expr = FunctionExpr("logical_max", fieldName, other) /** - * */ @JvmStatic fun logicalMax(fieldName: String, other: Any): Expr = FunctionExpr("logical_max", fieldName, other) /** - * */ @JvmStatic fun logicalMin(left: Expr, right: Expr): Expr = FunctionExpr("logical_min", left, right) /** - * */ @JvmStatic fun logicalMin(left: Expr, right: Any): Expr = FunctionExpr("logical_min", left, right) /** - * */ @JvmStatic fun logicalMin(fieldName: String, other: Expr): Expr = FunctionExpr("logical_min", fieldName, other) /** - * */ @JvmStatic fun logicalMin(fieldName: String, other: Any): Expr = FunctionExpr("logical_min", fieldName, other) /** - * */ @JvmStatic fun reverse(expr: Expr): Expr = FunctionExpr("reverse", expr) /** - * */ @JvmStatic fun reverse(fieldName: String): Expr = FunctionExpr("reverse", fieldName) /** - * */ @JvmStatic fun strContains(expr: Expr, substring: Expr) = BooleanExpr("str_contains", expr, substring) /** - * */ @JvmStatic fun strContains(expr: Expr, substring: String) = BooleanExpr("str_contains", expr, substring) /** - * */ @JvmStatic fun strContains(fieldName: String, substring: Expr) = BooleanExpr("str_contains", fieldName, substring) /** - * */ @JvmStatic fun strContains(fieldName: String, substring: String) = BooleanExpr("str_contains", fieldName, substring) /** - * */ @JvmStatic fun startsWith(expr: Expr, prefix: Expr) = BooleanExpr("starts_with", expr, prefix) /** - * */ @JvmStatic fun startsWith(expr: Expr, prefix: String) = BooleanExpr("starts_with", expr, prefix) /** - * */ @JvmStatic fun startsWith(fieldName: String, prefix: Expr) = BooleanExpr("starts_with", fieldName, prefix) /** - * */ @JvmStatic fun startsWith(fieldName: String, prefix: String) = BooleanExpr("starts_with", fieldName, prefix) /** - * */ @JvmStatic fun endsWith(expr: Expr, suffix: Expr) = BooleanExpr("ends_with", expr, suffix) /** - * */ @JvmStatic fun endsWith(expr: Expr, suffix: String) = BooleanExpr("ends_with", expr, suffix) /** - * */ @JvmStatic fun endsWith(fieldName: String, suffix: Expr) = BooleanExpr("ends_with", fieldName, suffix) /** - * */ @JvmStatic fun endsWith(fieldName: String, suffix: String) = BooleanExpr("ends_with", fieldName, suffix) /** - * */ @JvmStatic fun toLower(expr: Expr): Expr = FunctionExpr("to_lower", expr) /** - * */ @JvmStatic fun toLower( @@ -833,12 +786,10 @@ abstract class Expr internal constructor() { ): Expr = FunctionExpr("to_lower", fieldName) /** - * */ @JvmStatic fun toUpper(expr: Expr): Expr = FunctionExpr("to_upper", expr) /** - * */ @JvmStatic fun toUpper( @@ -846,36 +797,30 @@ abstract class Expr internal constructor() { ): Expr = FunctionExpr("to_upper", fieldName) /** - * */ @JvmStatic fun trim(expr: Expr): Expr = FunctionExpr("trim", expr) /** - * */ @JvmStatic fun trim(fieldName: String): Expr = FunctionExpr("trim", fieldName) /** - * */ @JvmStatic fun strConcat(first: Expr, vararg rest: Expr): Expr = FunctionExpr("str_concat", first, *rest) /** - * */ @JvmStatic fun strConcat(first: Expr, vararg rest: Any): Expr = FunctionExpr("str_concat", first, *rest) /** - * */ @JvmStatic fun strConcat(fieldName: String, vararg rest: Expr): Expr = FunctionExpr("str_concat", fieldName, *rest) /** - * */ @JvmStatic fun strConcat(fieldName: String, vararg rest: Any): Expr = @@ -884,651 +829,539 @@ abstract class Expr internal constructor() { internal fun map(elements: Array): Expr = FunctionExpr("map", elements) /** - * */ @JvmStatic fun map(elements: Map) = map(elements.flatMap { listOf(constant(it.key), toExprOrConstant(it.value)) }.toTypedArray()) /** - * */ @JvmStatic fun mapGet(map: Expr, key: Expr): Expr = FunctionExpr("map_get", map, key) /** - * */ @JvmStatic fun mapGet(map: Expr, key: String): Expr = FunctionExpr("map_get", map, key) /** - * */ @JvmStatic fun mapGet(fieldName: String, key: Expr): Expr = FunctionExpr("map_get", fieldName, key) /** - * */ @JvmStatic fun mapGet(fieldName: String, key: String): Expr = FunctionExpr("map_get", fieldName, key) /** - * */ @JvmStatic fun mapMerge(firstMap: Expr, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", firstMap, secondMap, otherMaps) /** - * */ @JvmStatic fun mapMerge(mapField: String, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", mapField, secondMap, otherMaps) /** - * */ @JvmStatic fun mapRemove(firstMap: Expr, key: Expr): Expr = FunctionExpr("map_remove", firstMap, key) /** - * */ @JvmStatic fun mapRemove(mapField: String, key: Expr): Expr = FunctionExpr("map_remove", mapField, key) /** - * */ @JvmStatic fun mapRemove(firstMap: Expr, key: String): Expr = FunctionExpr("map_remove", firstMap, key) /** - * */ @JvmStatic fun mapRemove(mapField: String, key: String): Expr = FunctionExpr("map_remove", mapField, key) /** - * */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("cosine_distance", vector1, vector2) /** - * */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("cosine_distance", vector1, vector(vector2)) /** - * */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("cosine_distance", vector1, vector2) /** - * */ @JvmStatic fun cosineDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("cosine_distance", fieldName, vector) /** - * */ @JvmStatic fun cosineDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("cosine_distance", fieldName, vector(vector)) /** - * */ @JvmStatic fun cosineDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("cosine_distance", fieldName, vector) /** - * */ @JvmStatic fun dotProduct(vector1: Expr, vector2: Expr): Expr = FunctionExpr("dot_product", vector1, vector2) /** - * */ @JvmStatic fun dotProduct(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("dot_product", vector1, vector(vector2)) /** - * */ @JvmStatic fun dotProduct(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("dot_product", vector1, vector2) /** - * */ @JvmStatic fun dotProduct(fieldName: String, vector: Expr): Expr = FunctionExpr("dot_product", fieldName, vector) /** - * */ @JvmStatic fun dotProduct(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("dot_product", fieldName, vector(vector)) /** - * */ @JvmStatic fun dotProduct(fieldName: String, vector: VectorValue): Expr = FunctionExpr("dot_product", fieldName, vector) /** - * */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("euclidean_distance", vector1, vector2) /** - * */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("euclidean_distance", vector1, vector(vector2)) /** - * */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("euclidean_distance", vector1, vector2) /** - * */ @JvmStatic fun euclideanDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("euclidean_distance", fieldName, vector) /** - * */ @JvmStatic fun euclideanDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("euclidean_distance", fieldName, vector(vector)) /** - * */ @JvmStatic fun euclideanDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("euclidean_distance", fieldName, vector) /** - * */ @JvmStatic fun vectorLength(vector: Expr): Expr = FunctionExpr("vector_length", vector) /** - * */ @JvmStatic fun vectorLength(fieldName: String): Expr = FunctionExpr("vector_length", fieldName) /** - * */ @JvmStatic fun unixMicrosToTimestamp(input: Expr): Expr = FunctionExpr("unix_micros_to_timestamp", input) /** - * */ @JvmStatic fun unixMicrosToTimestamp(fieldName: String): Expr = FunctionExpr("unix_micros_to_timestamp", fieldName) /** - * */ @JvmStatic fun timestampToUnixMicros(input: Expr): Expr = FunctionExpr("timestamp_to_unix_micros", input) /** - * */ @JvmStatic fun timestampToUnixMicros(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_micros", fieldName) /** - * */ @JvmStatic fun unixMillisToTimestamp(input: Expr): Expr = FunctionExpr("unix_millis_to_timestamp", input) /** - * */ @JvmStatic fun unixMillisToTimestamp(fieldName: String): Expr = FunctionExpr("unix_millis_to_timestamp", fieldName) /** - * */ @JvmStatic fun timestampToUnixMillis(input: Expr): Expr = FunctionExpr("timestamp_to_unix_millis", input) /** - * */ @JvmStatic fun timestampToUnixMillis(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_millis", fieldName) /** - * */ @JvmStatic fun unixSecondsToTimestamp(input: Expr): Expr = FunctionExpr("unix_seconds_to_timestamp", input) /** - * */ @JvmStatic fun unixSecondsToTimestamp(fieldName: String): Expr = FunctionExpr("unix_seconds_to_timestamp", fieldName) /** - * */ @JvmStatic fun timestampToUnixSeconds(input: Expr): Expr = FunctionExpr("timestamp_to_unix_seconds", input) /** - * */ @JvmStatic fun timestampToUnixSeconds(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_seconds", fieldName) /** - * */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) /** - * */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) /** - * */ @JvmStatic fun timestampAdd(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) /** - * */ @JvmStatic fun timestampAdd(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) /** - * */ @JvmStatic fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) /** - * */ @JvmStatic fun timestampSub(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) /** - * */ @JvmStatic fun timestampSub(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) /** - * */ @JvmStatic fun timestampSub(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) /** - * */ @JvmStatic fun eq(left: Expr, right: Expr) = BooleanExpr("eq", left, right) /** - * */ @JvmStatic fun eq(left: Expr, right: Any) = BooleanExpr("eq", left, right) /** - * */ @JvmStatic fun eq(fieldName: String, right: Expr) = BooleanExpr("eq", fieldName, right) /** - * */ @JvmStatic fun eq(fieldName: String, right: Any) = BooleanExpr("eq", fieldName, right) /** - * */ @JvmStatic fun neq(left: Expr, right: Expr) = BooleanExpr("neq", left, right) /** - * */ @JvmStatic fun neq(left: Expr, right: Any) = BooleanExpr("neq", left, right) /** - * */ @JvmStatic fun neq(fieldName: String, right: Expr) = BooleanExpr("neq", fieldName, right) /** - * */ @JvmStatic fun neq(fieldName: String, right: Any) = BooleanExpr("neq", fieldName, right) /** - * */ @JvmStatic fun gt(left: Expr, right: Expr) = BooleanExpr("gt", left, right) /** - * */ @JvmStatic fun gt(left: Expr, right: Any) = BooleanExpr("gt", left, right) /** - * */ @JvmStatic fun gt(fieldName: String, right: Expr) = BooleanExpr("gt", fieldName, right) /** - * */ @JvmStatic fun gt(fieldName: String, right: Any) = BooleanExpr("gt", fieldName, right) /** - * */ @JvmStatic fun gte(left: Expr, right: Expr) = BooleanExpr("gte", left, right) /** - * */ @JvmStatic fun gte(left: Expr, right: Any) = BooleanExpr("gte", left, right) /** - * */ @JvmStatic fun gte(fieldName: String, right: Expr) = BooleanExpr("gte", fieldName, right) /** - * */ @JvmStatic fun gte(fieldName: String, right: Any) = BooleanExpr("gte", fieldName, right) /** - * */ @JvmStatic fun lt(left: Expr, right: Expr) = BooleanExpr("lt", left, right) /** - * */ @JvmStatic fun lt(left: Expr, right: Any) = BooleanExpr("lt", left, right) /** - * */ @JvmStatic fun lt(fieldName: String, right: Expr) = BooleanExpr("lt", fieldName, right) /** - * */ @JvmStatic fun lt(fieldName: String, right: Any) = BooleanExpr("lt", fieldName, right) /** - * */ @JvmStatic fun lte(left: Expr, right: Expr) = BooleanExpr("lte", left, right) /** - * */ @JvmStatic fun lte(left: Expr, right: Any) = BooleanExpr("lte", left, right) /** - * */ @JvmStatic fun lte(fieldName: String, right: Expr) = BooleanExpr("lte", fieldName, right) /** - * */ @JvmStatic fun lte(fieldName: String, right: Any) = BooleanExpr("lte", fieldName, right) /** - * */ @JvmStatic fun arrayConcat(array: Expr, vararg arrays: Expr): Expr = FunctionExpr("array_concat", array, *arrays) /** - * */ @JvmStatic fun arrayConcat(fieldName: String, vararg arrays: Expr): Expr = FunctionExpr("array_concat", fieldName, *arrays) /** - * */ @JvmStatic fun arrayConcat(array: Expr, arrays: List): Expr = FunctionExpr("array_concat", array, ListOfExprs(toArrayOfExprOrConstant(arrays))) /** - * */ @JvmStatic fun arrayConcat(fieldName: String, arrays: List): Expr = FunctionExpr("array_concat", fieldName, ListOfExprs(toArrayOfExprOrConstant(arrays))) /** - * */ @JvmStatic fun arrayReverse(array: Expr): Expr = FunctionExpr("array_reverse", array) /** - * */ @JvmStatic fun arrayReverse(fieldName: String): Expr = FunctionExpr("array_reverse", fieldName) /** - * */ @JvmStatic fun arrayContains(array: Expr, value: Expr) = BooleanExpr("array_contains", array, value) /** - * */ @JvmStatic fun arrayContains(fieldName: String, value: Expr) = BooleanExpr("array_contains", fieldName, value) /** - * */ @JvmStatic fun arrayContains(array: Expr, value: Any) = BooleanExpr("array_contains", array, value) /** - * */ @JvmStatic fun arrayContains(fieldName: String, value: Any) = BooleanExpr("array_contains", fieldName, value) /** - * */ @JvmStatic fun arrayContainsAll(array: Expr, values: List) = BooleanExpr("array_contains_all", array, ListOfExprs(toArrayOfExprOrConstant(values))) /** - * */ @JvmStatic fun arrayContainsAll(fieldName: String, values: List) = BooleanExpr("array_contains_all", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) /** - * */ @JvmStatic fun arrayContainsAny(array: Expr, values: List) = BooleanExpr("array_contains_any", array, ListOfExprs(toArrayOfExprOrConstant(values))) /** - * */ @JvmStatic fun arrayContainsAny(fieldName: String, values: List) = BooleanExpr("array_contains_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) /** - * */ @JvmStatic fun arrayLength(array: Expr): Expr = FunctionExpr("array_length", array) /** - * */ @JvmStatic fun arrayLength(fieldName: String): Expr = FunctionExpr("array_length", fieldName) /** - * */ @JvmStatic fun cond(condition: BooleanExpr, then: Expr, otherwise: Expr): Expr = FunctionExpr("cond", condition, then, otherwise) /** - * */ @JvmStatic fun cond(condition: BooleanExpr, then: Any, otherwise: Any): Expr = FunctionExpr("cond", condition, then, otherwise) /** - * */ @JvmStatic fun exists(expr: Expr) = BooleanExpr("exists", expr) } /** - * */ fun bitAnd(right: Expr) = bitAnd(this, right) /** - * */ fun bitAnd(right: Any) = bitAnd(this, right) /** - * */ fun bitOr(right: Expr) = bitOr(this, right) /** - * */ fun bitOr(right: Any) = bitOr(this, right) /** - * */ fun bitXor(right: Expr) = bitXor(this, right) /** - * */ fun bitXor(right: Any) = bitXor(this, right) /** - * */ fun bitNot() = bitNot(this) /** - * */ fun bitLeftShift(numberExpr: Expr) = bitLeftShift(this, numberExpr) /** - * */ fun bitLeftShift(number: Int) = bitLeftShift(this, number) /** - * */ fun bitRightShift(numberExpr: Expr) = bitRightShift(this, numberExpr) /** - * */ fun bitRightShift(number: Int) = bitRightShift(this, number) /** * Assigns an alias to this expression. * - *

Aliases are useful for renaming fields in the output of a stage or for giving meaningful - * names to calculated values. - * - *

Example: - * - *

 // Calculate the total price and assign it the alias "totalPrice" and add it to the
-   *
-   * output. firestore.pipeline().collection("items")
-   * .addFields(Expr.field("price").multiply(Expr.field("quantity")).as("totalPrice")); 
+ * Aliases are useful for renaming fields in the output of a stage or for giving meaningful names + * to calculated values. * * @param alias The alias to assign to this expression. * @return A new [Selectable] (typically an [ExprWithAlias]) that wraps this expression and @@ -1537,506 +1370,403 @@ abstract class Expr internal constructor() { open fun alias(alias: String) = ExprWithAlias(alias, this) /** - * Creates an expression that this expression to another expression. + * Creates an expression that adds this expression to another expression. * - *

Example: - * - *

{@code // Add the value of the 'quantity' field and the 'reserve' field.
-   * Expr.field("quantity").add(Expr.field("reserve")); }
- * - * @param other The expression to add to this expression. - * @return A new {@code Expr} representing the addition operation. + * @param second The second expression to add to this expression. + * @param others Additional expression or literal to add to this expression. + * @return A new [Expr] representing the addition operation. */ - fun add(other: Expr) = add(this, other) + fun add(second: Expr, vararg others: Any) = Companion.add(this, second, *others) /** - * Creates an expression that this expression to another expression. - * - *

Example: + * Creates an expression that adds this expression to another expression. * - *

{@code // Add the value of the 'quantity' field and the 'reserve' field.
-   * Expr.field("quantity").add(Expr.field("reserve")); }
- * - * @param other The constant value to add to this expression. - * @return A new {@code Expr} representing the addition operation. + * @param second The second expression or literal to add to this expression. + * @param others Additional expression or literal to add to this expression. + * @return A new [Expr] representing the addition operation. */ - fun add(other: Any) = add(this, other) + fun add(second: Any, vararg others: Any) = Companion.add(this, second, *others) /** - * */ - fun subtract(other: Expr) = subtract(this, other) + fun subtract(other: Expr) = Companion.subtract(this, other) /** - * */ - fun subtract(other: Any) = subtract(this, other) + fun subtract(other: Any) = Companion.subtract(this, other) /** - * */ - fun multiply(other: Expr) = multiply(this, other) + fun multiply(other: Expr) = Companion.multiply(this, other) /** - * */ - fun multiply(other: Any) = multiply(this, other) + fun multiply(other: Any) = Companion.multiply(this, other) /** - * */ - fun divide(other: Expr) = divide(this, other) + fun divide(other: Expr) = Companion.divide(this, other) /** - * */ - fun divide(other: Any) = divide(this, other) + fun divide(other: Any) = Companion.divide(this, other) /** - * */ - fun mod(other: Expr) = mod(this, other) + fun mod(other: Expr) = Companion.mod(this, other) /** - * */ - fun mod(other: Any) = mod(this, other) + fun mod(other: Any) = Companion.mod(this, other) /** - * */ - fun eqAny(values: List) = eqAny(this, values) + fun eqAny(values: List) = Companion.eqAny(this, values) /** - * */ - fun notEqAny(values: List) = notEqAny(this, values) + fun notEqAny(values: List) = Companion.notEqAny(this, values) /** - * */ - fun isNan() = isNan(this) + fun isNan() = Companion.isNan(this) /** - * */ - fun isNotNan() = isNotNan(this) + fun isNotNan() = Companion.isNotNan(this) /** - * */ - fun isNull() = isNull(this) + fun isNull() = Companion.isNull(this) /** - * */ - fun isNotNull() = isNotNull(this) + fun isNotNull() = Companion.isNotNull(this) /** - * */ - fun replaceFirst(find: Expr, replace: Expr) = replaceFirst(this, find, replace) + fun replaceFirst(find: Expr, replace: Expr) = Companion.replaceFirst(this, find, replace) /** - * */ - fun replaceFirst(find: String, replace: String) = replaceFirst(this, find, replace) + fun replaceFirst(find: String, replace: String) = Companion.replaceFirst(this, find, replace) /** - * */ - fun replaceAll(find: Expr, replace: Expr) = replaceAll(this, find, replace) + fun replaceAll(find: Expr, replace: Expr) = Companion.replaceAll(this, find, replace) /** - * */ - fun replaceAll(find: String, replace: String) = replaceAll(this, find, replace) + fun replaceAll(find: String, replace: String) = Companion.replaceAll(this, find, replace) /** - * */ - fun charLength() = charLength(this) + fun charLength() = Companion.charLength(this) /** - * */ - fun byteLength() = byteLength(this) + fun byteLength() = Companion.byteLength(this) /** - * */ - fun like(pattern: Expr) = like(this, pattern) + fun like(pattern: Expr) = Companion.like(this, pattern) /** - * */ - fun like(pattern: String) = like(this, pattern) + fun like(pattern: String) = Companion.like(this, pattern) /** - * */ - fun regexContains(pattern: Expr) = regexContains(this, pattern) + fun regexContains(pattern: Expr) = Companion.regexContains(this, pattern) /** - * */ - fun regexContains(pattern: String) = regexContains(this, pattern) + fun regexContains(pattern: String) = Companion.regexContains(this, pattern) /** - * */ - fun regexMatch(pattern: Expr) = regexMatch(this, pattern) + fun regexMatch(pattern: Expr) = Companion.regexMatch(this, pattern) /** - * */ - fun regexMatch(pattern: String) = regexMatch(this, pattern) + fun regexMatch(pattern: String) = Companion.regexMatch(this, pattern) /** - * */ - fun logicalMax(other: Expr) = logicalMax(this, other) + fun logicalMax(other: Expr) = Companion.logicalMax(this, other) /** - * */ - fun logicalMax(other: Any) = logicalMax(this, other) + fun logicalMax(other: Any) = Companion.logicalMax(this, other) /** - * */ - fun logicalMin(other: Expr) = logicalMin(this, other) + fun logicalMin(other: Expr) = Companion.logicalMin(this, other) /** - * */ - fun logicalMin(other: Any) = logicalMin(this, other) + fun logicalMin(other: Any) = Companion.logicalMin(this, other) /** - * */ - fun reverse() = reverse(this) + fun reverse() = Companion.reverse(this) /** - * */ - fun strContains(substring: Expr) = strContains(this, substring) + fun strContains(substring: Expr) = Companion.strContains(this, substring) /** - * */ - fun strContains(substring: String) = strContains(this, substring) + fun strContains(substring: String) = Companion.strContains(this, substring) /** - * */ - fun startsWith(prefix: Expr) = startsWith(this, prefix) + fun startsWith(prefix: Expr) = Companion.startsWith(this, prefix) /** - * */ - fun startsWith(prefix: String) = startsWith(this, prefix) + fun startsWith(prefix: String) = Companion.startsWith(this, prefix) /** - * */ - fun endsWith(suffix: Expr) = endsWith(this, suffix) + fun endsWith(suffix: Expr) = Companion.endsWith(this, suffix) /** - * */ - fun endsWith(suffix: String) = endsWith(this, suffix) + fun endsWith(suffix: String) = Companion.endsWith(this, suffix) /** - * */ - fun toLower() = toLower(this) + fun toLower() = Companion.toLower(this) /** - * */ - fun toUpper() = toUpper(this) + fun toUpper() = Companion.toUpper(this) /** - * */ - fun trim() = trim(this) + fun trim() = Companion.trim(this) /** - * */ fun strConcat(vararg expr: Expr) = Companion.strConcat(this, *expr) /** - * */ - fun strConcat(vararg string: String) = strConcat(this, *string) + fun strConcat(vararg string: String) = Companion.strConcat(this, *string) /** - * */ fun strConcat(vararg string: Any) = Companion.strConcat(this, *string) /** - * */ - fun mapGet(key: Expr) = mapGet(this, key) + fun mapGet(key: Expr) = Companion.mapGet(this, key) /** - * */ - fun mapGet(key: String) = mapGet(this, key) + fun mapGet(key: String) = Companion.mapGet(this, key) /** - * */ fun mapMerge(secondMap: Expr, vararg otherMaps: Expr) = Companion.mapMerge(this, secondMap, *otherMaps) /** - * */ - fun mapRemove(key: Expr) = mapRemove(this, key) + fun mapRemove(key: Expr) = Companion.mapRemove(this, key) /** - * */ - fun mapRemove(key: String) = mapRemove(this, key) + fun mapRemove(key: String) = Companion.mapRemove(this, key) /** - * */ - fun cosineDistance(vector: Expr) = cosineDistance(this, vector) + fun cosineDistance(vector: Expr) = Companion.cosineDistance(this, vector) /** - * */ - fun cosineDistance(vector: DoubleArray) = cosineDistance(this, vector) + fun cosineDistance(vector: DoubleArray) = Companion.cosineDistance(this, vector) /** - * */ - fun cosineDistance(vector: VectorValue) = cosineDistance(this, vector) + fun cosineDistance(vector: VectorValue) = Companion.cosineDistance(this, vector) /** - * */ - fun dotProduct(vector: Expr) = dotProduct(this, vector) + fun dotProduct(vector: Expr) = Companion.dotProduct(this, vector) /** - * */ - fun dotProduct(vector: DoubleArray) = dotProduct(this, vector) + fun dotProduct(vector: DoubleArray) = Companion.dotProduct(this, vector) /** - * */ - fun dotProduct(vector: VectorValue) = dotProduct(this, vector) + fun dotProduct(vector: VectorValue) = Companion.dotProduct(this, vector) /** - * */ - fun euclideanDistance(vector: Expr) = euclideanDistance(this, vector) + fun euclideanDistance(vector: Expr) = Companion.euclideanDistance(this, vector) /** - * */ - fun euclideanDistance(vector: DoubleArray) = euclideanDistance(this, vector) + fun euclideanDistance(vector: DoubleArray) = Companion.euclideanDistance(this, vector) /** - * */ - fun euclideanDistance(vector: VectorValue) = euclideanDistance(this, vector) + fun euclideanDistance(vector: VectorValue) = Companion.euclideanDistance(this, vector) /** - * */ - fun vectorLength() = vectorLength(this) + fun vectorLength() = Companion.vectorLength(this) /** - * */ - fun unixMicrosToTimestamp() = unixMicrosToTimestamp(this) + fun unixMicrosToTimestamp() = Companion.unixMicrosToTimestamp(this) /** - * */ - fun timestampToUnixMicros() = timestampToUnixMicros(this) + fun timestampToUnixMicros() = Companion.timestampToUnixMicros(this) /** - * */ - fun unixMillisToTimestamp() = unixMillisToTimestamp(this) + fun unixMillisToTimestamp() = Companion.unixMillisToTimestamp(this) /** - * */ - fun timestampToUnixMillis() = timestampToUnixMillis(this) + fun timestampToUnixMillis() = Companion.timestampToUnixMillis(this) /** - * */ - fun unixSecondsToTimestamp() = unixSecondsToTimestamp(this) + fun unixSecondsToTimestamp() = Companion.unixSecondsToTimestamp(this) /** - * */ - fun timestampToUnixSeconds() = timestampToUnixSeconds(this) + fun timestampToUnixSeconds() = Companion.timestampToUnixSeconds(this) /** - * */ - fun timestampAdd(unit: Expr, amount: Expr) = timestampAdd(this, unit, amount) + fun timestampAdd(unit: Expr, amount: Expr) = Companion.timestampAdd(this, unit, amount) /** - * */ - fun timestampAdd(unit: String, amount: Double) = timestampAdd(this, unit, amount) + fun timestampAdd(unit: String, amount: Double) = Companion.timestampAdd(this, unit, amount) /** - * */ - fun timestampSub(unit: Expr, amount: Expr) = timestampSub(this, unit, amount) + fun timestampSub(unit: Expr, amount: Expr) = Companion.timestampSub(this, unit, amount) /** - * */ - fun timestampSub(unit: String, amount: Double) = timestampSub(this, unit, amount) + fun timestampSub(unit: String, amount: Double) = Companion.timestampSub(this, unit, amount) /** - * */ fun arrayConcat(vararg arrays: Expr) = Companion.arrayConcat(this, *arrays) /** - * */ - fun arrayConcat(arrays: List) = arrayConcat(this, arrays) + fun arrayConcat(arrays: List) = Companion.arrayConcat(this, arrays) /** - * */ - fun arrayReverse() = arrayReverse(this) + fun arrayReverse() = Companion.arrayReverse(this) /** - * */ - fun arrayContains(value: Expr) = arrayContains(this, value) + fun arrayContains(value: Expr) = Companion.arrayContains(this, value) /** - * */ - fun arrayContains(value: Any) = arrayContains(this, value) + fun arrayContains(value: Any) = Companion.arrayContains(this, value) /** - * */ - fun arrayContainsAll(values: List) = arrayContainsAll(this, values) + fun arrayContainsAll(values: List) = Companion.arrayContainsAll(this, values) /** - * */ - fun arrayContainsAny(values: List) = arrayContainsAny(this, values) + fun arrayContainsAny(values: List) = Companion.arrayContainsAny(this, values) /** - * */ - fun arrayLength() = arrayLength(this) + fun arrayLength() = Companion.arrayLength(this) /** - * */ fun sum() = AggregateFunction.sum(this) /** - * */ fun avg() = AggregateFunction.avg(this) /** - * */ fun min() = AggregateFunction.min(this) /** - * */ fun max() = AggregateFunction.max(this) /** - * */ fun ascending() = Ordering.ascending(this) /** - * */ fun descending() = Ordering.descending(this) /** - * */ - fun eq(other: Expr) = eq(this, other) + fun eq(other: Expr) = Companion.eq(this, other) /** - * */ - fun eq(other: Any) = eq(this, other) + fun eq(other: Any) = Companion.eq(this, other) /** - * */ - fun neq(other: Expr) = neq(this, other) + fun neq(other: Expr) = Companion.neq(this, other) /** - * */ - fun neq(other: Any) = neq(this, other) + fun neq(other: Any) = Companion.neq(this, other) /** - * */ - fun gt(other: Expr) = gt(this, other) + fun gt(other: Expr) = Companion.gt(this, other) /** - * */ - fun gt(other: Any) = gt(this, other) + fun gt(other: Any) = Companion.gt(this, other) /** - * */ - fun gte(other: Expr) = gte(this, other) + fun gte(other: Expr) = Companion.gte(this, other) /** - * */ - fun gte(other: Any) = gte(this, other) + fun gte(other: Any) = Companion.gte(this, other) /** - * */ - fun lt(other: Expr) = lt(this, other) + fun lt(other: Expr) = Companion.lt(this, other) /** - * */ - fun lt(other: Any) = lt(this, other) + fun lt(other: Any) = Companion.lt(this, other) /** - * */ - fun lte(other: Expr) = lte(this, other) + fun lte(other: Expr) = Companion.lte(this, other) /** - * */ - fun lte(other: Any) = lte(this, other) + fun lte(other: Any) = Companion.lte(this, other) /** - * */ - fun exists() = exists(this) + fun exists() = Companion.exists(this) internal abstract fun toProto(userDataReader: UserDataReader): Value } @@ -2050,8 +1780,8 @@ abstract class Selectable : Expr() { fun toSelectable(o: Any): Selectable { return when (o) { is Selectable -> o - is String -> Expr.field(o) - is FieldPath -> Expr.field(o) + is String -> field(o) + is FieldPath -> field(o) else -> throw IllegalArgumentException("Unknown Selectable type: $o") } } @@ -2115,11 +1845,17 @@ internal constructor(private val name: String, private val params: Array Date: Fri, 25 Apr 2025 11:54:33 -0400 Subject: [PATCH 46/77] Comments --- .../firestore/pipeline/expressions.kt | 264 +++++++++++++++++- 1 file changed, 255 insertions(+), 9 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 0d6c041bb92..f9bc0d193aa 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -313,68 +313,137 @@ abstract class Expr internal constructor() { fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("xor", condition, *conditions) + /** + * @return A new [Expr] representing the not operation. + */ @JvmStatic fun not(condition: BooleanExpr) = BooleanExpr("not", condition) + /** + * @return A new [Expr] representing the bitAnd operation. + */ @JvmStatic fun bitAnd(left: Expr, right: Expr): Expr = FunctionExpr("bit_and", left, right) + /** + * @return A new [Expr] representing the bitAnd operation. + */ @JvmStatic fun bitAnd(left: Expr, right: Any): Expr = FunctionExpr("bit_and", left, right) + /** + * @return A new [Expr] representing the bitAnd operation. + */ @JvmStatic fun bitAnd(fieldName: String, right: Expr): Expr = FunctionExpr("bit_and", fieldName, right) + /** + * @return A new [Expr] representing the bitAnd operation. + */ @JvmStatic fun bitAnd(fieldName: String, right: Any): Expr = FunctionExpr("bit_and", fieldName, right) + /** + * @return A new [Expr] representing the bitOr operation. + */ @JvmStatic fun bitOr(left: Expr, right: Expr): Expr = FunctionExpr("bit_or", left, right) + /** + * @return A new [Expr] representing the bitOr operation. + */ @JvmStatic fun bitOr(left: Expr, right: Any): Expr = FunctionExpr("bit_or", left, right) + /** + * @return A new [Expr] representing the bitOr operation. + */ @JvmStatic fun bitOr(fieldName: String, right: Expr): Expr = FunctionExpr("bit_or", fieldName, right) + /** + * @return A new [Expr] representing the bitOr operation. + */ @JvmStatic fun bitOr(fieldName: String, right: Any): Expr = FunctionExpr("bit_or", fieldName, right) + /** + * @return A new [Expr] representing the bitXor operation. + */ @JvmStatic fun bitXor(left: Expr, right: Expr): Expr = FunctionExpr("bit_xor", left, right) + /** + * @return A new [Expr] representing the bitXor operation. + */ @JvmStatic fun bitXor(left: Expr, right: Any): Expr = FunctionExpr("bit_xor", left, right) + /** + * @return A new [Expr] representing the bitXor operation. + */ @JvmStatic fun bitXor(fieldName: String, right: Expr): Expr = FunctionExpr("bit_xor", fieldName, right) + /** + * @return A new [Expr] representing the bitXor operation. + */ @JvmStatic fun bitXor(fieldName: String, right: Any): Expr = FunctionExpr("bit_xor", fieldName, right) + /** + * @return A new [Expr] representing the bitNot operation. + */ @JvmStatic fun bitNot(left: Expr): Expr = FunctionExpr("bit_not", left) + /** + * @return A new [Expr] representing the bitNot operation. + */ @JvmStatic fun bitNot(fieldName: String): Expr = FunctionExpr("bit_not", fieldName) + /** + * @return A new [Expr] representing the bitLeftShift operation. + */ @JvmStatic fun bitLeftShift(left: Expr, numberExpr: Expr): Expr = FunctionExpr("bit_left_shift", left, numberExpr) + /** + * @return A new [Expr] representing the bitLeftShift operation. + */ @JvmStatic fun bitLeftShift(left: Expr, number: Int): Expr = FunctionExpr("bit_left_shift", left, number) + /** + * @return A new [Expr] representing the bitLeftShift operation. + */ @JvmStatic fun bitLeftShift(fieldName: String, numberExpr: Expr): Expr = FunctionExpr("bit_left_shift", fieldName, numberExpr) + /** + * @return A new [Expr] representing the bitLeftShift operation. + */ @JvmStatic fun bitLeftShift(fieldName: String, number: Int): Expr = FunctionExpr("bit_left_shift", fieldName, number) + /** + * @return A new [Expr] representing the bitRightShift operation. + */ @JvmStatic fun bitRightShift(left: Expr, numberExpr: Expr): Expr = FunctionExpr("bit_right_shift", left, numberExpr) + /** + * @return A new [Expr] representing the bitRightShift operation. + */ @JvmStatic fun bitRightShift(left: Expr, number: Int): Expr = FunctionExpr("bit_right_shift", left, number) + /** + * @return A new [Expr] representing the bitRightShift operation. + */ @JvmStatic fun bitRightShift(fieldName: String, numberExpr: Expr): Expr = FunctionExpr("bit_right_shift", fieldName, numberExpr) + /** + * @return A new [Expr] representing the bitRightShift operation. + */ @JvmStatic fun bitRightShift(fieldName: String, number: Int): Expr = FunctionExpr("bit_right_shift", fieldName, number) @@ -426,359 +495,433 @@ abstract class Expr internal constructor() { FunctionExpr("add", fieldName, second, *others) /** + * @return A new [Expr] representing the subtract operation. */ @JvmStatic fun subtract(left: Expr, right: Expr): Expr = FunctionExpr("subtract", left, right) /** + * @return A new [Expr] representing the subtract operation. */ @JvmStatic fun subtract(left: Expr, right: Any): Expr = FunctionExpr("subtract", left, right) /** + * @return A new [Expr] representing the subtract operation. */ @JvmStatic fun subtract(fieldName: String, other: Expr): Expr = FunctionExpr("subtract", fieldName, other) /** + * @return A new [Expr] representing the subtract operation. */ @JvmStatic fun subtract(fieldName: String, other: Any): Expr = FunctionExpr("subtract", fieldName, other) /** + * @return A new [Expr] representing the multiply operation. */ @JvmStatic fun multiply(left: Expr, right: Expr): Expr = FunctionExpr("multiply", left, right) /** + * @return A new [Expr] representing the multiply operation. */ @JvmStatic fun multiply(left: Expr, right: Any): Expr = FunctionExpr("multiply", left, right) /** + * @return A new [Expr] representing the multiply operation. */ @JvmStatic fun multiply(fieldName: String, other: Expr): Expr = FunctionExpr("multiply", fieldName, other) /** + * @return A new [Expr] representing the multiply operation. */ @JvmStatic fun multiply(fieldName: String, other: Any): Expr = FunctionExpr("multiply", fieldName, other) /** + * @return A new [Expr] representing the divide operation. */ @JvmStatic fun divide(left: Expr, right: Expr): Expr = FunctionExpr("divide", left, right) /** + * @return A new [Expr] representing the divide operation. */ @JvmStatic fun divide(left: Expr, right: Any): Expr = FunctionExpr("divide", left, right) /** + * @return A new [Expr] representing the divide operation. */ @JvmStatic fun divide(fieldName: String, other: Expr): Expr = FunctionExpr("divide", fieldName, other) /** + * @return A new [Expr] representing the divide operation. */ @JvmStatic fun divide(fieldName: String, other: Any): Expr = FunctionExpr("divide", fieldName, other) /** + * @return A new [Expr] representing the mod operation. */ @JvmStatic fun mod(left: Expr, right: Expr): Expr = FunctionExpr("mod", left, right) /** + * @return A new [Expr] representing the mod operation. */ @JvmStatic fun mod(left: Expr, right: Any): Expr = FunctionExpr("mod", left, right) /** + * @return A new [Expr] representing the mod operation. */ @JvmStatic fun mod(fieldName: String, other: Expr): Expr = FunctionExpr("mod", fieldName, other) /** + * @return A new [Expr] representing the mod operation. */ @JvmStatic fun mod(fieldName: String, other: Any): Expr = FunctionExpr("mod", fieldName, other) /** + * @return A new [Expr] representing the eqAny operation. */ @JvmStatic fun eqAny(value: Expr, values: List) = BooleanExpr("eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) /** + * @return A new [Expr] representing the eqAny operation. */ @JvmStatic fun eqAny(fieldName: String, values: List) = BooleanExpr("eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) /** + * @return A new [Expr] representing the notEqAny operation. */ @JvmStatic fun notEqAny(value: Expr, values: List) = BooleanExpr("not_eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) /** + * @return A new [Expr] representing the notEqAny operation. */ @JvmStatic fun notEqAny(fieldName: String, values: List) = BooleanExpr("not_eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) /** + * @return A new [Expr] representing the isNan operation. */ @JvmStatic fun isNan(expr: Expr) = BooleanExpr("is_nan", expr) /** + * @return A new [Expr] representing the isNan operation. */ @JvmStatic fun isNan(fieldName: String) = BooleanExpr("is_nan", fieldName) /** + * @return A new [Expr] representing the isNotNan operation. */ @JvmStatic fun isNotNan(expr: Expr) = BooleanExpr("is_not_nan", expr) /** + * @return A new [Expr] representing the isNotNan operation. */ @JvmStatic fun isNotNan(fieldName: String) = BooleanExpr("is_not_nan", fieldName) /** + * @return A new [Expr] representing the isNull operation. */ @JvmStatic fun isNull(expr: Expr) = BooleanExpr("is_null", expr) /** + * @return A new [Expr] representing the isNull operation. */ @JvmStatic fun isNull(fieldName: String) = BooleanExpr("is_null", fieldName) /** + * @return A new [Expr] representing the isNotNull operation. */ @JvmStatic fun isNotNull(expr: Expr) = BooleanExpr("is_not_null", expr) /** + * @return A new [Expr] representing the isNotNull operation. */ @JvmStatic fun isNotNull(fieldName: String) = BooleanExpr("is_not_null", fieldName) /** + * @return A new [Expr] representing the replaceFirst operation. */ @JvmStatic fun replaceFirst(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_first", value, find, replace) /** + * @return A new [Expr] representing the replaceFirst operation. */ @JvmStatic fun replaceFirst(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_first", value, find, replace) /** + * @return A new [Expr] representing the replaceFirst operation. */ @JvmStatic fun replaceFirst(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_first", fieldName, find, replace) /** + * @return A new [Expr] representing the replaceAll operation. */ @JvmStatic fun replaceAll(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_all", value, find, replace) /** + * @return A new [Expr] representing the replaceAll operation. */ @JvmStatic fun replaceAll(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_all", value, find, replace) /** + * @return A new [Expr] representing the replaceAll operation. */ @JvmStatic fun replaceAll(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_all", fieldName, find, replace) /** + * @return A new [Expr] representing the charLength operation. */ @JvmStatic fun charLength(value: Expr): Expr = FunctionExpr("char_length", value) /** + * @return A new [Expr] representing the charLength operation. */ @JvmStatic fun charLength(fieldName: String): Expr = FunctionExpr("char_length", fieldName) /** + * @return A new [Expr] representing the byteLength operation. */ @JvmStatic fun byteLength(value: Expr): Expr = FunctionExpr("byte_length", value) /** + * @return A new [Expr] representing the byteLength operation. */ @JvmStatic fun byteLength(fieldName: String): Expr = FunctionExpr("byte_length", fieldName) /** + * @return A new [Expr] representing the like operation. */ @JvmStatic fun like(expr: Expr, pattern: Expr) = BooleanExpr("like", expr, pattern) /** + * @return A new [Expr] representing the like operation. */ @JvmStatic fun like(expr: Expr, pattern: String) = BooleanExpr("like", expr, pattern) /** + * @return A new [Expr] representing the like operation. */ @JvmStatic fun like(fieldName: String, pattern: Expr) = BooleanExpr("like", fieldName, pattern) /** + * @return A new [Expr] representing the like operation. */ @JvmStatic fun like(fieldName: String, pattern: String) = BooleanExpr("like", fieldName, pattern) /** + * @return A new [Expr] representing the regexContains operation. */ @JvmStatic fun regexContains(expr: Expr, pattern: Expr) = BooleanExpr("regex_contains", expr, pattern) /** + * @return A new [Expr] representing the regexContains operation. */ @JvmStatic fun regexContains(expr: Expr, pattern: String) = BooleanExpr("regex_contains", expr, pattern) /** + * @return A new [Expr] representing the regexContains operation. */ @JvmStatic fun regexContains(fieldName: String, pattern: Expr) = BooleanExpr("regex_contains", fieldName, pattern) /** + * @return A new [Expr] representing the regexContains operation. */ @JvmStatic fun regexContains(fieldName: String, pattern: String) = BooleanExpr("regex_contains", fieldName, pattern) /** + * @return A new [Expr] representing the regexMatch operation. */ @JvmStatic fun regexMatch(expr: Expr, pattern: Expr) = BooleanExpr("regex_match", expr, pattern) /** + * @return A new [Expr] representing the regexMatch operation. */ @JvmStatic fun regexMatch(expr: Expr, pattern: String) = BooleanExpr("regex_match", expr, pattern) /** + * @return A new [Expr] representing the regexMatch operation. */ @JvmStatic fun regexMatch(fieldName: String, pattern: Expr) = BooleanExpr("regex_match", fieldName, pattern) /** + * @return A new [Expr] representing the regexMatch operation. */ @JvmStatic fun regexMatch(fieldName: String, pattern: String) = BooleanExpr("regex_match", fieldName, pattern) /** + * @return A new [Expr] representing the logicalMax operation. */ @JvmStatic fun logicalMax(left: Expr, right: Expr): Expr = FunctionExpr("logical_max", left, right) /** + * @return A new [Expr] representing the logicalMax operation. */ @JvmStatic fun logicalMax(left: Expr, right: Any): Expr = FunctionExpr("logical_max", left, right) /** + * @return A new [Expr] representing the logicalMax operation. */ @JvmStatic fun logicalMax(fieldName: String, other: Expr): Expr = FunctionExpr("logical_max", fieldName, other) /** + * @return A new [Expr] representing the logicalMax operation. */ @JvmStatic fun logicalMax(fieldName: String, other: Any): Expr = FunctionExpr("logical_max", fieldName, other) /** + * @return A new [Expr] representing the logicalMin operation. */ @JvmStatic fun logicalMin(left: Expr, right: Expr): Expr = FunctionExpr("logical_min", left, right) /** + * @return A new [Expr] representing the logicalMin operation. */ @JvmStatic fun logicalMin(left: Expr, right: Any): Expr = FunctionExpr("logical_min", left, right) /** + * @return A new [Expr] representing the logicalMin operation. */ @JvmStatic fun logicalMin(fieldName: String, other: Expr): Expr = FunctionExpr("logical_min", fieldName, other) /** + * @return A new [Expr] representing the logicalMin operation. */ @JvmStatic fun logicalMin(fieldName: String, other: Any): Expr = FunctionExpr("logical_min", fieldName, other) /** + * @return A new [Expr] representing the reverse operation. */ @JvmStatic fun reverse(expr: Expr): Expr = FunctionExpr("reverse", expr) /** + * @return A new [Expr] representing the reverse operation. */ @JvmStatic fun reverse(fieldName: String): Expr = FunctionExpr("reverse", fieldName) /** + * @return A new [Expr] representing the strContains operation. */ @JvmStatic fun strContains(expr: Expr, substring: Expr) = BooleanExpr("str_contains", expr, substring) /** + * @return A new [Expr] representing the strContains operation. */ @JvmStatic fun strContains(expr: Expr, substring: String) = BooleanExpr("str_contains", expr, substring) /** + * @return A new [Expr] representing the strContains operation. */ @JvmStatic fun strContains(fieldName: String, substring: Expr) = BooleanExpr("str_contains", fieldName, substring) /** + * @return A new [Expr] representing the strContains operation. */ @JvmStatic fun strContains(fieldName: String, substring: String) = BooleanExpr("str_contains", fieldName, substring) /** + * @return A new [Expr] representing the startsWith operation. */ @JvmStatic fun startsWith(expr: Expr, prefix: Expr) = BooleanExpr("starts_with", expr, prefix) /** + * @return A new [Expr] representing the startsWith operation. */ @JvmStatic fun startsWith(expr: Expr, prefix: String) = BooleanExpr("starts_with", expr, prefix) /** + * @return A new [Expr] representing the startsWith operation. */ @JvmStatic fun startsWith(fieldName: String, prefix: Expr) = BooleanExpr("starts_with", fieldName, prefix) /** + * @return A new [Expr] representing the startsWith operation. */ @JvmStatic fun startsWith(fieldName: String, prefix: String) = BooleanExpr("starts_with", fieldName, prefix) /** + * @return A new [Expr] representing the endsWith operation. */ @JvmStatic fun endsWith(expr: Expr, suffix: Expr) = BooleanExpr("ends_with", expr, suffix) /** + * @return A new [Expr] representing the endsWith operation. */ @JvmStatic fun endsWith(expr: Expr, suffix: String) = BooleanExpr("ends_with", expr, suffix) /** + * @return A new [Expr] representing the endsWith operation. */ @JvmStatic fun endsWith(fieldName: String, suffix: Expr) = BooleanExpr("ends_with", fieldName, suffix) /** + * @return A new [Expr] representing the endsWith operation. */ @JvmStatic fun endsWith(fieldName: String, suffix: String) = BooleanExpr("ends_with", fieldName, suffix) /** + * @return A new [Expr] representing the toLower operation. */ @JvmStatic fun toLower(expr: Expr): Expr = FunctionExpr("to_lower", expr) /** + * @return A new [Expr] representing the toLower operation. */ @JvmStatic fun toLower( @@ -786,10 +929,12 @@ abstract class Expr internal constructor() { ): Expr = FunctionExpr("to_lower", fieldName) /** + * @return A new [Expr] representing the toUpper operation. */ @JvmStatic fun toUpper(expr: Expr): Expr = FunctionExpr("to_upper", expr) /** + * @return A new [Expr] representing the toUpper operation. */ @JvmStatic fun toUpper( @@ -797,30 +942,36 @@ abstract class Expr internal constructor() { ): Expr = FunctionExpr("to_upper", fieldName) /** + * @return A new [Expr] representing the trim operation. */ @JvmStatic fun trim(expr: Expr): Expr = FunctionExpr("trim", expr) /** + * @return A new [Expr] representing the trim operation. */ @JvmStatic fun trim(fieldName: String): Expr = FunctionExpr("trim", fieldName) /** + * @return A new [Expr] representing the strConcat operation. */ @JvmStatic fun strConcat(first: Expr, vararg rest: Expr): Expr = FunctionExpr("str_concat", first, *rest) /** + * @return A new [Expr] representing the strConcat operation. */ @JvmStatic fun strConcat(first: Expr, vararg rest: Any): Expr = FunctionExpr("str_concat", first, *rest) /** + * @return A new [Expr] representing the strConcat operation. */ @JvmStatic fun strConcat(fieldName: String, vararg rest: Expr): Expr = FunctionExpr("str_concat", fieldName, *rest) /** + * @return A new [Expr] representing the strConcat operation. */ @JvmStatic fun strConcat(fieldName: String, vararg rest: Any): Expr = @@ -829,410 +980,499 @@ abstract class Expr internal constructor() { internal fun map(elements: Array): Expr = FunctionExpr("map", elements) /** + * @return A new [Expr] representing the map operation. */ @JvmStatic fun map(elements: Map) = map(elements.flatMap { listOf(constant(it.key), toExprOrConstant(it.value)) }.toTypedArray()) /** + * @return A new [Expr] representing the mapGet operation. */ @JvmStatic fun mapGet(map: Expr, key: Expr): Expr = FunctionExpr("map_get", map, key) /** + * @return A new [Expr] representing the mapGet operation. */ @JvmStatic fun mapGet(map: Expr, key: String): Expr = FunctionExpr("map_get", map, key) /** + * @return A new [Expr] representing the mapGet operation. */ @JvmStatic fun mapGet(fieldName: String, key: Expr): Expr = FunctionExpr("map_get", fieldName, key) /** + * @return A new [Expr] representing the mapGet operation. */ @JvmStatic fun mapGet(fieldName: String, key: String): Expr = FunctionExpr("map_get", fieldName, key) /** + * @return A new [Expr] representing the mapMerge operation. */ @JvmStatic fun mapMerge(firstMap: Expr, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", firstMap, secondMap, otherMaps) /** + * @return A new [Expr] representing the mapMerge operation. */ @JvmStatic fun mapMerge(mapField: String, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", mapField, secondMap, otherMaps) /** + * @return A new [Expr] representing the mapRemove operation. */ @JvmStatic fun mapRemove(firstMap: Expr, key: Expr): Expr = FunctionExpr("map_remove", firstMap, key) /** + * @return A new [Expr] representing the mapRemove operation. */ @JvmStatic fun mapRemove(mapField: String, key: Expr): Expr = FunctionExpr("map_remove", mapField, key) /** + * @return A new [Expr] representing the mapRemove operation. */ @JvmStatic fun mapRemove(firstMap: Expr, key: String): Expr = FunctionExpr("map_remove", firstMap, key) /** + * @return A new [Expr] representing the mapRemove operation. */ @JvmStatic fun mapRemove(mapField: String, key: String): Expr = FunctionExpr("map_remove", mapField, key) /** + * @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("cosine_distance", vector1, vector2) /** + * @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("cosine_distance", vector1, vector(vector2)) /** + * @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("cosine_distance", vector1, vector2) /** + * @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("cosine_distance", fieldName, vector) /** + * @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("cosine_distance", fieldName, vector(vector)) /** + * @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("cosine_distance", fieldName, vector) /** + * @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(vector1: Expr, vector2: Expr): Expr = FunctionExpr("dot_product", vector1, vector2) /** + * @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("dot_product", vector1, vector(vector2)) /** + * @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("dot_product", vector1, vector2) /** + * @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(fieldName: String, vector: Expr): Expr = FunctionExpr("dot_product", fieldName, vector) /** + * @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("dot_product", fieldName, vector(vector)) /** + * @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(fieldName: String, vector: VectorValue): Expr = FunctionExpr("dot_product", fieldName, vector) /** + * @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("euclidean_distance", vector1, vector2) /** + * @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("euclidean_distance", vector1, vector(vector2)) /** + * @return A new [Expr] representing the not operation. */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("euclidean_distance", vector1, vector2) /** + * @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("euclidean_distance", fieldName, vector) /** + * @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("euclidean_distance", fieldName, vector(vector)) /** + * @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("euclidean_distance", fieldName, vector) /** + * @return A new [Expr] representing the vectorLength operation. */ @JvmStatic fun vectorLength(vector: Expr): Expr = FunctionExpr("vector_length", vector) /** + * @return A new [Expr] representing the vectorLength operation. */ @JvmStatic fun vectorLength(fieldName: String): Expr = FunctionExpr("vector_length", fieldName) /** + * @return A new [Expr] representing the unixMicrosToTimestamp operation. */ @JvmStatic fun unixMicrosToTimestamp(input: Expr): Expr = FunctionExpr("unix_micros_to_timestamp", input) /** + * @return A new [Expr] representing the unixMicrosToTimestamp operation. */ @JvmStatic fun unixMicrosToTimestamp(fieldName: String): Expr = FunctionExpr("unix_micros_to_timestamp", fieldName) /** + * @return A new [Expr] representing the timestampToUnixMicros operation. */ @JvmStatic fun timestampToUnixMicros(input: Expr): Expr = FunctionExpr("timestamp_to_unix_micros", input) /** + * @return A new [Expr] representing the timestampToUnixMicros operation. */ @JvmStatic fun timestampToUnixMicros(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_micros", fieldName) /** + * @return A new [Expr] representing the unixMillisToTimestamp operation. */ @JvmStatic fun unixMillisToTimestamp(input: Expr): Expr = FunctionExpr("unix_millis_to_timestamp", input) /** + * @return A new [Expr] representing the unixMillisToTimestamp operation. */ @JvmStatic fun unixMillisToTimestamp(fieldName: String): Expr = FunctionExpr("unix_millis_to_timestamp", fieldName) /** + * @return A new [Expr] representing the timestampToUnixMillis operation. */ @JvmStatic fun timestampToUnixMillis(input: Expr): Expr = FunctionExpr("timestamp_to_unix_millis", input) /** + * @return A new [Expr] representing the timestampToUnixMillis operation. */ @JvmStatic fun timestampToUnixMillis(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_millis", fieldName) /** + * @return A new [Expr] representing the unixSecondsToTimestamp operation. */ @JvmStatic fun unixSecondsToTimestamp(input: Expr): Expr = FunctionExpr("unix_seconds_to_timestamp", input) /** + * @return A new [Expr] representing the unixSecondsToTimestamp operation. */ @JvmStatic fun unixSecondsToTimestamp(fieldName: String): Expr = FunctionExpr("unix_seconds_to_timestamp", fieldName) /** + * @return A new [Expr] representing the timestampToUnixSeconds operation. */ @JvmStatic fun timestampToUnixSeconds(input: Expr): Expr = FunctionExpr("timestamp_to_unix_seconds", input) /** + * @return A new [Expr] representing the timestampToUnixSeconds operation. */ @JvmStatic fun timestampToUnixSeconds(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_seconds", fieldName) /** + * @return A new [Expr] representing the timestampAdd operation. */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) /** + * @return A new [Expr] representing the timestampAdd operation. */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) /** + * @return A new [Expr] representing the timestampAdd operation. */ @JvmStatic fun timestampAdd(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) /** + * @return A new [Expr] representing the timestampAdd operation. */ @JvmStatic fun timestampAdd(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) /** + * @return A new [Expr] representing the timestampSub operation. */ @JvmStatic fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) /** + * @return A new [Expr] representing the timestampSub operation. */ @JvmStatic fun timestampSub(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) /** + * @return A new [Expr] representing the timestampSub operation. */ @JvmStatic fun timestampSub(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) /** + * @return A new [Expr] representing the timestampSub operation. */ @JvmStatic fun timestampSub(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) /** + * @return A new [Expr] representing the eq operation. */ @JvmStatic fun eq(left: Expr, right: Expr) = BooleanExpr("eq", left, right) /** + * @return A new [Expr] representing the eq operation. */ @JvmStatic fun eq(left: Expr, right: Any) = BooleanExpr("eq", left, right) /** + * @return A new [Expr] representing the eq operation. */ @JvmStatic fun eq(fieldName: String, right: Expr) = BooleanExpr("eq", fieldName, right) /** + * @return A new [Expr] representing the eq operation. */ @JvmStatic fun eq(fieldName: String, right: Any) = BooleanExpr("eq", fieldName, right) /** + * @return A new [Expr] representing the neq operation. */ @JvmStatic fun neq(left: Expr, right: Expr) = BooleanExpr("neq", left, right) /** + * @return A new [Expr] representing the neq operation. */ @JvmStatic fun neq(left: Expr, right: Any) = BooleanExpr("neq", left, right) /** + * @return A new [Expr] representing the neq operation. */ @JvmStatic fun neq(fieldName: String, right: Expr) = BooleanExpr("neq", fieldName, right) /** + * @return A new [Expr] representing the neq operation. */ @JvmStatic fun neq(fieldName: String, right: Any) = BooleanExpr("neq", fieldName, right) /** + * @return A new [Expr] representing the gt operation. */ @JvmStatic fun gt(left: Expr, right: Expr) = BooleanExpr("gt", left, right) /** + * @return A new [Expr] representing the gt operation. */ @JvmStatic fun gt(left: Expr, right: Any) = BooleanExpr("gt", left, right) /** + * @return A new [Expr] representing the gt operation. */ @JvmStatic fun gt(fieldName: String, right: Expr) = BooleanExpr("gt", fieldName, right) /** + * @return A new [Expr] representing the gt operation. */ @JvmStatic fun gt(fieldName: String, right: Any) = BooleanExpr("gt", fieldName, right) /** + * @return A new [Expr] representing the gte operation. */ @JvmStatic fun gte(left: Expr, right: Expr) = BooleanExpr("gte", left, right) /** + * @return A new [Expr] representing the gte operation. */ @JvmStatic fun gte(left: Expr, right: Any) = BooleanExpr("gte", left, right) /** + * @return A new [Expr] representing the gte operation. */ @JvmStatic fun gte(fieldName: String, right: Expr) = BooleanExpr("gte", fieldName, right) /** + * @return A new [Expr] representing the gte operation. */ @JvmStatic fun gte(fieldName: String, right: Any) = BooleanExpr("gte", fieldName, right) /** + * @return A new [Expr] representing the lt operation. */ @JvmStatic fun lt(left: Expr, right: Expr) = BooleanExpr("lt", left, right) /** + * @return A new [Expr] representing the lt operation. */ @JvmStatic fun lt(left: Expr, right: Any) = BooleanExpr("lt", left, right) /** + * @return A new [Expr] representing the lt operation. */ @JvmStatic fun lt(fieldName: String, right: Expr) = BooleanExpr("lt", fieldName, right) /** + * @return A new [Expr] representing the lt operation. */ @JvmStatic fun lt(fieldName: String, right: Any) = BooleanExpr("lt", fieldName, right) /** + * @return A new [Expr] representing the lte operation. */ @JvmStatic fun lte(left: Expr, right: Expr) = BooleanExpr("lte", left, right) /** + * @return A new [Expr] representing the lte operation. */ @JvmStatic fun lte(left: Expr, right: Any) = BooleanExpr("lte", left, right) /** + * @return A new [Expr] representing the lte operation. */ @JvmStatic fun lte(fieldName: String, right: Expr) = BooleanExpr("lte", fieldName, right) /** + * @return A new [Expr] representing the lte operation. */ @JvmStatic fun lte(fieldName: String, right: Any) = BooleanExpr("lte", fieldName, right) /** + * Creates an expression that concatenates an array with other arrays. + * + * + * + * @return A new [Expr] representing the arrayConcat operation. */ @JvmStatic - fun arrayConcat(array: Expr, vararg arrays: Expr): Expr = - FunctionExpr("array_concat", array, *arrays) + fun arrayConcat(firstArray: Expr, secondArray: Expr, vararg otherArrays: Any): Expr = + FunctionExpr("array_concat", firstArray, secondArray, *otherArrays) /** + * Creates an expression that concatenates an array with other arrays. + * + * @return A new [Expr] representing the arrayConcat operation. */ @JvmStatic - fun arrayConcat(fieldName: String, vararg arrays: Expr): Expr = - FunctionExpr("array_concat", fieldName, *arrays) + fun arrayConcat(firstArray: Expr, vararg otherArrays: Any): Expr = + FunctionExpr("array_concat", firstArray, *otherArrays) /** + * Creates an expression that concatenates a field's array value with other arrays. + * + * @return A new [Expr] representing the arrayConcat operation. */ @JvmStatic - fun arrayConcat(array: Expr, arrays: List): Expr = - FunctionExpr("array_concat", array, ListOfExprs(toArrayOfExprOrConstant(arrays))) + fun arrayConcat(fieldName: String, secondArray: Expr, vararg otherArrays: Any): Expr = + FunctionExpr("array_concat", fieldName, secondArray, *otherArrays) /** + * Creates an expression that concatenates a field's array value with other arrays. + * + * @return A new [Expr] representing the arrayConcat operation. */ @JvmStatic - fun arrayConcat(fieldName: String, arrays: List): Expr = - FunctionExpr("array_concat", fieldName, ListOfExprs(toArrayOfExprOrConstant(arrays))) + fun arrayConcat(fieldName: String, vararg otherArrays: Any): Expr = + FunctionExpr("array_concat", fieldName, *otherArrays) /** */ @@ -1661,10 +1901,16 @@ abstract class Expr internal constructor() { fun timestampSub(unit: String, amount: Double) = Companion.timestampSub(this, unit, amount) /** + * Creates an expression that concatenates a field's array value with other arrays. + * + * @return A new [Expr] representing the arrayConcat operation. */ - fun arrayConcat(vararg arrays: Expr) = Companion.arrayConcat(this, *arrays) + fun arrayConcat(vararg otherArrays: Expr) = Companion.arrayConcat(this, *otherArrays) /** + * Creates an expression that concatenates a field's array value with other arrays. + * + * @return A new [Expr] representing the arrayConcat operation. */ fun arrayConcat(arrays: List) = Companion.arrayConcat(this, arrays) From 83d94e41b2c20701c82536d23082d99704ff97a6 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 25 Apr 2025 15:47:42 -0400 Subject: [PATCH 47/77] Comments --- .../firestore/pipeline/expressions.kt | 921 +++++++----------- 1 file changed, 354 insertions(+), 567 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index f9bc0d193aa..19c2af56700 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -313,137 +313,91 @@ abstract class Expr internal constructor() { fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("xor", condition, *conditions) - /** - * @return A new [Expr] representing the not operation. - */ + /** @return A new [Expr] representing the not operation. */ @JvmStatic fun not(condition: BooleanExpr) = BooleanExpr("not", condition) - /** - * @return A new [Expr] representing the bitAnd operation. - */ + /** @return A new [Expr] representing the bitAnd operation. */ @JvmStatic fun bitAnd(left: Expr, right: Expr): Expr = FunctionExpr("bit_and", left, right) - /** - * @return A new [Expr] representing the bitAnd operation. - */ + /** @return A new [Expr] representing the bitAnd operation. */ @JvmStatic fun bitAnd(left: Expr, right: Any): Expr = FunctionExpr("bit_and", left, right) - /** - * @return A new [Expr] representing the bitAnd operation. - */ + /** @return A new [Expr] representing the bitAnd operation. */ @JvmStatic fun bitAnd(fieldName: String, right: Expr): Expr = FunctionExpr("bit_and", fieldName, right) - /** - * @return A new [Expr] representing the bitAnd operation. - */ + /** @return A new [Expr] representing the bitAnd operation. */ @JvmStatic fun bitAnd(fieldName: String, right: Any): Expr = FunctionExpr("bit_and", fieldName, right) - /** - * @return A new [Expr] representing the bitOr operation. - */ + /** @return A new [Expr] representing the bitOr operation. */ @JvmStatic fun bitOr(left: Expr, right: Expr): Expr = FunctionExpr("bit_or", left, right) - /** - * @return A new [Expr] representing the bitOr operation. - */ + /** @return A new [Expr] representing the bitOr operation. */ @JvmStatic fun bitOr(left: Expr, right: Any): Expr = FunctionExpr("bit_or", left, right) - /** - * @return A new [Expr] representing the bitOr operation. - */ + /** @return A new [Expr] representing the bitOr operation. */ @JvmStatic fun bitOr(fieldName: String, right: Expr): Expr = FunctionExpr("bit_or", fieldName, right) - /** - * @return A new [Expr] representing the bitOr operation. - */ + /** @return A new [Expr] representing the bitOr operation. */ @JvmStatic fun bitOr(fieldName: String, right: Any): Expr = FunctionExpr("bit_or", fieldName, right) - /** - * @return A new [Expr] representing the bitXor operation. - */ + /** @return A new [Expr] representing the bitXor operation. */ @JvmStatic fun bitXor(left: Expr, right: Expr): Expr = FunctionExpr("bit_xor", left, right) - /** - * @return A new [Expr] representing the bitXor operation. - */ + /** @return A new [Expr] representing the bitXor operation. */ @JvmStatic fun bitXor(left: Expr, right: Any): Expr = FunctionExpr("bit_xor", left, right) - /** - * @return A new [Expr] representing the bitXor operation. - */ + /** @return A new [Expr] representing the bitXor operation. */ @JvmStatic fun bitXor(fieldName: String, right: Expr): Expr = FunctionExpr("bit_xor", fieldName, right) - /** - * @return A new [Expr] representing the bitXor operation. - */ + /** @return A new [Expr] representing the bitXor operation. */ @JvmStatic fun bitXor(fieldName: String, right: Any): Expr = FunctionExpr("bit_xor", fieldName, right) - /** - * @return A new [Expr] representing the bitNot operation. - */ + /** @return A new [Expr] representing the bitNot operation. */ @JvmStatic fun bitNot(left: Expr): Expr = FunctionExpr("bit_not", left) - /** - * @return A new [Expr] representing the bitNot operation. - */ + /** @return A new [Expr] representing the bitNot operation. */ @JvmStatic fun bitNot(fieldName: String): Expr = FunctionExpr("bit_not", fieldName) - /** - * @return A new [Expr] representing the bitLeftShift operation. - */ + /** @return A new [Expr] representing the bitLeftShift operation. */ @JvmStatic fun bitLeftShift(left: Expr, numberExpr: Expr): Expr = FunctionExpr("bit_left_shift", left, numberExpr) - /** - * @return A new [Expr] representing the bitLeftShift operation. - */ + /** @return A new [Expr] representing the bitLeftShift operation. */ @JvmStatic fun bitLeftShift(left: Expr, number: Int): Expr = FunctionExpr("bit_left_shift", left, number) - /** - * @return A new [Expr] representing the bitLeftShift operation. - */ + /** @return A new [Expr] representing the bitLeftShift operation. */ @JvmStatic fun bitLeftShift(fieldName: String, numberExpr: Expr): Expr = FunctionExpr("bit_left_shift", fieldName, numberExpr) - /** - * @return A new [Expr] representing the bitLeftShift operation. - */ + /** @return A new [Expr] representing the bitLeftShift operation. */ @JvmStatic fun bitLeftShift(fieldName: String, number: Int): Expr = FunctionExpr("bit_left_shift", fieldName, number) - /** - * @return A new [Expr] representing the bitRightShift operation. - */ + /** @return A new [Expr] representing the bitRightShift operation. */ @JvmStatic fun bitRightShift(left: Expr, numberExpr: Expr): Expr = FunctionExpr("bit_right_shift", left, numberExpr) - /** - * @return A new [Expr] representing the bitRightShift operation. - */ + /** @return A new [Expr] representing the bitRightShift operation. */ @JvmStatic fun bitRightShift(left: Expr, number: Int): Expr = FunctionExpr("bit_right_shift", left, number) - /** - * @return A new [Expr] representing the bitRightShift operation. - */ + /** @return A new [Expr] representing the bitRightShift operation. */ @JvmStatic fun bitRightShift(fieldName: String, numberExpr: Expr): Expr = FunctionExpr("bit_right_shift", fieldName, numberExpr) - /** - * @return A new [Expr] representing the bitRightShift operation. - */ + /** @return A new [Expr] representing the bitRightShift operation. */ @JvmStatic fun bitRightShift(fieldName: String, number: Int): Expr = FunctionExpr("bit_right_shift", fieldName, number) @@ -494,953 +448,640 @@ abstract class Expr internal constructor() { fun add(fieldName: String, second: Any, vararg others: Any): Expr = FunctionExpr("add", fieldName, second, *others) - /** - * @return A new [Expr] representing the subtract operation. - */ + /** @return A new [Expr] representing the subtract operation. */ @JvmStatic fun subtract(left: Expr, right: Expr): Expr = FunctionExpr("subtract", left, right) - /** - * @return A new [Expr] representing the subtract operation. - */ + /** @return A new [Expr] representing the subtract operation. */ @JvmStatic fun subtract(left: Expr, right: Any): Expr = FunctionExpr("subtract", left, right) - /** - * @return A new [Expr] representing the subtract operation. - */ + /** @return A new [Expr] representing the subtract operation. */ @JvmStatic fun subtract(fieldName: String, other: Expr): Expr = FunctionExpr("subtract", fieldName, other) - /** - * @return A new [Expr] representing the subtract operation. - */ + /** @return A new [Expr] representing the subtract operation. */ @JvmStatic fun subtract(fieldName: String, other: Any): Expr = FunctionExpr("subtract", fieldName, other) - /** - * @return A new [Expr] representing the multiply operation. - */ + /** @return A new [Expr] representing the multiply operation. */ @JvmStatic fun multiply(left: Expr, right: Expr): Expr = FunctionExpr("multiply", left, right) - /** - * @return A new [Expr] representing the multiply operation. - */ + /** @return A new [Expr] representing the multiply operation. */ @JvmStatic fun multiply(left: Expr, right: Any): Expr = FunctionExpr("multiply", left, right) - /** - * @return A new [Expr] representing the multiply operation. - */ + /** @return A new [Expr] representing the multiply operation. */ @JvmStatic fun multiply(fieldName: String, other: Expr): Expr = FunctionExpr("multiply", fieldName, other) - /** - * @return A new [Expr] representing the multiply operation. - */ + /** @return A new [Expr] representing the multiply operation. */ @JvmStatic fun multiply(fieldName: String, other: Any): Expr = FunctionExpr("multiply", fieldName, other) - /** - * @return A new [Expr] representing the divide operation. - */ + /** @return A new [Expr] representing the divide operation. */ @JvmStatic fun divide(left: Expr, right: Expr): Expr = FunctionExpr("divide", left, right) - /** - * @return A new [Expr] representing the divide operation. - */ + /** @return A new [Expr] representing the divide operation. */ @JvmStatic fun divide(left: Expr, right: Any): Expr = FunctionExpr("divide", left, right) - /** - * @return A new [Expr] representing the divide operation. - */ + /** @return A new [Expr] representing the divide operation. */ @JvmStatic fun divide(fieldName: String, other: Expr): Expr = FunctionExpr("divide", fieldName, other) - /** - * @return A new [Expr] representing the divide operation. - */ + /** @return A new [Expr] representing the divide operation. */ @JvmStatic fun divide(fieldName: String, other: Any): Expr = FunctionExpr("divide", fieldName, other) - /** - * @return A new [Expr] representing the mod operation. - */ + /** @return A new [Expr] representing the mod operation. */ @JvmStatic fun mod(left: Expr, right: Expr): Expr = FunctionExpr("mod", left, right) - /** - * @return A new [Expr] representing the mod operation. - */ + /** @return A new [Expr] representing the mod operation. */ @JvmStatic fun mod(left: Expr, right: Any): Expr = FunctionExpr("mod", left, right) - /** - * @return A new [Expr] representing the mod operation. - */ + /** @return A new [Expr] representing the mod operation. */ @JvmStatic fun mod(fieldName: String, other: Expr): Expr = FunctionExpr("mod", fieldName, other) - /** - * @return A new [Expr] representing the mod operation. - */ + /** @return A new [Expr] representing the mod operation. */ @JvmStatic fun mod(fieldName: String, other: Any): Expr = FunctionExpr("mod", fieldName, other) - /** - * @return A new [Expr] representing the eqAny operation. - */ + /** @return A new [Expr] representing the eqAny operation. */ @JvmStatic fun eqAny(value: Expr, values: List) = BooleanExpr("eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) - /** - * @return A new [Expr] representing the eqAny operation. - */ + /** @return A new [Expr] representing the eqAny operation. */ @JvmStatic fun eqAny(fieldName: String, values: List) = BooleanExpr("eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) - /** - * @return A new [Expr] representing the notEqAny operation. - */ + /** @return A new [Expr] representing the notEqAny operation. */ @JvmStatic fun notEqAny(value: Expr, values: List) = BooleanExpr("not_eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) - /** - * @return A new [Expr] representing the notEqAny operation. - */ + /** @return A new [Expr] representing the notEqAny operation. */ @JvmStatic fun notEqAny(fieldName: String, values: List) = BooleanExpr("not_eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) - /** - * @return A new [Expr] representing the isNan operation. - */ + /** @return A new [Expr] representing the isNan operation. */ @JvmStatic fun isNan(expr: Expr) = BooleanExpr("is_nan", expr) - /** - * @return A new [Expr] representing the isNan operation. - */ + /** @return A new [Expr] representing the isNan operation. */ @JvmStatic fun isNan(fieldName: String) = BooleanExpr("is_nan", fieldName) - /** - * @return A new [Expr] representing the isNotNan operation. - */ + /** @return A new [Expr] representing the isNotNan operation. */ @JvmStatic fun isNotNan(expr: Expr) = BooleanExpr("is_not_nan", expr) - /** - * @return A new [Expr] representing the isNotNan operation. - */ + /** @return A new [Expr] representing the isNotNan operation. */ @JvmStatic fun isNotNan(fieldName: String) = BooleanExpr("is_not_nan", fieldName) - /** - * @return A new [Expr] representing the isNull operation. - */ + /** @return A new [Expr] representing the isNull operation. */ @JvmStatic fun isNull(expr: Expr) = BooleanExpr("is_null", expr) - /** - * @return A new [Expr] representing the isNull operation. - */ + /** @return A new [Expr] representing the isNull operation. */ @JvmStatic fun isNull(fieldName: String) = BooleanExpr("is_null", fieldName) - /** - * @return A new [Expr] representing the isNotNull operation. - */ + /** @return A new [Expr] representing the isNotNull operation. */ @JvmStatic fun isNotNull(expr: Expr) = BooleanExpr("is_not_null", expr) - /** - * @return A new [Expr] representing the isNotNull operation. - */ + /** @return A new [Expr] representing the isNotNull operation. */ @JvmStatic fun isNotNull(fieldName: String) = BooleanExpr("is_not_null", fieldName) - /** - * @return A new [Expr] representing the replaceFirst operation. - */ + /** @return A new [Expr] representing the replaceFirst operation. */ @JvmStatic fun replaceFirst(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_first", value, find, replace) - /** - * @return A new [Expr] representing the replaceFirst operation. - */ + /** @return A new [Expr] representing the replaceFirst operation. */ @JvmStatic fun replaceFirst(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_first", value, find, replace) - /** - * @return A new [Expr] representing the replaceFirst operation. - */ + /** @return A new [Expr] representing the replaceFirst operation. */ @JvmStatic fun replaceFirst(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_first", fieldName, find, replace) - /** - * @return A new [Expr] representing the replaceAll operation. - */ + /** @return A new [Expr] representing the replaceAll operation. */ @JvmStatic fun replaceAll(value: Expr, find: Expr, replace: Expr): Expr = FunctionExpr("replace_all", value, find, replace) - /** - * @return A new [Expr] representing the replaceAll operation. - */ + /** @return A new [Expr] representing the replaceAll operation. */ @JvmStatic fun replaceAll(value: Expr, find: String, replace: String): Expr = FunctionExpr("replace_all", value, find, replace) - /** - * @return A new [Expr] representing the replaceAll operation. - */ + /** @return A new [Expr] representing the replaceAll operation. */ @JvmStatic fun replaceAll(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_all", fieldName, find, replace) - /** - * @return A new [Expr] representing the charLength operation. - */ + /** @return A new [Expr] representing the charLength operation. */ @JvmStatic fun charLength(value: Expr): Expr = FunctionExpr("char_length", value) - /** - * @return A new [Expr] representing the charLength operation. - */ + /** @return A new [Expr] representing the charLength operation. */ @JvmStatic fun charLength(fieldName: String): Expr = FunctionExpr("char_length", fieldName) - /** - * @return A new [Expr] representing the byteLength operation. - */ + /** @return A new [Expr] representing the byteLength operation. */ @JvmStatic fun byteLength(value: Expr): Expr = FunctionExpr("byte_length", value) - /** - * @return A new [Expr] representing the byteLength operation. - */ + /** @return A new [Expr] representing the byteLength operation. */ @JvmStatic fun byteLength(fieldName: String): Expr = FunctionExpr("byte_length", fieldName) - /** - * @return A new [Expr] representing the like operation. - */ + /** @return A new [Expr] representing the like operation. */ @JvmStatic fun like(expr: Expr, pattern: Expr) = BooleanExpr("like", expr, pattern) - /** - * @return A new [Expr] representing the like operation. - */ + /** @return A new [Expr] representing the like operation. */ @JvmStatic fun like(expr: Expr, pattern: String) = BooleanExpr("like", expr, pattern) - /** - * @return A new [Expr] representing the like operation. - */ + /** @return A new [Expr] representing the like operation. */ @JvmStatic fun like(fieldName: String, pattern: Expr) = BooleanExpr("like", fieldName, pattern) - /** - * @return A new [Expr] representing the like operation. - */ + /** @return A new [Expr] representing the like operation. */ @JvmStatic fun like(fieldName: String, pattern: String) = BooleanExpr("like", fieldName, pattern) - /** - * @return A new [Expr] representing the regexContains operation. - */ + /** @return A new [Expr] representing the regexContains operation. */ @JvmStatic fun regexContains(expr: Expr, pattern: Expr) = BooleanExpr("regex_contains", expr, pattern) - /** - * @return A new [Expr] representing the regexContains operation. - */ + /** @return A new [Expr] representing the regexContains operation. */ @JvmStatic fun regexContains(expr: Expr, pattern: String) = BooleanExpr("regex_contains", expr, pattern) - /** - * @return A new [Expr] representing the regexContains operation. - */ + /** @return A new [Expr] representing the regexContains operation. */ @JvmStatic fun regexContains(fieldName: String, pattern: Expr) = BooleanExpr("regex_contains", fieldName, pattern) - /** - * @return A new [Expr] representing the regexContains operation. - */ + /** @return A new [Expr] representing the regexContains operation. */ @JvmStatic fun regexContains(fieldName: String, pattern: String) = BooleanExpr("regex_contains", fieldName, pattern) - /** - * @return A new [Expr] representing the regexMatch operation. - */ + /** @return A new [Expr] representing the regexMatch operation. */ @JvmStatic fun regexMatch(expr: Expr, pattern: Expr) = BooleanExpr("regex_match", expr, pattern) - /** - * @return A new [Expr] representing the regexMatch operation. - */ + /** @return A new [Expr] representing the regexMatch operation. */ @JvmStatic fun regexMatch(expr: Expr, pattern: String) = BooleanExpr("regex_match", expr, pattern) - /** - * @return A new [Expr] representing the regexMatch operation. - */ + /** @return A new [Expr] representing the regexMatch operation. */ @JvmStatic fun regexMatch(fieldName: String, pattern: Expr) = BooleanExpr("regex_match", fieldName, pattern) - /** - * @return A new [Expr] representing the regexMatch operation. - */ + /** @return A new [Expr] representing the regexMatch operation. */ @JvmStatic fun regexMatch(fieldName: String, pattern: String) = BooleanExpr("regex_match", fieldName, pattern) - /** - * @return A new [Expr] representing the logicalMax operation. - */ + /** @return A new [Expr] representing the logicalMax operation. */ @JvmStatic fun logicalMax(left: Expr, right: Expr): Expr = FunctionExpr("logical_max", left, right) - /** - * @return A new [Expr] representing the logicalMax operation. - */ + /** @return A new [Expr] representing the logicalMax operation. */ @JvmStatic fun logicalMax(left: Expr, right: Any): Expr = FunctionExpr("logical_max", left, right) - /** - * @return A new [Expr] representing the logicalMax operation. - */ + /** @return A new [Expr] representing the logicalMax operation. */ @JvmStatic fun logicalMax(fieldName: String, other: Expr): Expr = FunctionExpr("logical_max", fieldName, other) - /** - * @return A new [Expr] representing the logicalMax operation. - */ + /** @return A new [Expr] representing the logicalMax operation. */ @JvmStatic fun logicalMax(fieldName: String, other: Any): Expr = FunctionExpr("logical_max", fieldName, other) - /** - * @return A new [Expr] representing the logicalMin operation. - */ + /** @return A new [Expr] representing the logicalMin operation. */ @JvmStatic fun logicalMin(left: Expr, right: Expr): Expr = FunctionExpr("logical_min", left, right) - /** - * @return A new [Expr] representing the logicalMin operation. - */ + /** @return A new [Expr] representing the logicalMin operation. */ @JvmStatic fun logicalMin(left: Expr, right: Any): Expr = FunctionExpr("logical_min", left, right) - /** - * @return A new [Expr] representing the logicalMin operation. - */ + /** @return A new [Expr] representing the logicalMin operation. */ @JvmStatic fun logicalMin(fieldName: String, other: Expr): Expr = FunctionExpr("logical_min", fieldName, other) - /** - * @return A new [Expr] representing the logicalMin operation. - */ + /** @return A new [Expr] representing the logicalMin operation. */ @JvmStatic fun logicalMin(fieldName: String, other: Any): Expr = FunctionExpr("logical_min", fieldName, other) - /** - * @return A new [Expr] representing the reverse operation. - */ + /** @return A new [Expr] representing the reverse operation. */ @JvmStatic fun reverse(expr: Expr): Expr = FunctionExpr("reverse", expr) - /** - * @return A new [Expr] representing the reverse operation. - */ + /** @return A new [Expr] representing the reverse operation. */ @JvmStatic fun reverse(fieldName: String): Expr = FunctionExpr("reverse", fieldName) - /** - * @return A new [Expr] representing the strContains operation. - */ + /** @return A new [Expr] representing the strContains operation. */ @JvmStatic fun strContains(expr: Expr, substring: Expr) = BooleanExpr("str_contains", expr, substring) - /** - * @return A new [Expr] representing the strContains operation. - */ + /** @return A new [Expr] representing the strContains operation. */ @JvmStatic fun strContains(expr: Expr, substring: String) = BooleanExpr("str_contains", expr, substring) - /** - * @return A new [Expr] representing the strContains operation. - */ + /** @return A new [Expr] representing the strContains operation. */ @JvmStatic fun strContains(fieldName: String, substring: Expr) = BooleanExpr("str_contains", fieldName, substring) - /** - * @return A new [Expr] representing the strContains operation. - */ + /** @return A new [Expr] representing the strContains operation. */ @JvmStatic fun strContains(fieldName: String, substring: String) = BooleanExpr("str_contains", fieldName, substring) - /** - * @return A new [Expr] representing the startsWith operation. - */ + /** @return A new [Expr] representing the startsWith operation. */ @JvmStatic fun startsWith(expr: Expr, prefix: Expr) = BooleanExpr("starts_with", expr, prefix) - /** - * @return A new [Expr] representing the startsWith operation. - */ + /** @return A new [Expr] representing the startsWith operation. */ @JvmStatic fun startsWith(expr: Expr, prefix: String) = BooleanExpr("starts_with", expr, prefix) - /** - * @return A new [Expr] representing the startsWith operation. - */ + /** @return A new [Expr] representing the startsWith operation. */ @JvmStatic fun startsWith(fieldName: String, prefix: Expr) = BooleanExpr("starts_with", fieldName, prefix) - /** - * @return A new [Expr] representing the startsWith operation. - */ + /** @return A new [Expr] representing the startsWith operation. */ @JvmStatic fun startsWith(fieldName: String, prefix: String) = BooleanExpr("starts_with", fieldName, prefix) - /** - * @return A new [Expr] representing the endsWith operation. - */ + /** @return A new [Expr] representing the endsWith operation. */ @JvmStatic fun endsWith(expr: Expr, suffix: Expr) = BooleanExpr("ends_with", expr, suffix) - /** - * @return A new [Expr] representing the endsWith operation. - */ + /** @return A new [Expr] representing the endsWith operation. */ @JvmStatic fun endsWith(expr: Expr, suffix: String) = BooleanExpr("ends_with", expr, suffix) - /** - * @return A new [Expr] representing the endsWith operation. - */ + /** @return A new [Expr] representing the endsWith operation. */ @JvmStatic fun endsWith(fieldName: String, suffix: Expr) = BooleanExpr("ends_with", fieldName, suffix) - /** - * @return A new [Expr] representing the endsWith operation. - */ + /** @return A new [Expr] representing the endsWith operation. */ @JvmStatic fun endsWith(fieldName: String, suffix: String) = BooleanExpr("ends_with", fieldName, suffix) - /** - * @return A new [Expr] representing the toLower operation. - */ + /** @return A new [Expr] representing the toLower operation. */ @JvmStatic fun toLower(expr: Expr): Expr = FunctionExpr("to_lower", expr) - /** - * @return A new [Expr] representing the toLower operation. - */ + /** @return A new [Expr] representing the toLower operation. */ @JvmStatic fun toLower( fieldName: String, ): Expr = FunctionExpr("to_lower", fieldName) - /** - * @return A new [Expr] representing the toUpper operation. - */ + /** @return A new [Expr] representing the toUpper operation. */ @JvmStatic fun toUpper(expr: Expr): Expr = FunctionExpr("to_upper", expr) - /** - * @return A new [Expr] representing the toUpper operation. - */ + /** @return A new [Expr] representing the toUpper operation. */ @JvmStatic fun toUpper( fieldName: String, ): Expr = FunctionExpr("to_upper", fieldName) - /** - * @return A new [Expr] representing the trim operation. - */ + /** @return A new [Expr] representing the trim operation. */ @JvmStatic fun trim(expr: Expr): Expr = FunctionExpr("trim", expr) - /** - * @return A new [Expr] representing the trim operation. - */ + /** @return A new [Expr] representing the trim operation. */ @JvmStatic fun trim(fieldName: String): Expr = FunctionExpr("trim", fieldName) - /** - * @return A new [Expr] representing the strConcat operation. - */ + /** @return A new [Expr] representing the strConcat operation. */ @JvmStatic fun strConcat(first: Expr, vararg rest: Expr): Expr = FunctionExpr("str_concat", first, *rest) - /** - * @return A new [Expr] representing the strConcat operation. - */ + /** @return A new [Expr] representing the strConcat operation. */ @JvmStatic fun strConcat(first: Expr, vararg rest: Any): Expr = FunctionExpr("str_concat", first, *rest) - /** - * @return A new [Expr] representing the strConcat operation. - */ + /** @return A new [Expr] representing the strConcat operation. */ @JvmStatic fun strConcat(fieldName: String, vararg rest: Expr): Expr = FunctionExpr("str_concat", fieldName, *rest) - /** - * @return A new [Expr] representing the strConcat operation. - */ + /** @return A new [Expr] representing the strConcat operation. */ @JvmStatic fun strConcat(fieldName: String, vararg rest: Any): Expr = FunctionExpr("str_concat", fieldName, *rest) internal fun map(elements: Array): Expr = FunctionExpr("map", elements) - /** - * @return A new [Expr] representing the map operation. - */ + /** @return A new [Expr] representing the map operation. */ @JvmStatic fun map(elements: Map) = map(elements.flatMap { listOf(constant(it.key), toExprOrConstant(it.value)) }.toTypedArray()) - /** - * @return A new [Expr] representing the mapGet operation. - */ + /** @return A new [Expr] representing the mapGet operation. */ @JvmStatic fun mapGet(map: Expr, key: Expr): Expr = FunctionExpr("map_get", map, key) - /** - * @return A new [Expr] representing the mapGet operation. - */ + /** @return A new [Expr] representing the mapGet operation. */ @JvmStatic fun mapGet(map: Expr, key: String): Expr = FunctionExpr("map_get", map, key) - /** - * @return A new [Expr] representing the mapGet operation. - */ + /** @return A new [Expr] representing the mapGet operation. */ @JvmStatic fun mapGet(fieldName: String, key: Expr): Expr = FunctionExpr("map_get", fieldName, key) - /** - * @return A new [Expr] representing the mapGet operation. - */ + /** @return A new [Expr] representing the mapGet operation. */ @JvmStatic fun mapGet(fieldName: String, key: String): Expr = FunctionExpr("map_get", fieldName, key) - /** - * @return A new [Expr] representing the mapMerge operation. - */ + /** @return A new [Expr] representing the mapMerge operation. */ @JvmStatic fun mapMerge(firstMap: Expr, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", firstMap, secondMap, otherMaps) - /** - * @return A new [Expr] representing the mapMerge operation. - */ + /** @return A new [Expr] representing the mapMerge operation. */ @JvmStatic fun mapMerge(mapField: String, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", mapField, secondMap, otherMaps) - /** - * @return A new [Expr] representing the mapRemove operation. - */ + /** @return A new [Expr] representing the mapRemove operation. */ @JvmStatic fun mapRemove(firstMap: Expr, key: Expr): Expr = FunctionExpr("map_remove", firstMap, key) - /** - * @return A new [Expr] representing the mapRemove operation. - */ + /** @return A new [Expr] representing the mapRemove operation. */ @JvmStatic fun mapRemove(mapField: String, key: Expr): Expr = FunctionExpr("map_remove", mapField, key) - /** - * @return A new [Expr] representing the mapRemove operation. - */ + /** @return A new [Expr] representing the mapRemove operation. */ @JvmStatic fun mapRemove(firstMap: Expr, key: String): Expr = FunctionExpr("map_remove", firstMap, key) - /** - * @return A new [Expr] representing the mapRemove operation. - */ + /** @return A new [Expr] representing the mapRemove operation. */ @JvmStatic fun mapRemove(mapField: String, key: String): Expr = FunctionExpr("map_remove", mapField, key) - /** - * @return A new [Expr] representing the cosineDistance operation. - */ + /** @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("cosine_distance", vector1, vector2) - /** - * @return A new [Expr] representing the cosineDistance operation. - */ + /** @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("cosine_distance", vector1, vector(vector2)) - /** - * @return A new [Expr] representing the cosineDistance operation. - */ + /** @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("cosine_distance", vector1, vector2) - /** - * @return A new [Expr] representing the cosineDistance operation. - */ + /** @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("cosine_distance", fieldName, vector) - /** - * @return A new [Expr] representing the cosineDistance operation. - */ + /** @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("cosine_distance", fieldName, vector(vector)) - /** - * @return A new [Expr] representing the cosineDistance operation. - */ + /** @return A new [Expr] representing the cosineDistance operation. */ @JvmStatic fun cosineDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("cosine_distance", fieldName, vector) - /** - * @return A new [Expr] representing the dotProduct operation. - */ + /** @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(vector1: Expr, vector2: Expr): Expr = FunctionExpr("dot_product", vector1, vector2) - /** - * @return A new [Expr] representing the dotProduct operation. - */ + /** @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("dot_product", vector1, vector(vector2)) - /** - * @return A new [Expr] representing the dotProduct operation. - */ + /** @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("dot_product", vector1, vector2) - /** - * @return A new [Expr] representing the dotProduct operation. - */ + /** @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(fieldName: String, vector: Expr): Expr = FunctionExpr("dot_product", fieldName, vector) - /** - * @return A new [Expr] representing the dotProduct operation. - */ + /** @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("dot_product", fieldName, vector(vector)) - /** - * @return A new [Expr] representing the dotProduct operation. - */ + /** @return A new [Expr] representing the dotProduct operation. */ @JvmStatic fun dotProduct(fieldName: String, vector: VectorValue): Expr = FunctionExpr("dot_product", fieldName, vector) - /** - * @return A new [Expr] representing the euclideanDistance operation. - */ + /** @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("euclidean_distance", vector1, vector2) - /** - * @return A new [Expr] representing the euclideanDistance operation. - */ + /** @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("euclidean_distance", vector1, vector(vector2)) - /** - * @return A new [Expr] representing the not operation. - */ + /** @return A new [Expr] representing the not operation. */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("euclidean_distance", vector1, vector2) - /** - * @return A new [Expr] representing the euclideanDistance operation. - */ + /** @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(fieldName: String, vector: Expr): Expr = FunctionExpr("euclidean_distance", fieldName, vector) - /** - * @return A new [Expr] representing the euclideanDistance operation. - */ + /** @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(fieldName: String, vector: DoubleArray): Expr = FunctionExpr("euclidean_distance", fieldName, vector(vector)) - /** - * @return A new [Expr] representing the euclideanDistance operation. - */ + /** @return A new [Expr] representing the euclideanDistance operation. */ @JvmStatic fun euclideanDistance(fieldName: String, vector: VectorValue): Expr = FunctionExpr("euclidean_distance", fieldName, vector) - /** - * @return A new [Expr] representing the vectorLength operation. - */ + /** @return A new [Expr] representing the vectorLength operation. */ @JvmStatic fun vectorLength(vector: Expr): Expr = FunctionExpr("vector_length", vector) - /** - * @return A new [Expr] representing the vectorLength operation. - */ + /** @return A new [Expr] representing the vectorLength operation. */ @JvmStatic fun vectorLength(fieldName: String): Expr = FunctionExpr("vector_length", fieldName) - /** - * @return A new [Expr] representing the unixMicrosToTimestamp operation. - */ + /** @return A new [Expr] representing the unixMicrosToTimestamp operation. */ @JvmStatic fun unixMicrosToTimestamp(input: Expr): Expr = FunctionExpr("unix_micros_to_timestamp", input) - /** - * @return A new [Expr] representing the unixMicrosToTimestamp operation. - */ + /** @return A new [Expr] representing the unixMicrosToTimestamp operation. */ @JvmStatic fun unixMicrosToTimestamp(fieldName: String): Expr = FunctionExpr("unix_micros_to_timestamp", fieldName) - /** - * @return A new [Expr] representing the timestampToUnixMicros operation. - */ + /** @return A new [Expr] representing the timestampToUnixMicros operation. */ @JvmStatic fun timestampToUnixMicros(input: Expr): Expr = FunctionExpr("timestamp_to_unix_micros", input) - /** - * @return A new [Expr] representing the timestampToUnixMicros operation. - */ + /** @return A new [Expr] representing the timestampToUnixMicros operation. */ @JvmStatic fun timestampToUnixMicros(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_micros", fieldName) - /** - * @return A new [Expr] representing the unixMillisToTimestamp operation. - */ + /** @return A new [Expr] representing the unixMillisToTimestamp operation. */ @JvmStatic fun unixMillisToTimestamp(input: Expr): Expr = FunctionExpr("unix_millis_to_timestamp", input) - /** - * @return A new [Expr] representing the unixMillisToTimestamp operation. - */ + /** @return A new [Expr] representing the unixMillisToTimestamp operation. */ @JvmStatic fun unixMillisToTimestamp(fieldName: String): Expr = FunctionExpr("unix_millis_to_timestamp", fieldName) - /** - * @return A new [Expr] representing the timestampToUnixMillis operation. - */ + /** @return A new [Expr] representing the timestampToUnixMillis operation. */ @JvmStatic fun timestampToUnixMillis(input: Expr): Expr = FunctionExpr("timestamp_to_unix_millis", input) - /** - * @return A new [Expr] representing the timestampToUnixMillis operation. - */ + /** @return A new [Expr] representing the timestampToUnixMillis operation. */ @JvmStatic fun timestampToUnixMillis(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_millis", fieldName) - /** - * @return A new [Expr] representing the unixSecondsToTimestamp operation. - */ + /** @return A new [Expr] representing the unixSecondsToTimestamp operation. */ @JvmStatic fun unixSecondsToTimestamp(input: Expr): Expr = FunctionExpr("unix_seconds_to_timestamp", input) - /** - * @return A new [Expr] representing the unixSecondsToTimestamp operation. - */ + /** @return A new [Expr] representing the unixSecondsToTimestamp operation. */ @JvmStatic fun unixSecondsToTimestamp(fieldName: String): Expr = FunctionExpr("unix_seconds_to_timestamp", fieldName) - /** - * @return A new [Expr] representing the timestampToUnixSeconds operation. - */ + /** @return A new [Expr] representing the timestampToUnixSeconds operation. */ @JvmStatic fun timestampToUnixSeconds(input: Expr): Expr = FunctionExpr("timestamp_to_unix_seconds", input) - /** - * @return A new [Expr] representing the timestampToUnixSeconds operation. - */ + /** @return A new [Expr] representing the timestampToUnixSeconds operation. */ @JvmStatic fun timestampToUnixSeconds(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_seconds", fieldName) - /** - * @return A new [Expr] representing the timestampAdd operation. - */ + /** @return A new [Expr] representing the timestampAdd operation. */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) - /** - * @return A new [Expr] representing the timestampAdd operation. - */ + /** @return A new [Expr] representing the timestampAdd operation. */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) - /** - * @return A new [Expr] representing the timestampAdd operation. - */ + /** @return A new [Expr] representing the timestampAdd operation. */ @JvmStatic fun timestampAdd(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) - /** - * @return A new [Expr] representing the timestampAdd operation. - */ + /** @return A new [Expr] representing the timestampAdd operation. */ @JvmStatic fun timestampAdd(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) - /** - * @return A new [Expr] representing the timestampSub operation. - */ + /** @return A new [Expr] representing the timestampSub operation. */ @JvmStatic fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) - /** - * @return A new [Expr] representing the timestampSub operation. - */ + /** @return A new [Expr] representing the timestampSub operation. */ @JvmStatic fun timestampSub(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) - /** - * @return A new [Expr] representing the timestampSub operation. - */ + /** @return A new [Expr] representing the timestampSub operation. */ @JvmStatic fun timestampSub(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) - /** - * @return A new [Expr] representing the timestampSub operation. - */ + /** @return A new [Expr] representing the timestampSub operation. */ @JvmStatic fun timestampSub(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) - /** - * @return A new [Expr] representing the eq operation. - */ + /** @return A new [Expr] representing the eq operation. */ @JvmStatic fun eq(left: Expr, right: Expr) = BooleanExpr("eq", left, right) - /** - * @return A new [Expr] representing the eq operation. - */ + /** @return A new [Expr] representing the eq operation. */ @JvmStatic fun eq(left: Expr, right: Any) = BooleanExpr("eq", left, right) - /** - * @return A new [Expr] representing the eq operation. - */ + /** @return A new [Expr] representing the eq operation. */ @JvmStatic fun eq(fieldName: String, right: Expr) = BooleanExpr("eq", fieldName, right) - /** - * @return A new [Expr] representing the eq operation. - */ + /** @return A new [Expr] representing the eq operation. */ @JvmStatic fun eq(fieldName: String, right: Any) = BooleanExpr("eq", fieldName, right) - /** - * @return A new [Expr] representing the neq operation. - */ + /** @return A new [Expr] representing the neq operation. */ @JvmStatic fun neq(left: Expr, right: Expr) = BooleanExpr("neq", left, right) - /** - * @return A new [Expr] representing the neq operation. - */ + /** @return A new [Expr] representing the neq operation. */ @JvmStatic fun neq(left: Expr, right: Any) = BooleanExpr("neq", left, right) - /** - * @return A new [Expr] representing the neq operation. - */ + /** @return A new [Expr] representing the neq operation. */ @JvmStatic fun neq(fieldName: String, right: Expr) = BooleanExpr("neq", fieldName, right) - /** - * @return A new [Expr] representing the neq operation. - */ + /** @return A new [Expr] representing the neq operation. */ @JvmStatic fun neq(fieldName: String, right: Any) = BooleanExpr("neq", fieldName, right) - /** - * @return A new [Expr] representing the gt operation. - */ + /** @return A new [Expr] representing the gt operation. */ @JvmStatic fun gt(left: Expr, right: Expr) = BooleanExpr("gt", left, right) - /** - * @return A new [Expr] representing the gt operation. - */ + /** @return A new [Expr] representing the gt operation. */ @JvmStatic fun gt(left: Expr, right: Any) = BooleanExpr("gt", left, right) - /** - * @return A new [Expr] representing the gt operation. - */ + /** @return A new [Expr] representing the gt operation. */ @JvmStatic fun gt(fieldName: String, right: Expr) = BooleanExpr("gt", fieldName, right) - /** - * @return A new [Expr] representing the gt operation. - */ + /** @return A new [Expr] representing the gt operation. */ @JvmStatic fun gt(fieldName: String, right: Any) = BooleanExpr("gt", fieldName, right) - /** - * @return A new [Expr] representing the gte operation. - */ + /** @return A new [Expr] representing the gte operation. */ @JvmStatic fun gte(left: Expr, right: Expr) = BooleanExpr("gte", left, right) - /** - * @return A new [Expr] representing the gte operation. - */ + /** @return A new [Expr] representing the gte operation. */ @JvmStatic fun gte(left: Expr, right: Any) = BooleanExpr("gte", left, right) - /** - * @return A new [Expr] representing the gte operation. - */ + /** @return A new [Expr] representing the gte operation. */ @JvmStatic fun gte(fieldName: String, right: Expr) = BooleanExpr("gte", fieldName, right) - /** - * @return A new [Expr] representing the gte operation. - */ + /** @return A new [Expr] representing the gte operation. */ @JvmStatic fun gte(fieldName: String, right: Any) = BooleanExpr("gte", fieldName, right) - /** - * @return A new [Expr] representing the lt operation. - */ + /** @return A new [Expr] representing the lt operation. */ @JvmStatic fun lt(left: Expr, right: Expr) = BooleanExpr("lt", left, right) - /** - * @return A new [Expr] representing the lt operation. - */ + /** @return A new [Expr] representing the lt operation. */ @JvmStatic fun lt(left: Expr, right: Any) = BooleanExpr("lt", left, right) - /** - * @return A new [Expr] representing the lt operation. - */ + /** @return A new [Expr] representing the lt operation. */ @JvmStatic fun lt(fieldName: String, right: Expr) = BooleanExpr("lt", fieldName, right) - /** - * @return A new [Expr] representing the lt operation. - */ + /** @return A new [Expr] representing the lt operation. */ @JvmStatic fun lt(fieldName: String, right: Any) = BooleanExpr("lt", fieldName, right) - /** - * @return A new [Expr] representing the lte operation. - */ + /** @return A new [Expr] representing the lte operation. */ @JvmStatic fun lte(left: Expr, right: Expr) = BooleanExpr("lte", left, right) - /** - * @return A new [Expr] representing the lte operation. - */ + /** @return A new [Expr] representing the lte operation. */ @JvmStatic fun lte(left: Expr, right: Any) = BooleanExpr("lte", left, right) - /** - * @return A new [Expr] representing the lte operation. - */ + /** @return A new [Expr] representing the lte operation. */ @JvmStatic fun lte(fieldName: String, right: Expr) = BooleanExpr("lte", fieldName, right) - /** - * @return A new [Expr] representing the lte operation. - */ + /** @return A new [Expr] representing the lte operation. */ @JvmStatic fun lte(fieldName: String, right: Any) = BooleanExpr("lte", fieldName, right) /** * Creates an expression that concatenates an array with other arrays. * - * - * + * @param firstArray The first array expression to concatenate to. + * @param secondArray An expression that evaluates to array to concatenate. + * @param otherArrays Optional additional array expressions or array literals to concatenate. * @return A new [Expr] representing the arrayConcat operation. */ @JvmStatic @@ -1450,105 +1091,210 @@ abstract class Expr internal constructor() { /** * Creates an expression that concatenates an array with other arrays. * + * @param firstArray The first array expression to concatenate to. + * @param secondArray An array expression or array literal to concatenate. + * @param otherArrays Optional additional array expressions or array literals to concatenate. * @return A new [Expr] representing the arrayConcat operation. */ @JvmStatic - fun arrayConcat(firstArray: Expr, vararg otherArrays: Any): Expr = - FunctionExpr("array_concat", firstArray, *otherArrays) + fun arrayConcat(firstArray: Expr, secondArray: Any, vararg otherArrays: Any): Expr = + FunctionExpr("array_concat", firstArray, secondArray, *otherArrays) /** * Creates an expression that concatenates a field's array value with other arrays. * + * @param firstArrayField The name of field that contains first array to concatenate to. + * @param secondArray An expression that evaluates to array to concatenate. + * @param otherArrays Optional additional array expressions or array literals to concatenate. * @return A new [Expr] representing the arrayConcat operation. */ @JvmStatic - fun arrayConcat(fieldName: String, secondArray: Expr, vararg otherArrays: Any): Expr = - FunctionExpr("array_concat", fieldName, secondArray, *otherArrays) + fun arrayConcat(firstArrayField: String, secondArray: Expr, vararg otherArrays: Any): Expr = + FunctionExpr("array_concat", firstArrayField, secondArray, *otherArrays) /** * Creates an expression that concatenates a field's array value with other arrays. * + * @param firstArrayField The name of field that contains first array to concatenate to. + * @param secondArray An array expression or array literal to concatenate. + * @param otherArrays Optional additional array expressions or array literals to concatenate. * @return A new [Expr] representing the arrayConcat operation. */ @JvmStatic - fun arrayConcat(fieldName: String, vararg otherArrays: Any): Expr = - FunctionExpr("array_concat", fieldName, *otherArrays) + fun arrayConcat(firstArrayField: String, secondArray: Any, vararg otherArrays: Any): Expr = + FunctionExpr("array_concat", firstArrayField, secondArray, *otherArrays) /** + * @return A new [Expr] representing the arrayReverse operation. */ @JvmStatic fun arrayReverse(array: Expr): Expr = FunctionExpr("array_reverse", array) /** + * @return A new [Expr] representing the arrayReverse operation. */ @JvmStatic fun arrayReverse(fieldName: String): Expr = FunctionExpr("array_reverse", fieldName) /** + * Creates an expression that checks if the array contains a specific [element]. + * + * @param array The array expression to check. + * @param element The element to search for in the array. + * @return A new [BooleanExpr] representing the arrayContains operation. */ @JvmStatic - fun arrayContains(array: Expr, value: Expr) = BooleanExpr("array_contains", array, value) + fun arrayContains(array: Expr, element: Expr) = BooleanExpr("array_contains", array, element) /** + * Creates an expression that checks if the array field contains a specific [element]. + * + * @param arrayFieldName The name of field that contains array to check. + * @param element The element to search for in the array. + * @return A new [BooleanExpr] representing the arrayContains operation. */ @JvmStatic - fun arrayContains(fieldName: String, value: Expr) = - BooleanExpr("array_contains", fieldName, value) + fun arrayContains(arrayFieldName: String, element: Expr) = + BooleanExpr("array_contains", arrayFieldName, element) /** + * Creates an expression that checks if the [array] contains a specific [element]. + * + * @param array The array expression to check. + * @param element The element to search for in the array. + * @return A new [BooleanExpr] representing the arrayContains operation. */ @JvmStatic - fun arrayContains(array: Expr, value: Any) = BooleanExpr("array_contains", array, value) + fun arrayContains(array: Expr, element: Any) = BooleanExpr("array_contains", array, element) /** + * Creates an expression that checks if the array field contains a specific [element]. + * + * @param arrayFieldName The name of field that contains array to check. + * @param element The element to search for in the array. + * @return A new [BooleanExpr] representing the arrayContains operation. */ @JvmStatic - fun arrayContains(fieldName: String, value: Any) = - BooleanExpr("array_contains", fieldName, value) + fun arrayContains(arrayFieldName: String, element: Any) = + BooleanExpr("array_contains", arrayFieldName, element) /** + * Creates an expression that checks if [array] contains all the specified [values]. + * + * @param array The array expression to check. + * @param values The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAll operation. */ @JvmStatic - fun arrayContainsAll(array: Expr, values: List) = - BooleanExpr("array_contains_all", array, ListOfExprs(toArrayOfExprOrConstant(values))) + fun arrayContainsAll(array: Expr, values: List) = arrayContainsAll(array, ListOfExprs(toArrayOfExprOrConstant(values))) /** + * Creates an expression that checks if [array] contains all elements of [arrayExpression]. + * + * @param array The array expression to check. + * @param arrayExpression The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAll operation. */ @JvmStatic - fun arrayContainsAll(fieldName: String, values: List) = - BooleanExpr("array_contains_all", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + fun arrayContainsAll(array: Expr, arrayExpression: Expr) = + BooleanExpr("array_contains_all", array, arrayExpression) /** + * Creates an expression that checks if array field contains all the specified [values]. + * + * @param arrayFieldName The name of field that contains array to check. + * @param values The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAll operation. + */ + @JvmStatic + fun arrayContainsAll(arrayFieldName: String, values: List) = + BooleanExpr("array_contains_all", arrayFieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + + /** + * Creates an expression that checks if array field contains all elements of [arrayExpression]. + * + * @param arrayFieldName The name of field that contains array to check. + * @param arrayExpression The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAll operation. + */ + @JvmStatic + fun arrayContainsAll(arrayFieldName: String, arrayExpression: Expr) = + BooleanExpr("array_contains_all", arrayFieldName, arrayExpression) + + /** + * Creates an expression that checks if [array] contains any of the specified [values]. + * + * @param array The array expression to check. + * @param values The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAny operation. */ @JvmStatic fun arrayContainsAny(array: Expr, values: List) = BooleanExpr("array_contains_any", array, ListOfExprs(toArrayOfExprOrConstant(values))) /** + * Creates an expression that checks if [array] contains any elements of [arrayExpression]. + * + * @param array The array expression to check. + * @param arrayExpression The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAny operation. + */ + @JvmStatic + fun arrayContainsAny(array: Expr, arrayExpression: Expr) = + BooleanExpr("array_contains_any", array, arrayExpression) + + /** + * Creates an expression that checks if array field contains any of the specified [values]. + * + * @param arrayFieldName The name of field that contains array to check. + * @param values The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAny operation. */ @JvmStatic - fun arrayContainsAny(fieldName: String, values: List) = - BooleanExpr("array_contains_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + fun arrayContainsAny(arrayFieldName: String, values: List) = + BooleanExpr("array_contains_any", arrayFieldName, ListOfExprs(toArrayOfExprOrConstant(values))) /** + * Creates an expression that checks if array field contains any elements of [arrayExpression]. + * + * @param arrayFieldName The name of field that contains array to check. + * @param arrayExpression The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAny operation. + */ + @JvmStatic + fun arrayContainsAny(arrayFieldName: String, arrayExpression: Expr) = + BooleanExpr("array_contains_any", arrayFieldName, arrayExpression) + + /** + * Creates an expression that calculates the length of an [array] expression. + * + * @param array The array expression to calculate the length of. + * @return A new [Expr] representing the the length of the array. */ @JvmStatic fun arrayLength(array: Expr): Expr = FunctionExpr("array_length", array) /** + * Creates an expression that calculates the length of an array field. + * + * @param arrayFieldName The name of the field containing an array to calculate the length of. + * @return A new [Expr] representing the the length of the array. */ - @JvmStatic fun arrayLength(fieldName: String): Expr = FunctionExpr("array_length", fieldName) + @JvmStatic fun arrayLength(arrayFieldName: String): Expr = FunctionExpr("array_length", arrayFieldName) /** + * @return A new [Expr] representing the cond operation. */ @JvmStatic fun cond(condition: BooleanExpr, then: Expr, otherwise: Expr): Expr = FunctionExpr("cond", condition, then, otherwise) /** + * @return A new [Expr] representing the cond operation. */ @JvmStatic fun cond(condition: BooleanExpr, then: Any, otherwise: Any): Expr = FunctionExpr("cond", condition, then, otherwise) /** + * @return A new [Expr] representing the exists operation. */ @JvmStatic fun exists(expr: Expr) = BooleanExpr("exists", expr) } @@ -1903,38 +1649,79 @@ abstract class Expr internal constructor() { /** * Creates an expression that concatenates a field's array value with other arrays. * + * @param secondArray An expression that evaluates to array to concatenate. + * @param otherArrays Optional additional array expressions or array literals to concatenate. * @return A new [Expr] representing the arrayConcat operation. */ - fun arrayConcat(vararg otherArrays: Expr) = Companion.arrayConcat(this, *otherArrays) + fun arrayConcat(secondArray: Expr, vararg otherArrays: Any) = + Companion.arrayConcat(this, secondArray, *otherArrays) /** * Creates an expression that concatenates a field's array value with other arrays. * + * @param secondArray An array expression or array literal to concatenate. + * @param otherArrays Optional additional array expressions or array literals to concatenate. * @return A new [Expr] representing the arrayConcat operation. */ - fun arrayConcat(arrays: List) = Companion.arrayConcat(this, arrays) + fun arrayConcat(secondArray: Any, vararg otherArrays: Any) = + Companion.arrayConcat(this, secondArray, *otherArrays) /** */ fun arrayReverse() = Companion.arrayReverse(this) /** + * Creates an expression that checks if array contains a specific [element]. + * + * @param element The element to search for in the array. + * @return A new [BooleanExpr] representing the arrayContains operation. */ - fun arrayContains(value: Expr) = Companion.arrayContains(this, value) + fun arrayContains(element: Expr): BooleanExpr = Companion.arrayContains(this, element) /** + * Creates an expression that checks if array contains a specific [element]. + * + * @param element The element to search for in the array. + * @return A new [BooleanExpr] representing the arrayContains operation. + */ + fun arrayContains(element: Any): BooleanExpr = Companion.arrayContains(this, element) + + /** + * Creates an expression that checks if array contains all the specified [values]. + * + * @param values The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAll operation. + */ + fun arrayContainsAll(values: List): BooleanExpr = Companion.arrayContainsAll(this, values) + + /** + * Creates an expression that checks if array contains all elements of [arrayExpression]. + * + * @param arrayExpression The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAll operation. */ - fun arrayContains(value: Any) = Companion.arrayContains(this, value) + fun arrayContainsAll(arrayExpression: Expr): BooleanExpr = Companion.arrayContainsAll(this, arrayExpression) /** + * Creates an expression that checks if array contains any of the specified [values]. + * + * @param values The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAny operation. */ - fun arrayContainsAll(values: List) = Companion.arrayContainsAll(this, values) + fun arrayContainsAny(values: List): BooleanExpr = Companion.arrayContainsAny(this, values) /** + * Creates an expression that checks if array contains any elements of [arrayExpression]. + * + * @param arrayExpression The elements to check for in the array. + * @return A new [BooleanExpr] representing the arrayContainsAny operation. */ - fun arrayContainsAny(values: List) = Companion.arrayContainsAny(this, values) + fun arrayContainsAny(arrayExpression: Expr): BooleanExpr = Companion.arrayContainsAny(this, arrayExpression) /** + * Creates an expression that calculates the length of an array expression. + * + * @return A new [Expr] representing the the length of the array. */ fun arrayLength() = Companion.arrayLength(this) From 309fa919cb4bb993b86e34ce32be3d62a8ec2d29 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 25 Apr 2025 16:51:24 -0400 Subject: [PATCH 48/77] WIP --- .../firebase/firestore/pipeline/aggregates.kt | 7 ++- .../firestore/pipeline/expressions.kt | 53 +++++++++++-------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt index bdc5707388b..60bdbdab8eb 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt @@ -22,7 +22,11 @@ internal constructor(internal val alias: String, internal val expr: AggregateFun /** A class that represents an aggregate function. */ class AggregateFunction -private constructor(private val name: String, private val params: Array) { +private constructor( + private val name: String, + private val params: Array, + private val options: InternalOptions = InternalOptions.EMPTY +) { private constructor(name: String) : this(name, emptyArray()) private constructor(name: String, expr: Expr) : this(name, arrayOf(expr)) private constructor(name: String, fieldName: String) : this(name, Expr.field(fieldName)) @@ -71,6 +75,7 @@ private constructor(private val name: String, private val params: Array) = arrayContainsAll(array, ListOfExprs(toArrayOfExprOrConstant(values))) + fun arrayContainsAll(array: Expr, values: List) = + arrayContainsAll(array, ListOfExprs(toArrayOfExprOrConstant(values))) /** * Creates an expression that checks if [array] contains all elements of [arrayExpression]. @@ -1206,7 +1203,11 @@ abstract class Expr internal constructor() { */ @JvmStatic fun arrayContainsAll(arrayFieldName: String, values: List) = - BooleanExpr("array_contains_all", arrayFieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + BooleanExpr( + "array_contains_all", + arrayFieldName, + ListOfExprs(toArrayOfExprOrConstant(values)) + ) /** * Creates an expression that checks if array field contains all elements of [arrayExpression]. @@ -1250,7 +1251,11 @@ abstract class Expr internal constructor() { */ @JvmStatic fun arrayContainsAny(arrayFieldName: String, values: List) = - BooleanExpr("array_contains_any", arrayFieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + BooleanExpr( + "array_contains_any", + arrayFieldName, + ListOfExprs(toArrayOfExprOrConstant(values)) + ) /** * Creates an expression that checks if array field contains any elements of [arrayExpression]. @@ -1277,25 +1282,20 @@ abstract class Expr internal constructor() { * @param arrayFieldName The name of the field containing an array to calculate the length of. * @return A new [Expr] representing the the length of the array. */ - @JvmStatic fun arrayLength(arrayFieldName: String): Expr = FunctionExpr("array_length", arrayFieldName) + @JvmStatic + fun arrayLength(arrayFieldName: String): Expr = FunctionExpr("array_length", arrayFieldName) - /** - * @return A new [Expr] representing the cond operation. - */ + /** @return A new [Expr] representing the cond operation. */ @JvmStatic fun cond(condition: BooleanExpr, then: Expr, otherwise: Expr): Expr = FunctionExpr("cond", condition, then, otherwise) - /** - * @return A new [Expr] representing the cond operation. - */ + /** @return A new [Expr] representing the cond operation. */ @JvmStatic fun cond(condition: BooleanExpr, then: Any, otherwise: Any): Expr = FunctionExpr("cond", condition, then, otherwise) - /** - * @return A new [Expr] representing the exists operation. - */ + /** @return A new [Expr] representing the exists operation. */ @JvmStatic fun exists(expr: Expr) = BooleanExpr("exists", expr) } @@ -1700,7 +1700,8 @@ abstract class Expr internal constructor() { * @param arrayExpression The elements to check for in the array. * @return A new [BooleanExpr] representing the arrayContainsAll operation. */ - fun arrayContainsAll(arrayExpression: Expr): BooleanExpr = Companion.arrayContainsAll(this, arrayExpression) + fun arrayContainsAll(arrayExpression: Expr): BooleanExpr = + Companion.arrayContainsAll(this, arrayExpression) /** * Creates an expression that checks if array contains any of the specified [values]. @@ -1716,7 +1717,8 @@ abstract class Expr internal constructor() { * @param arrayExpression The elements to check for in the array. * @return A new [BooleanExpr] representing the arrayContainsAny operation. */ - fun arrayContainsAny(arrayExpression: Expr): BooleanExpr = Companion.arrayContainsAny(this, arrayExpression) + fun arrayContainsAny(arrayExpression: Expr): BooleanExpr = + Companion.arrayContainsAny(this, arrayExpression) /** * Creates an expression that calculates the length of an array expression. @@ -1872,7 +1874,11 @@ internal class ListOfExprs(private val expressions: Array) : Expr() { * [FunctionExpr] instances. */ open class FunctionExpr -internal constructor(private val name: String, private val params: Array) : Expr() { +internal constructor( + private val name: String, + private val params: Array, + private val options: InternalOptions = InternalOptions.EMPTY +) : Expr() { internal constructor( name: String, param: Expr, @@ -1896,13 +1902,14 @@ internal constructor(private val name: String, private val params: Array) : - FunctionExpr(name, params) { + FunctionExpr(name, params, InternalOptions.EMPTY) { internal constructor( name: String, params: List From 0606a18a3914ed9ea67ae9c5d3cb63e4f3bd71dd Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 28 Apr 2025 22:21:26 -0400 Subject: [PATCH 49/77] Work on pipeline expressions. --- .../google/firebase/firestore/model/Values.kt | 72 +-- .../firestore/pipeline/expressions.kt | 440 +++++++++++++++--- 2 files changed, 396 insertions(+), 116 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt index afda3ca32ae..3bcd2ed3c38 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt @@ -559,46 +559,31 @@ internal object Values { return VECTOR_VALUE_TYPE == value.mapValue.fieldsMap[TYPE_KEY] } - @JvmStatic - fun encodeValue(value: Long): Value { - return Value.newBuilder().setIntegerValue(value).build() - } + @JvmStatic fun encodeValue(value: Long): Value = Value.newBuilder().setIntegerValue(value).build() @JvmStatic - fun encodeValue(value: Int): Value { - return Value.newBuilder().setIntegerValue(value.toLong()).build() - } + fun encodeValue(value: Int): Value = Value.newBuilder().setIntegerValue(value.toLong()).build() @JvmStatic - fun encodeValue(value: Double): Value { - return Value.newBuilder().setDoubleValue(value).build() - } + fun encodeValue(value: Double): Value = Value.newBuilder().setDoubleValue(value).build() @JvmStatic - fun encodeValue(value: Float): Value { - return Value.newBuilder().setDoubleValue(value.toDouble()).build() - } + fun encodeValue(value: Float): Value = Value.newBuilder().setDoubleValue(value.toDouble()).build() @JvmStatic - fun encodeValue(value: Number): Value { - return when (value) { + fun encodeValue(value: Number): Value = + when (value) { is Long -> encodeValue(value) is Int -> encodeValue(value) is Double -> encodeValue(value) is Float -> encodeValue(value) else -> throw IllegalArgumentException("Unexpected number type: $value") } - } @JvmStatic - fun encodeValue(value: String): Value { - return Value.newBuilder().setStringValue(value).build() - } + fun encodeValue(value: String): Value = Value.newBuilder().setStringValue(value).build() - @JvmStatic - fun encodeValue(date: Date): Value { - return encodeValue(com.google.firebase.Timestamp((date))) - } + @JvmStatic fun encodeValue(date: Date): Value = encodeValue(com.google.firebase.Timestamp((date))) @JvmStatic fun encodeValue(timestamp: com.google.firebase.Timestamp): Value { @@ -615,33 +600,29 @@ internal object Values { } @JvmStatic - fun encodeValue(value: Boolean): Value { - return Value.newBuilder().setBooleanValue(value).build() - } + fun encodeValue(value: Boolean): Value = Value.newBuilder().setBooleanValue(value).build() @JvmStatic - fun encodeValue(geoPoint: GeoPoint): Value { - return Value.newBuilder() + fun encodeValue(geoPoint: GeoPoint): Value = + Value.newBuilder() .setGeoPointValue( LatLng.newBuilder().setLatitude(geoPoint.latitude).setLongitude(geoPoint.longitude) ) .build() - } @JvmStatic - fun encodeValue(value: Blob): Value { - return Value.newBuilder().setBytesValue(value.toByteString()).build() - } + fun encodeValue(value: ByteArray): Value = + Value.newBuilder().setBytesValue(ByteString.copyFrom(value)).build() @JvmStatic - fun encodeValue(docRef: DocumentReference): Value { - return Value.newBuilder().setReferenceValue(docRef.fullPath).build() - } + fun encodeValue(value: Blob): Value = + Value.newBuilder().setBytesValue(value.toByteString()).build() @JvmStatic - fun encodeValue(vector: VectorValue): Value { - return encodeVectorValue(vector.toArray()) - } + fun encodeValue(docRef: DocumentReference): Value = + Value.newBuilder().setReferenceValue(docRef.fullPath).build() + + @JvmStatic fun encodeValue(vector: VectorValue): Value = encodeVectorValue(vector.toArray()) @JvmStatic fun encodeVectorValue(vector: DoubleArray): Value { @@ -659,18 +640,16 @@ internal object Values { } @JvmStatic - fun encodeValue(map: Map): Value { - return Value.newBuilder().setMapValue(MapValue.newBuilder().putAllFields(map)).build() - } + fun encodeValue(map: Map): Value = + Value.newBuilder().setMapValue(MapValue.newBuilder().putAllFields(map)).build() @JvmStatic - fun encodeValue(values: Iterable): Value { - return Value.newBuilder().setArrayValue(ArrayValue.newBuilder().addAllValues(values)).build() - } + fun encodeValue(values: Iterable): Value = + Value.newBuilder().setArrayValue(ArrayValue.newBuilder().addAllValues(values)).build() @JvmStatic - fun encodeAnyValue(value: Any?): Value { - return when (value) { + fun encodeAnyValue(value: Any?): Value = + when (value) { null -> NULL_VALUE is String -> encodeValue(value) is Number -> encodeValue(value) @@ -682,5 +661,4 @@ internal object Values { is VectorValue -> encodeValue(value) else -> throw IllegalArgumentException("Unexpected type: $value") } - } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 07188c6a2ef..fbe5ad07a78 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -73,6 +73,7 @@ abstract class Expr internal constructor() { is GeoPoint -> constant(value) is Blob -> constant(value) is DocumentReference -> constant(value) + is ByteArray -> constant(value) is VectorValue -> constant(value) is Value -> ValueConstant(value) is Map<*, *> -> @@ -177,6 +178,17 @@ abstract class Expr internal constructor() { return ValueConstant(encodeValue(value)) } + /** + * Create a constant for a bytes value. + * + * @param value The bytes value. + * @return A new [Expr] constant instance. + */ + @JvmStatic + fun constant(value: ByteArray): Expr { + return ValueConstant(encodeValue(value)) + } + /** * Create a constant for a [Blob] value. * @@ -316,91 +328,247 @@ abstract class Expr internal constructor() { /** @return A new [Expr] representing the not operation. */ @JvmStatic fun not(condition: BooleanExpr) = BooleanExpr("not", condition) - /** @return A new [Expr] representing the bitAnd operation. */ - @JvmStatic fun bitAnd(left: Expr, right: Expr): Expr = FunctionExpr("bit_and", left, right) + /** + * Creates an expression that applies a bitwise AND operation between two expressions. + * + * @param bits An expression that returns bits when evaluated. + * @param bitsOther An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise AND operation. + */ + @JvmStatic + fun bitAnd(bits: Expr, bitsOther: Expr): Expr = FunctionExpr("bit_and", bits, bitsOther) - /** @return A new [Expr] representing the bitAnd operation. */ - @JvmStatic fun bitAnd(left: Expr, right: Any): Expr = FunctionExpr("bit_and", left, right) + /** + * Creates an expression that applies a bitwise AND operation between an expression and a + * constant. + * + * @param bits An expression that returns bits when evaluated. + * @param bitsOther A constant byte array. + * @return A new [Expr] representing the bitwise AND operation. + */ + @JvmStatic + fun bitAnd(bits: Expr, bitsOther: ByteArray): Expr = + FunctionExpr("bit_and", bits, constant(bitsOther)) - /** @return A new [Expr] representing the bitAnd operation. */ + /** + * Creates an expression that applies a bitwise AND operation between an field and an + * expression. + * + * @param bitsFieldName Name of field that contains bits data. + * @param bitsOther An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise AND operation. + */ @JvmStatic - fun bitAnd(fieldName: String, right: Expr): Expr = FunctionExpr("bit_and", fieldName, right) + fun bitAnd(bitsFieldName: String, bitsOther: Expr): Expr = + FunctionExpr("bit_and", bitsFieldName, bitsOther) - /** @return A new [Expr] representing the bitAnd operation. */ + /** + * Creates an expression that applies a bitwise AND operation between an field and constant. + * + * @param bitsFieldName Name of field that contains bits data. + * @param bitsOther A constant byte array. + * @return A new [Expr] representing the bitwise AND operation. + */ @JvmStatic - fun bitAnd(fieldName: String, right: Any): Expr = FunctionExpr("bit_and", fieldName, right) + fun bitAnd(bitsFieldName: String, bitsOther: ByteArray): Expr = + FunctionExpr("bit_and", bitsFieldName, constant(bitsOther)) - /** @return A new [Expr] representing the bitOr operation. */ - @JvmStatic fun bitOr(left: Expr, right: Expr): Expr = FunctionExpr("bit_or", left, right) + /** + * Creates an expression that applies a bitwise OR operation between two expressions. + * + * @param bits An expression that returns bits when evaluated. + * @param bitsOther An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise OR operation. + */ + @JvmStatic + fun bitOr(bits: Expr, bitsOther: Expr): Expr = FunctionExpr("bit_or", bits, bitsOther) - /** @return A new [Expr] representing the bitOr operation. */ - @JvmStatic fun bitOr(left: Expr, right: Any): Expr = FunctionExpr("bit_or", left, right) + /** + * Creates an expression that applies a bitwise OR operation between an expression and a + * constant. + * + * @param bits An expression that returns bits when evaluated. + * @param bitsOther A constant byte array. + * @return A new [Expr] representing the bitwise OR operation. + */ + @JvmStatic + fun bitOr(bits: Expr, bitsOther: ByteArray): Expr = + FunctionExpr("bit_or", bits, constant(bitsOther)) - /** @return A new [Expr] representing the bitOr operation. */ + /** + * Creates an expression that applies a bitwise OR operation between an field and an expression. + * + * @param bitsFieldName Name of field that contains bits data. + * @param bitsOther An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise OR operation. + */ @JvmStatic - fun bitOr(fieldName: String, right: Expr): Expr = FunctionExpr("bit_or", fieldName, right) + fun bitOr(bitsFieldName: String, bitsOther: Expr): Expr = + FunctionExpr("bit_or", bitsFieldName, bitsOther) - /** @return A new [Expr] representing the bitOr operation. */ + /** + * Creates an expression that applies a bitwise OR operation between an field and constant. + * + * @param bitsFieldName Name of field that contains bits data. + * @param bitsOther A constant byte array. + * @return A new [Expr] representing the bitwise OR operation. + */ @JvmStatic - fun bitOr(fieldName: String, right: Any): Expr = FunctionExpr("bit_or", fieldName, right) + fun bitOr(bitsFieldName: String, bitsOther: ByteArray): Expr = + FunctionExpr("bit_or", bitsFieldName, constant(bitsOther)) - /** @return A new [Expr] representing the bitXor operation. */ - @JvmStatic fun bitXor(left: Expr, right: Expr): Expr = FunctionExpr("bit_xor", left, right) + /** + * Creates an expression that applies a bitwise XOR operation between two expressions. + * + * @param bits An expression that returns bits when evaluated. + * @param bitsOther An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise XOR operation. + */ + @JvmStatic + fun bitXor(bits: Expr, bitsOther: Expr): Expr = FunctionExpr("bit_xor", bits, bitsOther) - /** @return A new [Expr] representing the bitXor operation. */ - @JvmStatic fun bitXor(left: Expr, right: Any): Expr = FunctionExpr("bit_xor", left, right) + /** + * Creates an expression that applies a bitwise XOR operation between an expression and a + * constant. + * + * @param bits An expression that returns bits when evaluated. + * @param bitsOther A constant byte array. + * @return A new [Expr] representing the bitwise XOR operation. + */ + @JvmStatic + fun bitXor(bits: Expr, bitsOther: ByteArray): Expr = + FunctionExpr("bit_xor", bits, constant(bitsOther)) - /** @return A new [Expr] representing the bitXor operation. */ + /** + * Creates an expression that applies a bitwise XOR operation between an field and an + * expression. + * + * @param bitsFieldName Name of field that contains bits data. + * @param bitsOther An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise XOR operation. + */ @JvmStatic - fun bitXor(fieldName: String, right: Expr): Expr = FunctionExpr("bit_xor", fieldName, right) + fun bitXor(bitsFieldName: String, bitsOther: Expr): Expr = + FunctionExpr("bit_xor", bitsFieldName, bitsOther) - /** @return A new [Expr] representing the bitXor operation. */ + /** + * Creates an expression that applies a bitwise XOR operation between an field and constant. + * + * @param bitsFieldName Name of field that contains bits data. + * @param bitsOther A constant byte array. + * @return A new [Expr] representing the bitwise XOR operation. + */ @JvmStatic - fun bitXor(fieldName: String, right: Any): Expr = FunctionExpr("bit_xor", fieldName, right) + fun bitXor(bitsFieldName: String, bitsOther: ByteArray): Expr = + FunctionExpr("bit_xor", bitsFieldName, constant(bitsOther)) - /** @return A new [Expr] representing the bitNot operation. */ - @JvmStatic fun bitNot(left: Expr): Expr = FunctionExpr("bit_not", left) + /** + * Creates an expression that applies a bitwise NOT operation to an expression. + * + * @param bits An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise NOT operation. + */ + @JvmStatic fun bitNot(bits: Expr): Expr = FunctionExpr("bit_not", bits) - /** @return A new [Expr] representing the bitNot operation. */ - @JvmStatic fun bitNot(fieldName: String): Expr = FunctionExpr("bit_not", fieldName) + /** + * Creates an expression that applies a bitwise NOT operation to a field. + * + * @param bitsFieldName Name of field that contains bits data. + * @return A new [Expr] representing the bitwise NOT operation. + */ + @JvmStatic fun bitNot(bitsFieldName: String): Expr = FunctionExpr("bit_not", bitsFieldName) - /** @return A new [Expr] representing the bitLeftShift operation. */ + /** + * Creates an expression that applies a bitwise left shift operation between two expressions. + * + * @param bits An expression that returns bits when evaluated. + * @param numberExpr The number of bits to shift. + * @return A new [Expr] representing the bitwise left shift operation. + */ @JvmStatic - fun bitLeftShift(left: Expr, numberExpr: Expr): Expr = - FunctionExpr("bit_left_shift", left, numberExpr) + fun bitLeftShift(bits: Expr, numberExpr: Expr): Expr = + FunctionExpr("bit_left_shift", bits, numberExpr) - /** @return A new [Expr] representing the bitLeftShift operation. */ + /** + * Creates an expression that applies a bitwise left shift operation between an expression and a + * constant. + * + * @param bits An expression that returns bits when evaluated. + * @param number The number of bits to shift. + * @return A new [Expr] representing the bitwise left shift operation. + */ @JvmStatic - fun bitLeftShift(left: Expr, number: Int): Expr = FunctionExpr("bit_left_shift", left, number) + fun bitLeftShift(bits: Expr, number: Int): Expr = FunctionExpr("bit_left_shift", bits, number) - /** @return A new [Expr] representing the bitLeftShift operation. */ + /** + * Creates an expression that applies a bitwise left shift operation between a field and an + * expression. + * + * @param bitsFieldName Name of field that contains bits data. + * @param numberExpr The number of bits to shift. + * @return A new [Expr] representing the bitwise left shift operation. + */ @JvmStatic - fun bitLeftShift(fieldName: String, numberExpr: Expr): Expr = - FunctionExpr("bit_left_shift", fieldName, numberExpr) + fun bitLeftShift(bitsFieldName: String, numberExpr: Expr): Expr = + FunctionExpr("bit_left_shift", bitsFieldName, numberExpr) - /** @return A new [Expr] representing the bitLeftShift operation. */ + /** + * Creates an expression that applies a bitwise left shift operation between a field and a + * constant. + * + * @param bitsFieldName Name of field that contains bits data. + * @param number The number of bits to shift. + * @return A new [Expr] representing the bitwise left shift operation. + */ @JvmStatic - fun bitLeftShift(fieldName: String, number: Int): Expr = - FunctionExpr("bit_left_shift", fieldName, number) + fun bitLeftShift(bitsFieldName: String, number: Int): Expr = + FunctionExpr("bit_left_shift", bitsFieldName, number) - /** @return A new [Expr] representing the bitRightShift operation. */ + /** + * Creates an expression that applies a bitwise right shift operation between two expressions. + * + * @param bits An expression that returns bits when evaluated. + * @param numberExpr The number of bits to shift. + * @return A new [Expr] representing the bitwise right shift operation. + */ @JvmStatic - fun bitRightShift(left: Expr, numberExpr: Expr): Expr = - FunctionExpr("bit_right_shift", left, numberExpr) + fun bitRightShift(bits: Expr, numberExpr: Expr): Expr = + FunctionExpr("bit_right_shift", bits, numberExpr) - /** @return A new [Expr] representing the bitRightShift operation. */ + /** + * Creates an expression that applies a bitwise right shift operation between an expression and + * a constant. + * + * @param bits An expression that returns bits when evaluated. + * @param number The number of bits to shift. + * @return A new [Expr] representing the bitwise right shift operation. + */ @JvmStatic - fun bitRightShift(left: Expr, number: Int): Expr = FunctionExpr("bit_right_shift", left, number) + fun bitRightShift(bits: Expr, number: Int): Expr = FunctionExpr("bit_right_shift", bits, number) - /** @return A new [Expr] representing the bitRightShift operation. */ + /** + * Creates an expression that applies a bitwise right shift operation between a field and an + * expression. + * + * @param bitsFieldName Name of field that contains bits data. + * @param numberExpr The number of bits to shift. + * @return A new [Expr] representing the bitwise right shift operation. + */ @JvmStatic - fun bitRightShift(fieldName: String, numberExpr: Expr): Expr = - FunctionExpr("bit_right_shift", fieldName, numberExpr) + fun bitRightShift(bitsFieldName: String, numberExpr: Expr): Expr = + FunctionExpr("bit_right_shift", bitsFieldName, numberExpr) - /** @return A new [Expr] representing the bitRightShift operation. */ + /** + * Creates an expression that applies a bitwise right shift operation between a field and a + * constant. + * + * @param bitsFieldName Name of field that contains bits data. + * @param number The number of bits to shift. + * @return A new [Expr] representing the bitwise right shift operation. + */ @JvmStatic - fun bitRightShift(fieldName: String, number: Int): Expr = - FunctionExpr("bit_right_shift", fieldName, number) + fun bitRightShift(bitsFieldName: String, number: Int): Expr = + FunctionExpr("bit_right_shift", bitsFieldName, number) /** * Creates an expression that adds this expression to another expression. @@ -1124,11 +1292,22 @@ abstract class Expr internal constructor() { fun arrayConcat(firstArrayField: String, secondArray: Any, vararg otherArrays: Any): Expr = FunctionExpr("array_concat", firstArrayField, secondArray, *otherArrays) - /** @return A new [Expr] representing the arrayReverse operation. */ + /** + * Reverses the order of elements in the [array]. + * + * @param array The array expression to reverse. + * @return A new [Expr] representing the arrayReverse operation. + */ @JvmStatic fun arrayReverse(array: Expr): Expr = FunctionExpr("array_reverse", array) - /** @return A new [Expr] representing the arrayReverse operation. */ - @JvmStatic fun arrayReverse(fieldName: String): Expr = FunctionExpr("array_reverse", fieldName) + /** + * Reverses the order of elements in the array field. + * + * @param arrayFieldName The name of field that contains the array to reverse. + * @return A new [Expr] representing the arrayReverse operation. + */ + @JvmStatic + fun arrayReverse(arrayFieldName: String): Expr = FunctionExpr("array_reverse", arrayFieldName) /** * Creates an expression that checks if the array contains a specific [element]. @@ -1272,7 +1451,7 @@ abstract class Expr internal constructor() { * Creates an expression that calculates the length of an [array] expression. * * @param array The array expression to calculate the length of. - * @return A new [Expr] representing the the length of the array. + * @return A new [Expr] representing the length of the array. */ @JvmStatic fun arrayLength(array: Expr): Expr = FunctionExpr("array_length", array) @@ -1280,11 +1459,62 @@ abstract class Expr internal constructor() { * Creates an expression that calculates the length of an array field. * * @param arrayFieldName The name of the field containing an array to calculate the length of. - * @return A new [Expr] representing the the length of the array. + * @return A new [Expr] representing the length of the array. */ @JvmStatic fun arrayLength(arrayFieldName: String): Expr = FunctionExpr("array_length", arrayFieldName) + /** + * Creates an expression that indexes into an array from the beginning or end and return the + * element. If the offset exceeds the array length, an error is returned. A negative offset, + * starts from the end. + * + * @param array An [Expr] evaluating to an array. + * @param offset An Expr evaluating to the index of the element to return. + * @return A new [Expr] representing the arrayOffset operation. + */ + @JvmStatic + fun arrayOffset(array: Expr, offset: Expr): Expr = FunctionExpr("array_offset", array, offset) + + /** + * Creates an expression that indexes into an array from the beginning or end and return the + * element. If the offset exceeds the array length, an error is returned. A negative offset, + * starts from the end. + * + * @param array An [Expr] evaluating to an array. + * @param offset The index of the element to return. + * @return A new [Expr] representing the arrayOffset operation. + */ + @JvmStatic + fun arrayOffset(array: Expr, offset: Int): Expr = + FunctionExpr("array_offset", array, constant(offset)) + + /** + * Creates an expression that indexes into an array from the beginning or end and return the + * element. If the offset exceeds the array length, an error is returned. A negative offset, + * starts from the end. + * + * @param arrayFieldName The name of an array field. + * @param offset An Expr evaluating to the index of the element to return. + * @return A new [Expr] representing the arrayOffset operation. + */ + @JvmStatic + fun arrayOffset(arrayFieldName: String, offset: Expr): Expr = + FunctionExpr("array_offset", arrayFieldName, offset) + + /** + * Creates an expression that indexes into an array from the beginning or end and return the + * element. If the offset exceeds the array length, an error is returned. A negative offset, + * starts from the end. + * + * @param arrayFieldName The name of an array field. + * @param offset The index of the element to return. + * @return A new [Expr] representing the arrayOffset operation. + */ + @JvmStatic + fun arrayOffset(arrayFieldName: String, offset: Int): Expr = + FunctionExpr("array_offset", arrayFieldName, constant(offset)) + /** @return A new [Expr] representing the cond operation. */ @JvmStatic fun cond(condition: BooleanExpr, then: Expr, otherwise: Expr): Expr = @@ -1300,48 +1530,91 @@ abstract class Expr internal constructor() { } /** + * Creates an expression that applies a bitwise AND operation with other expression. + * + * @param bitsOther An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise AND operation. */ - fun bitAnd(right: Expr) = bitAnd(this, right) + fun bitAnd(bitsOther: Expr): Expr = Companion.bitAnd(this, bitsOther) /** + * Creates an expression that applies a bitwise AND operation with a constant. + * + * @param bitsOther A constant byte array. + * @return A new [Expr] representing the bitwise AND operation. */ - fun bitAnd(right: Any) = bitAnd(this, right) + fun bitAnd(bitsOther: ByteArray): Expr = Companion.bitAnd(this, bitsOther) /** + * Creates an expression that applies a bitwise OR operation with other expression. + * + * @param bitsOther An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise OR operation. */ - fun bitOr(right: Expr) = bitOr(this, right) + fun bitOr(bitsOther: Expr): Expr = Companion.bitOr(this, bitsOther) /** + * Creates an expression that applies a bitwise OR operation with a constant. + * + * @param bitsOther A constant byte array. + * @return A new [Expr] representing the bitwise OR operation. */ - fun bitOr(right: Any) = bitOr(this, right) + fun bitOr(bitsOther: ByteArray): Expr = Companion.bitOr(this, bitsOther) /** + * Creates an expression that applies a bitwise XOR operation with an expression. + * + * @param bitsOther An expression that returns bits when evaluated. + * @return A new [Expr] representing the bitwise XOR operation. */ - fun bitXor(right: Expr) = bitXor(this, right) + fun bitXor(bitsOther: Expr): Expr = Companion.bitXor(this, bitsOther) /** + * Creates an expression that applies a bitwise XOR operation with a constant. + * + * @param bitsOther A constant byte array. + * @return A new [Expr] representing the bitwise XOR operation. */ - fun bitXor(right: Any) = bitXor(this, right) + fun bitXor(bitsOther: ByteArray): Expr = Companion.bitXor(this, bitsOther) /** + * Creates an expression that applies a bitwise NOT operation to this expression. + * + * @return A new [Expr] representing the bitwise NOT operation. */ - fun bitNot() = bitNot(this) + fun bitNot(): Expr = Companion.bitNot(this) /** + * Creates an expression that applies a bitwise left shift operation with an expression. + * + * @param numberExpr The number of bits to shift. + * @return A new [Expr] representing the bitwise left shift operation. */ - fun bitLeftShift(numberExpr: Expr) = bitLeftShift(this, numberExpr) + fun bitLeftShift(numberExpr: Expr): Expr = Companion.bitLeftShift(this, numberExpr) /** + * Creates an expression that applies a bitwise left shift operation with a constant. + * + * @param number The number of bits to shift. + * @return A new [Expr] representing the bitwise left shift operation. */ - fun bitLeftShift(number: Int) = bitLeftShift(this, number) + fun bitLeftShift(number: Int): Expr = Companion.bitLeftShift(this, number) /** + * Creates an expression that applies a bitwise right shift operation with an expression. + * + * @param numberExpr The number of bits to shift. + * @return A new [Expr] representing the bitwise right shift operation. */ - fun bitRightShift(numberExpr: Expr) = bitRightShift(this, numberExpr) + fun bitRightShift(numberExpr: Expr): Expr = Companion.bitRightShift(this, numberExpr) /** + * Creates an expression that applies a bitwise right shift operation with a constant. + * + * @param number The number of bits to shift. + * @return A new [Expr] representing the bitwise right shift operation. */ - fun bitRightShift(number: Int) = bitRightShift(this, number) + fun bitRightShift(number: Int): Expr = Companion.bitRightShift(this, number) /** * Assigns an alias to this expression. @@ -1667,6 +1940,9 @@ abstract class Expr internal constructor() { Companion.arrayConcat(this, secondArray, *otherArrays) /** + * Reverses the order of elements in the array. + * + * @return A new [Expr] representing the arrayReverse operation. */ fun arrayReverse() = Companion.arrayReverse(this) @@ -1723,10 +1999,30 @@ abstract class Expr internal constructor() { /** * Creates an expression that calculates the length of an array expression. * - * @return A new [Expr] representing the the length of the array. + * @return A new [Expr] representing the length of the array. */ fun arrayLength() = Companion.arrayLength(this) + /** + * Creates an expression that indexes into an array from the beginning or end and return the + * element. If the offset exceeds the array length, an error is returned. A negative offset, + * starts from the end. + * + * @param offset An Expr evaluating to the index of the element to return. + * @return A new [Expr] representing the arrayOffset operation. + */ + fun arrayOffset(offset: Expr) = Companion.arrayOffset(this, offset) + + /** + * Creates an expression that indexes into an array from the beginning or end and return the + * element. If the offset exceeds the array length, an error is returned. A negative offset, + * starts from the end. + * + * @param offset An Expr evaluating to the index of the element to return. + * @return A new [Expr] representing the arrayOffset operation. + */ + fun arrayOffset(offset: Int) = Companion.arrayOffset(this, offset) + /** */ fun sum() = AggregateFunction.sum(this) @@ -1744,12 +2040,18 @@ abstract class Expr internal constructor() { fun max() = AggregateFunction.max(this) /** + * Create an [Ordering] that sorts documents in ascending order based on value of this expression + * + * @return A new [Ordering] object with ascending sort by this expression. */ - fun ascending() = Ordering.ascending(this) + fun ascending(): Ordering = Ordering.ascending(this) /** + * Create an [Ordering] that sorts documents in descending order based on value of this expression + * + * @return A new [Ordering] object with descending sort by this expression. */ - fun descending() = Ordering.descending(this) + fun descending(): Ordering = Ordering.descending(this) /** */ From 402a98d549426832c231fd2ea12b2e413b715c69 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 29 Apr 2025 11:30:55 -0400 Subject: [PATCH 50/77] Comments --- .../firestore/pipeline/expressions.kt | 355 +++++++++++++++--- 1 file changed, 298 insertions(+), 57 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index fbe5ad07a78..eb32b56df5e 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -644,17 +644,41 @@ abstract class Expr internal constructor() { @JvmStatic fun multiply(fieldName: String, other: Any): Expr = FunctionExpr("multiply", fieldName, other) - /** @return A new [Expr] representing the divide operation. */ + /** + * Creates an expression that divides two expressions. + * + * @param left The expression to be divided. + * @param right The expression to divide by. + * @return A new [Expr] representing the division operation. + */ @JvmStatic fun divide(left: Expr, right: Expr): Expr = FunctionExpr("divide", left, right) - /** @return A new [Expr] representing the divide operation. */ + /** + * Creates an expression that divides an expression by an expression by a value. + * + * @param left The expression to be divided. + * @param right The value to divide by. + * @return A new [Expr] representing the division operation. + */ @JvmStatic fun divide(left: Expr, right: Any): Expr = FunctionExpr("divide", left, right) - /** @return A new [Expr] representing the divide operation. */ + /** + * Creates an expression that divides a field's value by an expression. + * + * @param fieldName The field name to be divided. + * @param other The expression to divide by. + * @return A new [Expr] representing the divide operation. + */ @JvmStatic fun divide(fieldName: String, other: Expr): Expr = FunctionExpr("divide", fieldName, other) - /** @return A new [Expr] representing the divide operation. */ + /** + * Creates an expression that divides a field's value by a value. + * + * @param fieldName The field name to be divided. + * @param other The value to divide by. + * @return A new [Expr] representing the divide operation. + */ @JvmStatic fun divide(fieldName: String, other: Any): Expr = FunctionExpr("divide", fieldName, other) @@ -744,16 +768,38 @@ abstract class Expr internal constructor() { fun replaceAll(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_all", fieldName, find, replace) - /** @return A new [Expr] representing the charLength operation. */ - @JvmStatic fun charLength(value: Expr): Expr = FunctionExpr("char_length", value) + /** + * Creates an expression that calculates the character length of a string expression in UTF8. + * + * @param expr The expression representing the string. + * @return A new [Expr] representing the charLength operation. + */ + @JvmStatic fun charLength(expr: Expr): Expr = FunctionExpr("char_length", expr) - /** @return A new [Expr] representing the charLength operation. */ + /** + * Creates an expression that calculates the character length of a string field in UTF8. + * + * @param fieldName The name of the field containing the string. + * @return A new [Expr] representing the charLength operation. + */ @JvmStatic fun charLength(fieldName: String): Expr = FunctionExpr("char_length", fieldName) - /** @return A new [Expr] representing the byteLength operation. */ + /** + * Creates an expression that calculates the length of a string in UTF-8 bytes, or just the + * length of a Blob. + * + * @param value The expression representing the string. + * @return A new [Expr] representing the length of the string in bytes. + */ @JvmStatic fun byteLength(value: Expr): Expr = FunctionExpr("byte_length", value) - /** @return A new [Expr] representing the byteLength operation. */ + /** + * Creates an expression that calculates the length of a string represented by a field in UTF-8 + * bytes, or just the length of a Blob. + * + * @param fieldName The name of the field containing the string. + * @return A new [Expr] representing the length of the string in bytes. + */ @JvmStatic fun byteLength(fieldName: String): Expr = FunctionExpr("byte_length", fieldName) /** @return A new [Expr] representing the like operation. */ @@ -982,95 +1028,203 @@ abstract class Expr internal constructor() { @JvmStatic fun mapRemove(mapField: String, key: String): Expr = FunctionExpr("map_remove", mapField, key) - /** @return A new [Expr] representing the cosineDistance operation. */ + /** + * Calculates the Cosine distance between two vector expressions. + * + * @param vector1 The first vector (represented as an Expr) to compare against. + * @param vector2 The other vector (represented as an Expr) to compare against. + * @return A new [Expr] representing the cosine distance between the two vectors. + */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("cosine_distance", vector1, vector2) - /** @return A new [Expr] representing the cosineDistance operation. */ + /** + * Calculates the Cosine distance between vector expression and a vector literal. + * + * @param vector1 The first vector (represented as an Expr) to compare against. + * @param vector2 The other vector (as an array of doubles) to compare against. + * @return A new [Expr] representing the cosine distance between the two vectors. + */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("cosine_distance", vector1, vector(vector2)) - /** @return A new [Expr] representing the cosineDistance operation. */ + /** + * Calculates the Cosine distance between vector expression and a vector literal. + * + * @param vector1 The first vector (represented as an [Expr]) to compare against. + * @param vector2 The other vector (represented as an [VectorValue]) to compare against. + * @return A new [Expr] representing the cosine distance between the two vectors. + */ @JvmStatic fun cosineDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("cosine_distance", vector1, vector2) - /** @return A new [Expr] representing the cosineDistance operation. */ + /** + * Calculates the Cosine distance between a vector field and a vector expression. + * + * @param vectorFieldName The name of the field containing the first vector. + * @param vector The other vector (represented as an Expr) to compare against. + * @return A new [Expr] representing the cosine distance between the two vectors. + */ @JvmStatic - fun cosineDistance(fieldName: String, vector: Expr): Expr = - FunctionExpr("cosine_distance", fieldName, vector) + fun cosineDistance(vectorFieldName: String, vector: Expr): Expr = + FunctionExpr("cosine_distance", vectorFieldName, vector) - /** @return A new [Expr] representing the cosineDistance operation. */ + /** + * Calculates the Cosine distance between a vector field and a vector literal. + * + * @param vectorFieldName The name of the field containing the first vector. + * @param vector The other vector (as an array of doubles) to compare against. + * @return A new [Expr] representing the cosine distance between the two vectors. + */ @JvmStatic - fun cosineDistance(fieldName: String, vector: DoubleArray): Expr = - FunctionExpr("cosine_distance", fieldName, vector(vector)) + fun cosineDistance(vectorFieldName: String, vector: DoubleArray): Expr = + FunctionExpr("cosine_distance", vectorFieldName, vector(vector)) - /** @return A new [Expr] representing the cosineDistance operation. */ + /** + * Calculates the Cosine distance between a vector field and a vector literal. + * + * @param vectorFieldName The name of the field containing the first vector. + * @param vector The other vector (represented as an [VectorValue]) to compare against. + * @return A new [Expr] representing the cosine distance between the two vectors. + */ @JvmStatic - fun cosineDistance(fieldName: String, vector: VectorValue): Expr = - FunctionExpr("cosine_distance", fieldName, vector) + fun cosineDistance(vectorFieldName: String, vector: VectorValue): Expr = + FunctionExpr("cosine_distance", vectorFieldName, vector) - /** @return A new [Expr] representing the dotProduct operation. */ + /** + * Calculates the dot product distance between two vector expressions. + * + * @param vector1 The first vector (represented as an Expr) to compare against. + * @param vector2 The other vector (represented as an Expr) to compare against. + * @return A new [Expr] representing the dot product distance between the two vectors. + */ @JvmStatic fun dotProduct(vector1: Expr, vector2: Expr): Expr = FunctionExpr("dot_product", vector1, vector2) - /** @return A new [Expr] representing the dotProduct operation. */ + /** + * Calculates the dot product distance between vector expression and a vector literal. + * + * @param vector1 The first vector (represented as an Expr) to compare against. + * @param vector2 The other vector (as an array of doubles) to compare against. + * @return A new [Expr] representing the dot product distance between the two vectors. + */ @JvmStatic fun dotProduct(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("dot_product", vector1, vector(vector2)) - /** @return A new [Expr] representing the dotProduct operation. */ + /** + * Calculates the dot product distance between vector expression and a vector literal. + * + * @param vector1 The first vector (represented as an [Expr]) to compare against. + * @param vector2 The other vector (represented as an [VectorValue]) to compare against. + * @return A new [Expr] representing the dot product distance between the two vectors. + */ @JvmStatic fun dotProduct(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("dot_product", vector1, vector2) - /** @return A new [Expr] representing the dotProduct operation. */ + /** + * Calculates the dot product distance between a vector field and a vector expression. + * + * @param vectorFieldName The name of the field containing the first vector. + * @param vector The other vector (represented as an Expr) to compare against. + * @return A new [Expr] representing the dot product distance between the two vectors. + */ @JvmStatic - fun dotProduct(fieldName: String, vector: Expr): Expr = - FunctionExpr("dot_product", fieldName, vector) + fun dotProduct(vectorFieldName: String, vector: Expr): Expr = + FunctionExpr("dot_product", vectorFieldName, vector) - /** @return A new [Expr] representing the dotProduct operation. */ + /** + * Calculates the dot product distance between vector field and a vector literal. + * + * @param vectorFieldName The name of the field containing the first vector. + * @param vector The other vector (as an array of doubles) to compare against. + * @return A new [Expr] representing the dot product distance between the two vectors. + */ @JvmStatic - fun dotProduct(fieldName: String, vector: DoubleArray): Expr = - FunctionExpr("dot_product", fieldName, vector(vector)) + fun dotProduct(vectorFieldName: String, vector: DoubleArray): Expr = + FunctionExpr("dot_product", vectorFieldName, vector(vector)) - /** @return A new [Expr] representing the dotProduct operation. */ + /** + * Calculates the dot product distance between a vector field and a vector literal. + * + * @param vectorFieldName The name of the field containing the first vector. + * @param vector The other vector (represented as an [VectorValue]) to compare against. + * @return A new [Expr] representing the dot product distance between the two vectors. + */ @JvmStatic - fun dotProduct(fieldName: String, vector: VectorValue): Expr = - FunctionExpr("dot_product", fieldName, vector) + fun dotProduct(vectorFieldName: String, vector: VectorValue): Expr = + FunctionExpr("dot_product", vectorFieldName, vector) - /** @return A new [Expr] representing the euclideanDistance operation. */ + /** + * Calculates the Euclidean distance between two vector expressions. + * + * @param vector1 The first vector (represented as an Expr) to compare against. + * @param vector2 The other vector (represented as an Expr) to compare against. + * @return A new [Expr] representing the Euclidean distance between the two vectors. + */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: Expr): Expr = FunctionExpr("euclidean_distance", vector1, vector2) - /** @return A new [Expr] representing the euclideanDistance operation. */ + /** + * Calculates the Euclidean distance between vector expression and a vector literal. + * + * @param vector1 The first vector (represented as an Expr) to compare against. + * @param vector2 The other vector (as an array of doubles) to compare against. + * @return A new [Expr] representing the Euclidean distance between the two vectors. + */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: DoubleArray): Expr = FunctionExpr("euclidean_distance", vector1, vector(vector2)) - /** @return A new [Expr] representing the not operation. */ + /** + * Calculates the Euclidean distance between vector expression and a vector literal. + * + * @param vector1 The first vector (represented as an [Expr]) to compare against. + * @param vector2 The other vector (represented as an [VectorValue]) to compare against. + * @return A new [Expr] representing the Euclidean distance between the two vectors. + */ @JvmStatic fun euclideanDistance(vector1: Expr, vector2: VectorValue): Expr = FunctionExpr("euclidean_distance", vector1, vector2) - /** @return A new [Expr] representing the euclideanDistance operation. */ + /** + * Calculates the Euclidean distance between a vector field and a vector expression. + * + * @param vectorFieldName The name of the field containing the first vector. + * @param vector The other vector (represented as an Expr) to compare against. + * @return A new [Expr] representing the Euclidean distance between the two vectors. + */ @JvmStatic - fun euclideanDistance(fieldName: String, vector: Expr): Expr = - FunctionExpr("euclidean_distance", fieldName, vector) + fun euclideanDistance(vectorFieldName: String, vector: Expr): Expr = + FunctionExpr("euclidean_distance", vectorFieldName, vector) - /** @return A new [Expr] representing the euclideanDistance operation. */ + /** + * Calculates the Euclidean distance between a vector field and a vector literal. + * + * @param vectorFieldName The name of the field containing the first vector. + * @param vector The other vector (as an array of doubles) to compare against. + * @return A new [Expr] representing the Euclidean distance between the two vectors. + */ @JvmStatic - fun euclideanDistance(fieldName: String, vector: DoubleArray): Expr = - FunctionExpr("euclidean_distance", fieldName, vector(vector)) + fun euclideanDistance(vectorFieldName: String, vector: DoubleArray): Expr = + FunctionExpr("euclidean_distance", vectorFieldName, vector(vector)) - /** @return A new [Expr] representing the euclideanDistance operation. */ + /** + * Calculates the Euclidean distance between a vector field and a vector literal. + * + * @param vectorFieldName The name of the field containing the first vector. + * @param vector The other vector (represented as an [VectorValue]) to compare against. + * @return A new [Expr] representing the Euclidean distance between the two vectors. + */ @JvmStatic - fun euclideanDistance(fieldName: String, vector: VectorValue): Expr = - FunctionExpr("euclidean_distance", fieldName, vector) + fun euclideanDistance(vectorFieldName: String, vector: VectorValue): Expr = + FunctionExpr("euclidean_distance", vectorFieldName, vector) /** @return A new [Expr] representing the vectorLength operation. */ @JvmStatic fun vectorLength(vector: Expr): Expr = FunctionExpr("vector_length", vector) @@ -1515,15 +1669,31 @@ abstract class Expr internal constructor() { fun arrayOffset(arrayFieldName: String, offset: Int): Expr = FunctionExpr("array_offset", arrayFieldName, constant(offset)) - /** @return A new [Expr] representing the cond operation. */ + /** + * Creates a conditional expression that evaluates to a [thenExpr] expression if a condition is + * true or an [elseExpr] expression if the condition is false. + * + * @param condition The condition to evaluate. + * @param thenExpr The expression to evaluate if the condition is true. + * @param elseExpr The expression to evaluate if the condition is false. + * @return A new [Expr] representing the conditional operation. + */ @JvmStatic - fun cond(condition: BooleanExpr, then: Expr, otherwise: Expr): Expr = - FunctionExpr("cond", condition, then, otherwise) + fun cond(condition: BooleanExpr, thenExpr: Expr, elseExpr: Expr): Expr = + FunctionExpr("cond", condition, thenExpr, elseExpr) - /** @return A new [Expr] representing the cond operation. */ + /** + * Creates a conditional expression that evaluates to a [thenValue] if a condition is true or an + * [elseValue] if the condition is false. + * + * @param condition The condition to evaluate. + * @param thenValue Value if the condition is true. + * @param elseValue Value if the condition is false. + * @return A new [Expr] representing the conditional operation. + */ @JvmStatic - fun cond(condition: BooleanExpr, then: Any, otherwise: Any): Expr = - FunctionExpr("cond", condition, then, otherwise) + fun cond(condition: BooleanExpr, thenValue: Any, elseValue: Any): Expr = + FunctionExpr("cond", condition, thenValue, elseValue) /** @return A new [Expr] representing the exists operation. */ @JvmStatic fun exists(expr: Expr) = BooleanExpr("exists", expr) @@ -1663,10 +1833,18 @@ abstract class Expr internal constructor() { fun multiply(other: Any) = Companion.multiply(this, other) /** + * Creates an expression that divides this expression by another expression. + * + * @param other The expression to divide by. + * @return A new [Expr] representing the division operation. */ fun divide(other: Expr) = Companion.divide(this, other) /** + * Creates an expression that divides this expression by a value. + * + * @param other The value to divide by. + * @return A new [Expr] representing the division operation. */ fun divide(other: Any) = Companion.divide(this, other) @@ -1719,12 +1897,19 @@ abstract class Expr internal constructor() { fun replaceAll(find: String, replace: String) = Companion.replaceAll(this, find, replace) /** + * Creates an expression that calculates the character length of this string expression in UTF8. + * + * @return A new [Expr] representing the charLength operation. */ - fun charLength() = Companion.charLength(this) + fun charLength(): Expr = Companion.charLength(this) /** + * Creates an expression that calculates the length of a string in UTF-8 bytes, or just the length + * of a Blob. + * + * @return A new [Expr] representing the length of the string in bytes. */ - fun byteLength() = Companion.byteLength(this) + fun byteLength(): Expr = Companion.byteLength(this) /** */ @@ -1840,34 +2025,66 @@ abstract class Expr internal constructor() { fun mapRemove(key: String) = Companion.mapRemove(this, key) /** + * Calculates the Cosine distance between this and another vector expressions. + * + * @param vector The other vector (represented as an Expr) to compare against. + * @return A new [Expr] representing the cosine distance between the two vectors. */ fun cosineDistance(vector: Expr) = Companion.cosineDistance(this, vector) /** + * Calculates the Cosine distance between this vector expression and a vector literal. + * + * @param vector The other vector (as an array of doubles) to compare against. + * @return A new [Expr] representing the cosine distance between the two vectors. */ fun cosineDistance(vector: DoubleArray) = Companion.cosineDistance(this, vector) /** + * Calculates the Cosine distance between this vector expression and a vector literal. + * + * @param vector The other vector (represented as an [VectorValue]) to compare against. + * @return A new [Expr] representing the cosine distance between the two vectors. */ fun cosineDistance(vector: VectorValue) = Companion.cosineDistance(this, vector) /** + * Calculates the dot product distance between this and another vector expression. + * + * @param vector The other vector (represented as an Expr) to compare against. + * @return A new [Expr] representing the dot product distance between the two vectors. */ fun dotProduct(vector: Expr) = Companion.dotProduct(this, vector) /** + * Calculates the dot product distance between this vector expression and a vector literal. + * + * @param vector The other vector (as an array of doubles) to compare against. + * @return A new [Expr] representing the dot product distance between the two vectors. */ fun dotProduct(vector: DoubleArray) = Companion.dotProduct(this, vector) /** + * Calculates the dot product distance between this vector expression and a vector literal. + * + * @param vector The other vector (represented as an [VectorValue]) to compare against. + * @return A new [Expr] representing the dot product distance between the two vectors. */ fun dotProduct(vector: VectorValue) = Companion.dotProduct(this, vector) /** + * Calculates the Euclidean distance between this and another vector expression. + * + * @param vector The other vector (represented as an Expr) to compare against. + * @return A new [Expr] representing the Euclidean distance between the two vectors. */ fun euclideanDistance(vector: Expr) = Companion.euclideanDistance(this, vector) /** + * Calculates the Euclidean distance between this vector expression and a vector literal. + * + * @param vector The other vector (as an array of doubles) to compare against. + * @return A new [Expr] representing the Euclidean distance between the two vectors. */ fun euclideanDistance(vector: DoubleArray) = Companion.euclideanDistance(this, vector) @@ -2024,20 +2241,44 @@ abstract class Expr internal constructor() { fun arrayOffset(offset: Int) = Companion.arrayOffset(this, offset) /** + * Creates an aggregation that counts the number of stage inputs with valid evaluations of the + * this expression. + * + * @return A new [AggregateFunction] representing the 'count' aggregation. */ - fun sum() = AggregateFunction.sum(this) + fun count(): AggregateFunction = AggregateFunction.count(this) /** + * Creates an aggregation that calculates the sum of this numeric expression across multiple + * stage inputs. + * + * @return A new [AggregateFunction] representing the 'sum' aggregation. */ - fun avg() = AggregateFunction.avg(this) + fun sum(): AggregateFunction = AggregateFunction.sum(this) /** + * Creates an aggregation that calculates the average (mean) of this numeric expression across + * multiple stage inputs. + * + * @return A new [AggregateFunction] representing the 'avg' aggregation. + */ + fun avg(): AggregateFunction = AggregateFunction.avg(this) + + /** + * Creates an aggregation that finds the minimum value of this expression across multiple stage + * inputs. + * + * @return A new [AggregateFunction] representing the 'min' aggregation. */ - fun min() = AggregateFunction.min(this) + fun min(): AggregateFunction = AggregateFunction.min(this) /** + * Creates an aggregation that finds the maximum value of this expression across multiple stage + * inputs. + * + * @return A new [AggregateFunction] representing the 'max' aggregation. */ - fun max() = AggregateFunction.max(this) + fun max(): AggregateFunction = AggregateFunction.max(this) /** * Create an [Ordering] that sorts documents in ascending order based on value of this expression From ef3a8f2745899ee654edb67835d30f7b6123f867 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 29 Apr 2025 17:25:27 -0400 Subject: [PATCH 51/77] Comments --- .../firestore/pipeline/expressions.kt | 660 ++++++++++++++---- 1 file changed, 538 insertions(+), 122 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index eb32b56df5e..e3a97589292 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -694,49 +694,129 @@ abstract class Expr internal constructor() { /** @return A new [Expr] representing the mod operation. */ @JvmStatic fun mod(fieldName: String, other: Any): Expr = FunctionExpr("mod", fieldName, other) - /** @return A new [Expr] representing the eqAny operation. */ + /** + * Creates an expression that checks if an [expression], when evaluated, is equal to any of the + * provided [values]. + * + * @param expression The expression whose results to compare. + * @param values The values to check against. + * @return A new [BooleanExpr] representing the 'IN' comparison. + */ + @JvmStatic + fun eqAny(expression: Expr, values: List): BooleanExpr = + eqAny(expression, ListOfExprs(toArrayOfExprOrConstant(values))) + + /** + * Creates an expression that checks if an [expression], when evaluated, is equal to any of the + * elements of [arrayExpression]. + * + * @param expression The expression whose results to compare. + * @param arrayExpression An expression that evaluates to an array, whose elements to check for + * equality to the input. + * @return A new [BooleanExpr] representing the 'IN' comparison. + */ + @JvmStatic + fun eqAny(expression: Expr, arrayExpression: Expr): BooleanExpr = + BooleanExpr("eq_any", expression, arrayExpression) + + /** + * Creates an expression that checks if a field's value is equal to any of the provided [values] + * . + * + * @param fieldName The field to compare. + * @param values The values to check against. + * @return A new [BooleanExpr] representing the 'IN' comparison. + */ @JvmStatic - fun eqAny(value: Expr, values: List) = - BooleanExpr("eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) + fun eqAny(fieldName: String, values: List): BooleanExpr = + eqAny(fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) - /** @return A new [Expr] representing the eqAny operation. */ + /** + * Creates an expression that checks if a field's value is equal to any of the elements of + * [arrayExpression]. + * + * @param fieldName The field to compare. + * @param arrayExpression An expression that evaluates to an array, whose elements to check for + * equality to the input. + * @return A new [BooleanExpr] representing the 'IN' comparison. + */ @JvmStatic - fun eqAny(fieldName: String, values: List) = - BooleanExpr("eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + fun eqAny(fieldName: String, arrayExpression: Expr): BooleanExpr = + BooleanExpr("eq_any", fieldName, arrayExpression) - /** @return A new [Expr] representing the notEqAny operation. */ + /** + * Creates an expression that checks if an [expression], when evaluated, is not equal to all the + * provided [values]. + * + * @param expression The expression whose results to compare. + * @param values The values to check against. + * @return A new [BooleanExpr] representing the 'NOT IN' comparison. + */ @JvmStatic - fun notEqAny(value: Expr, values: List) = - BooleanExpr("not_eq_any", value, ListOfExprs(toArrayOfExprOrConstant(values))) + fun notEqAny(expression: Expr, values: List): BooleanExpr = + notEqAny(expression, ListOfExprs(toArrayOfExprOrConstant(values))) - /** @return A new [Expr] representing the notEqAny operation. */ + /** + * Creates an expression that checks if an [expression], when evaluated, is not equal to all the + * elements of [arrayExpression]. + * + * @param expression The expression whose results to compare. + * @param arrayExpression An expression that evaluates to an array, whose elements to check for + * equality to the input. + * @return A new [BooleanExpr] representing the 'NOT IN' comparison. + */ @JvmStatic - fun notEqAny(fieldName: String, values: List) = - BooleanExpr("not_eq_any", fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + fun notEqAny(expression: Expr, arrayExpression: Expr): BooleanExpr = + BooleanExpr("not_eq_any", expression, arrayExpression) + + /** + * Creates an expression that checks if a field's value is not equal to all of the provided + * [values]. + * + * @param fieldName The field to compare. + * @param values The values to check against. + * @return A new [BooleanExpr] representing the 'NOT IN' comparison. + */ + @JvmStatic + fun notEqAny(fieldName: String, values: List): BooleanExpr = + notEqAny(fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + + /** + * Creates an expression that checks if a field's value is not equal to all of the elements of + * [arrayExpression]. + * + * @param fieldName The field to compare. + * @param arrayExpression An expression that evaluates to an array, whose elements to check for + * equality to the input. + * @return A new [BooleanExpr] representing the 'NOT IN' comparison. + */ + @JvmStatic + fun notEqAny(fieldName: String, arrayExpression: Expr): BooleanExpr = + BooleanExpr("not_eq_any", fieldName, arrayExpression) /** @return A new [Expr] representing the isNan operation. */ - @JvmStatic fun isNan(expr: Expr) = BooleanExpr("is_nan", expr) + @JvmStatic fun isNan(expr: Expr): BooleanExpr = BooleanExpr("is_nan", expr) /** @return A new [Expr] representing the isNan operation. */ - @JvmStatic fun isNan(fieldName: String) = BooleanExpr("is_nan", fieldName) + @JvmStatic fun isNan(fieldName: String): BooleanExpr = BooleanExpr("is_nan", fieldName) /** @return A new [Expr] representing the isNotNan operation. */ - @JvmStatic fun isNotNan(expr: Expr) = BooleanExpr("is_not_nan", expr) + @JvmStatic fun isNotNan(expr: Expr): BooleanExpr = BooleanExpr("is_not_nan", expr) /** @return A new [Expr] representing the isNotNan operation. */ - @JvmStatic fun isNotNan(fieldName: String) = BooleanExpr("is_not_nan", fieldName) + @JvmStatic fun isNotNan(fieldName: String): BooleanExpr = BooleanExpr("is_not_nan", fieldName) /** @return A new [Expr] representing the isNull operation. */ - @JvmStatic fun isNull(expr: Expr) = BooleanExpr("is_null", expr) + @JvmStatic fun isNull(expr: Expr): BooleanExpr = BooleanExpr("is_null", expr) /** @return A new [Expr] representing the isNull operation. */ - @JvmStatic fun isNull(fieldName: String) = BooleanExpr("is_null", fieldName) + @JvmStatic fun isNull(fieldName: String): BooleanExpr = BooleanExpr("is_null", fieldName) /** @return A new [Expr] representing the isNotNull operation. */ - @JvmStatic fun isNotNull(expr: Expr) = BooleanExpr("is_not_null", expr) + @JvmStatic fun isNotNull(expr: Expr): BooleanExpr = BooleanExpr("is_not_null", expr) /** @return A new [Expr] representing the isNotNull operation. */ - @JvmStatic fun isNotNull(fieldName: String) = BooleanExpr("is_not_null", fieldName) + @JvmStatic fun isNotNull(fieldName: String): BooleanExpr = BooleanExpr("is_not_null", fieldName) /** @return A new [Expr] representing the replaceFirst operation. */ @JvmStatic @@ -803,25 +883,31 @@ abstract class Expr internal constructor() { @JvmStatic fun byteLength(fieldName: String): Expr = FunctionExpr("byte_length", fieldName) /** @return A new [Expr] representing the like operation. */ - @JvmStatic fun like(expr: Expr, pattern: Expr) = BooleanExpr("like", expr, pattern) + @JvmStatic fun like(expr: Expr, pattern: Expr): BooleanExpr = BooleanExpr("like", expr, pattern) /** @return A new [Expr] representing the like operation. */ - @JvmStatic fun like(expr: Expr, pattern: String) = BooleanExpr("like", expr, pattern) + @JvmStatic + fun like(expr: Expr, pattern: String): BooleanExpr = BooleanExpr("like", expr, pattern) /** @return A new [Expr] representing the like operation. */ - @JvmStatic fun like(fieldName: String, pattern: Expr) = BooleanExpr("like", fieldName, pattern) + @JvmStatic + fun like(fieldName: String, pattern: Expr): BooleanExpr = + BooleanExpr("like", fieldName, pattern) /** @return A new [Expr] representing the like operation. */ @JvmStatic - fun like(fieldName: String, pattern: String) = BooleanExpr("like", fieldName, pattern) + fun like(fieldName: String, pattern: String): BooleanExpr = + BooleanExpr("like", fieldName, pattern) /** @return A new [Expr] representing the regexContains operation. */ @JvmStatic - fun regexContains(expr: Expr, pattern: Expr) = BooleanExpr("regex_contains", expr, pattern) + fun regexContains(expr: Expr, pattern: Expr): BooleanExpr = + BooleanExpr("regex_contains", expr, pattern) /** @return A new [Expr] representing the regexContains operation. */ @JvmStatic - fun regexContains(expr: Expr, pattern: String) = BooleanExpr("regex_contains", expr, pattern) + fun regexContains(expr: Expr, pattern: String): BooleanExpr = + BooleanExpr("regex_contains", expr, pattern) /** @return A new [Expr] representing the regexContains operation. */ @JvmStatic @@ -834,11 +920,14 @@ abstract class Expr internal constructor() { BooleanExpr("regex_contains", fieldName, pattern) /** @return A new [Expr] representing the regexMatch operation. */ - @JvmStatic fun regexMatch(expr: Expr, pattern: Expr) = BooleanExpr("regex_match", expr, pattern) + @JvmStatic + fun regexMatch(expr: Expr, pattern: Expr): BooleanExpr = + BooleanExpr("regex_match", expr, pattern) /** @return A new [Expr] representing the regexMatch operation. */ @JvmStatic - fun regexMatch(expr: Expr, pattern: String) = BooleanExpr("regex_match", expr, pattern) + fun regexMatch(expr: Expr, pattern: String): BooleanExpr = + BooleanExpr("regex_match", expr, pattern) /** @return A new [Expr] representing the regexMatch operation. */ @JvmStatic @@ -894,50 +983,111 @@ abstract class Expr internal constructor() { /** @return A new [Expr] representing the strContains operation. */ @JvmStatic - fun strContains(expr: Expr, substring: Expr) = BooleanExpr("str_contains", expr, substring) + fun strContains(expr: Expr, substring: Expr): BooleanExpr = + BooleanExpr("str_contains", expr, substring) /** @return A new [Expr] representing the strContains operation. */ @JvmStatic - fun strContains(expr: Expr, substring: String) = BooleanExpr("str_contains", expr, substring) + fun strContains(expr: Expr, substring: String): BooleanExpr = + BooleanExpr("str_contains", expr, substring) - /** @return A new [Expr] representing the strContains operation. */ + /** @return A new [BooleanExpr] representing the strContains operation. */ @JvmStatic - fun strContains(fieldName: String, substring: Expr) = + fun strContains(fieldName: String, substring: Expr): BooleanExpr = BooleanExpr("str_contains", fieldName, substring) - /** @return A new [Expr] representing the strContains operation. */ + /** @return A new [BooleanExpr] representing the strContains operation. */ @JvmStatic - fun strContains(fieldName: String, substring: String) = + fun strContains(fieldName: String, substring: String): BooleanExpr = BooleanExpr("str_contains", fieldName, substring) - /** @return A new [Expr] representing the startsWith operation. */ - @JvmStatic fun startsWith(expr: Expr, prefix: Expr) = BooleanExpr("starts_with", expr, prefix) + /** + * Creates an expression that checks if a string expression starts with a given [prefix]. + * + * @param stringExpr The expression to check. + * @param prefix The prefix string expression to check for. + * @return A new [BooleanExpr] representing the 'starts with' comparison. + */ + @JvmStatic + fun startsWith(stringExpr: Expr, prefix: Expr): BooleanExpr = + BooleanExpr("starts_with", stringExpr, prefix) - /** @return A new [Expr] representing the startsWith operation. */ - @JvmStatic fun startsWith(expr: Expr, prefix: String) = BooleanExpr("starts_with", expr, prefix) + /** + * Creates an expression that checks if a string expression starts with a given [prefix]. + * + * @param stringExpr The expression to check. + * @param prefix The prefix string to check for. + * @return A new [BooleanExpr] representing the 'starts with' comparison. + */ + @JvmStatic + fun startsWith(stringExpr: Expr, prefix: String): BooleanExpr = + BooleanExpr("starts_with", stringExpr, prefix) - /** @return A new [Expr] representing the startsWith operation. */ + /** + * Creates an expression that checks if a string expression starts with a given [prefix]. + * + * @param fieldName The name of field that contains a string to check. + * @param prefix The prefix string expression to check for. + * @return A new [BooleanExpr] representing the 'starts with' comparison. + */ @JvmStatic - fun startsWith(fieldName: String, prefix: Expr) = BooleanExpr("starts_with", fieldName, prefix) + fun startsWith(fieldName: String, prefix: Expr): BooleanExpr = + BooleanExpr("starts_with", fieldName, prefix) - /** @return A new [Expr] representing the startsWith operation. */ + /** + * Creates an expression that checks if a string expression starts with a given [prefix]. + * + * @param fieldName The name of field that contains a string to check. + * @param prefix The prefix string to check for. + * @return A new [BooleanExpr] representing the 'starts with' comparison. + */ @JvmStatic - fun startsWith(fieldName: String, prefix: String) = + fun startsWith(fieldName: String, prefix: String): BooleanExpr = BooleanExpr("starts_with", fieldName, prefix) - /** @return A new [Expr] representing the endsWith operation. */ - @JvmStatic fun endsWith(expr: Expr, suffix: Expr) = BooleanExpr("ends_with", expr, suffix) + /** + * Creates an expression that checks if a string expression ends with a given [suffix]. + * + * @param stringExpr The expression to check. + * @param suffix The suffix string expression to check for. + * @return A new [BooleanExpr] representing the 'ends with' comparison. + */ + @JvmStatic + fun endsWith(stringExpr: Expr, suffix: Expr): BooleanExpr = + BooleanExpr("ends_with", stringExpr, suffix) - /** @return A new [Expr] representing the endsWith operation. */ - @JvmStatic fun endsWith(expr: Expr, suffix: String) = BooleanExpr("ends_with", expr, suffix) + /** + * Creates an expression that checks if a string expression ends with a given [suffix]. + * + * @param stringExpr The expression to check. + * @param suffix The suffix string to check for. + * @return A new [BooleanExpr] representing the 'ends with' comparison. + */ + @JvmStatic + fun endsWith(stringExpr: Expr, suffix: String): BooleanExpr = + BooleanExpr("ends_with", stringExpr, suffix) - /** @return A new [Expr] representing the endsWith operation. */ + /** + * Creates an expression that checks if a string expression ends with a given [suffix]. + * + * @param fieldName The name of field that contains a string to check. + * @param suffix The suffix string expression to check for. + * @return A new [BooleanExpr] representing the 'ends with' comparison. + */ @JvmStatic - fun endsWith(fieldName: String, suffix: Expr) = BooleanExpr("ends_with", fieldName, suffix) + fun endsWith(fieldName: String, suffix: Expr): BooleanExpr = + BooleanExpr("ends_with", fieldName, suffix) - /** @return A new [Expr] representing the endsWith operation. */ + /** + * Creates an expression that checks if a string expression ends with a given [suffix]. + * + * @param fieldName The name of field that contains a string to check. + * @param suffix The suffix string to check for. + * @return A new [BooleanExpr] representing the 'ends with' comparison. + */ @JvmStatic - fun endsWith(fieldName: String, suffix: String) = BooleanExpr("ends_with", fieldName, suffix) + fun endsWith(fieldName: String, suffix: String): BooleanExpr = + BooleanExpr("ends_with", fieldName, suffix) /** @return A new [Expr] representing the toLower operation. */ @JvmStatic fun toLower(expr: Expr): Expr = FunctionExpr("to_lower", expr) @@ -1326,77 +1476,244 @@ abstract class Expr internal constructor() { fun timestampSub(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) - /** @return A new [Expr] representing the eq operation. */ - @JvmStatic fun eq(left: Expr, right: Expr) = BooleanExpr("eq", left, right) + /** + * Creates an expression that checks if two expressions are equal. + * + * @param left The first expression to compare. + * @param right The second expression to compare to. + * @return A new [BooleanExpr] representing the equality comparison. + */ + @JvmStatic fun eq(left: Expr, right: Expr): BooleanExpr = BooleanExpr("eq", left, right) - /** @return A new [Expr] representing the eq operation. */ - @JvmStatic fun eq(left: Expr, right: Any) = BooleanExpr("eq", left, right) + /** + * Creates an expression that checks if an expression is equal to a value. + * + * @param left The first expression to compare. + * @param right The value to compare to. + * @return A new [BooleanExpr] representing the equality comparison. + */ + @JvmStatic fun eq(left: Expr, right: Any): BooleanExpr = BooleanExpr("eq", left, right) - /** @return A new [Expr] representing the eq operation. */ - @JvmStatic fun eq(fieldName: String, right: Expr) = BooleanExpr("eq", fieldName, right) + /** + * Creates an expression that checks if a field's value is equal to an expression. + * + * @param fieldName The field name to compare. + * @param expression The expression to compare to. + * @return A new [BooleanExpr] representing the equality comparison. + */ + @JvmStatic + fun eq(fieldName: String, expression: Expr): BooleanExpr = + BooleanExpr("eq", fieldName, expression) - /** @return A new [Expr] representing the eq operation. */ - @JvmStatic fun eq(fieldName: String, right: Any) = BooleanExpr("eq", fieldName, right) + /** + * Creates an expression that checks if a field's value is equal to another value. + * + * @param fieldName The field name to compare. + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the equality comparison. + */ + @JvmStatic + fun eq(fieldName: String, value: Any): BooleanExpr = BooleanExpr("eq", fieldName, value) - /** @return A new [Expr] representing the neq operation. */ - @JvmStatic fun neq(left: Expr, right: Expr) = BooleanExpr("neq", left, right) + /** + * Creates an expression that checks if two expressions are not equal. + * + * @param left The first expression to compare. + * @param right The second expression to compare to. + * @return A new [BooleanExpr] representing the inequality comparison. + */ + @JvmStatic fun neq(left: Expr, right: Expr): BooleanExpr = BooleanExpr("neq", left, right) - /** @return A new [Expr] representing the neq operation. */ - @JvmStatic fun neq(left: Expr, right: Any) = BooleanExpr("neq", left, right) + /** + * Creates an expression that checks if an expression is not equal to a value. + * + * @param left The first expression to compare. + * @param right The value to compare to. + * @return A new [BooleanExpr] representing the inequality comparison. + */ + @JvmStatic fun neq(left: Expr, right: Any): BooleanExpr = BooleanExpr("neq", left, right) - /** @return A new [Expr] representing the neq operation. */ - @JvmStatic fun neq(fieldName: String, right: Expr) = BooleanExpr("neq", fieldName, right) + /** + * Creates an expression that checks if a field's value is not equal to an expression. + * + * @param fieldName The field name to compare. + * @param expression The expression to compare to. + * @return A new [BooleanExpr] representing the inequality comparison. + */ + @JvmStatic + fun neq(fieldName: String, expression: Expr): BooleanExpr = + BooleanExpr("neq", fieldName, expression) - /** @return A new [Expr] representing the neq operation. */ - @JvmStatic fun neq(fieldName: String, right: Any) = BooleanExpr("neq", fieldName, right) + /** + * Creates an expression that checks if a field's value is not equal to another value. + * + * @param fieldName The field name to compare. + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the inequality comparison. + */ + @JvmStatic + fun neq(fieldName: String, value: Any): BooleanExpr = BooleanExpr("neq", fieldName, value) - /** @return A new [Expr] representing the gt operation. */ - @JvmStatic fun gt(left: Expr, right: Expr) = BooleanExpr("gt", left, right) + /** + * Creates an expression that checks if the first expression is greater than the second + * expression. + * + * @param left The first expression to compare. + * @param right The second expression to compare to. + * @return A new [BooleanExpr] representing the greater than comparison. + */ + @JvmStatic fun gt(left: Expr, right: Expr): BooleanExpr = BooleanExpr("gt", left, right) - /** @return A new [Expr] representing the gt operation. */ - @JvmStatic fun gt(left: Expr, right: Any) = BooleanExpr("gt", left, right) + /** + * Creates an expression that checks if an expression is greater than a value. + * + * @param left The first expression to compare. + * @param right The value to compare to. + * @return A new [BooleanExpr] representing the greater than comparison. + */ + @JvmStatic fun gt(left: Expr, right: Any): BooleanExpr = BooleanExpr("gt", left, right) - /** @return A new [Expr] representing the gt operation. */ - @JvmStatic fun gt(fieldName: String, right: Expr) = BooleanExpr("gt", fieldName, right) + /** + * Creates an expression that checks if a field's value is greater than an expression. + * + * @param fieldName The field name to compare. + * @param expression The expression to compare to. + * @return A new [BooleanExpr] representing the greater than comparison. + */ + @JvmStatic + fun gt(fieldName: String, expression: Expr): BooleanExpr = + BooleanExpr("gt", fieldName, expression) - /** @return A new [Expr] representing the gt operation. */ - @JvmStatic fun gt(fieldName: String, right: Any) = BooleanExpr("gt", fieldName, right) + /** + * Creates an expression that checks if a field's value is greater than another value. + * + * @param fieldName The field name to compare. + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the greater than comparison. + */ + @JvmStatic + fun gt(fieldName: String, value: Any): BooleanExpr = BooleanExpr("gt", fieldName, value) - /** @return A new [Expr] representing the gte operation. */ - @JvmStatic fun gte(left: Expr, right: Expr) = BooleanExpr("gte", left, right) + /** + * Creates an expression that checks if the first expression is greater than or equal to the + * second expression. + * + * @param left The first expression to compare. + * @param right The second expression to compare to. + * @return A new [BooleanExpr] representing the greater than or equal to comparison. + */ + @JvmStatic fun gte(left: Expr, right: Expr): BooleanExpr = BooleanExpr("gte", left, right) - /** @return A new [Expr] representing the gte operation. */ - @JvmStatic fun gte(left: Expr, right: Any) = BooleanExpr("gte", left, right) + /** + * Creates an expression that checks if an expression is greater than or equal to a value. + * + * @param left The first expression to compare. + * @param right The value to compare to. + * @return A new [BooleanExpr] representing the greater than or equal to comparison. + */ + @JvmStatic fun gte(left: Expr, right: Any): BooleanExpr = BooleanExpr("gte", left, right) - /** @return A new [Expr] representing the gte operation. */ - @JvmStatic fun gte(fieldName: String, right: Expr) = BooleanExpr("gte", fieldName, right) + /** + * Creates an expression that checks if a field's value is greater than or equal to an + * expression. + * + * @param fieldName The field name to compare. + * @param expression The expression to compare to. + * @return A new [BooleanExpr] representing the greater than or equal to comparison. + */ + @JvmStatic + fun gte(fieldName: String, expression: Expr): BooleanExpr = + BooleanExpr("gte", fieldName, expression) - /** @return A new [Expr] representing the gte operation. */ - @JvmStatic fun gte(fieldName: String, right: Any) = BooleanExpr("gte", fieldName, right) + /** + * Creates an expression that checks if a field's value is greater than or equal to another + * value. + * + * @param fieldName The field name to compare. + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the greater than or equal to comparison. + */ + @JvmStatic + fun gte(fieldName: String, value: Any): BooleanExpr = BooleanExpr("gte", fieldName, value) - /** @return A new [Expr] representing the lt operation. */ - @JvmStatic fun lt(left: Expr, right: Expr) = BooleanExpr("lt", left, right) + /** + * Creates an expression that checks if the first expression is less than the second expression. + * + * @param left The first expression to compare. + * @param right The second expression to compare to. + * @return A new [BooleanExpr] representing the less than comparison. + */ + @JvmStatic fun lt(left: Expr, right: Expr): BooleanExpr = BooleanExpr("lt", left, right) - /** @return A new [Expr] representing the lt operation. */ - @JvmStatic fun lt(left: Expr, right: Any) = BooleanExpr("lt", left, right) + /** + * Creates an expression that checks if an expression is less than a value. + * + * @param left The first expression to compare. + * @param right The value to compare to. + * @return A new [BooleanExpr] representing the less than comparison. + */ + @JvmStatic fun lt(left: Expr, right: Any): BooleanExpr = BooleanExpr("lt", left, right) - /** @return A new [Expr] representing the lt operation. */ - @JvmStatic fun lt(fieldName: String, right: Expr) = BooleanExpr("lt", fieldName, right) + /** + * Creates an expression that checks if a field's value is less than an expression. + * + * @param fieldName The field name to compare. + * @param expression The expression to compare to. + * @return A new [BooleanExpr] representing the less than comparison. + */ + @JvmStatic + fun lt(fieldName: String, expression: Expr): BooleanExpr = + BooleanExpr("lt", fieldName, expression) - /** @return A new [Expr] representing the lt operation. */ - @JvmStatic fun lt(fieldName: String, right: Any) = BooleanExpr("lt", fieldName, right) + /** + * Creates an expression that checks if a field's value is less than another value. + * + * @param fieldName The field name to compare. + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the less than comparison. + */ + @JvmStatic + fun lt(fieldName: String, right: Any): BooleanExpr = BooleanExpr("lt", fieldName, right) - /** @return A new [Expr] representing the lte operation. */ - @JvmStatic fun lte(left: Expr, right: Expr) = BooleanExpr("lte", left, right) + /** + * Creates an expression that checks if the first expression is less than or equal to the second + * expression. + * + * @param left The first expression to compare. + * @param right The second expression to compare to. + * @return A new [BooleanExpr] representing the less than or equal to comparison. + */ + @JvmStatic fun lte(left: Expr, right: Expr): BooleanExpr = BooleanExpr("lte", left, right) - /** @return A new [Expr] representing the lte operation. */ - @JvmStatic fun lte(left: Expr, right: Any) = BooleanExpr("lte", left, right) + /** + * Creates an expression that checks if an expression is less than or equal to a value. + * + * @param left The first expression to compare. + * @param right The value to compare to. + * @return A new [BooleanExpr] representing the less than or equal to comparison. + */ + @JvmStatic fun lte(left: Expr, right: Any): BooleanExpr = BooleanExpr("lte", left, right) - /** @return A new [Expr] representing the lte operation. */ - @JvmStatic fun lte(fieldName: String, right: Expr) = BooleanExpr("lte", fieldName, right) + /** + * Creates an expression that checks if a field's value is less than or equal to an expression. + * + * @param fieldName The field name to compare. + * @param expression The expression to compare to. + * @return A new [BooleanExpr] representing the less than or equal to comparison. + */ + @JvmStatic + fun lte(fieldName: String, expression: Expr): BooleanExpr = + BooleanExpr("lte", fieldName, expression) - /** @return A new [Expr] representing the lte operation. */ - @JvmStatic fun lte(fieldName: String, right: Any) = BooleanExpr("lte", fieldName, right) + /** + * Creates an expression that checks if a field's value is less than or equal to another value. + * + * @param fieldName The field name to compare. + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the less than or equal to comparison. + */ + @JvmStatic + fun lte(fieldName: String, value: Any): BooleanExpr = BooleanExpr("lte", fieldName, value) /** * Creates an expression that concatenates an array with other arrays. @@ -1471,7 +1788,8 @@ abstract class Expr internal constructor() { * @return A new [BooleanExpr] representing the arrayContains operation. */ @JvmStatic - fun arrayContains(array: Expr, element: Expr) = BooleanExpr("array_contains", array, element) + fun arrayContains(array: Expr, element: Expr): BooleanExpr = + BooleanExpr("array_contains", array, element) /** * Creates an expression that checks if the array field contains a specific [element]. @@ -1492,7 +1810,8 @@ abstract class Expr internal constructor() { * @return A new [BooleanExpr] representing the arrayContains operation. */ @JvmStatic - fun arrayContains(array: Expr, element: Any) = BooleanExpr("array_contains", array, element) + fun arrayContains(array: Expr, element: Any): BooleanExpr = + BooleanExpr("array_contains", array, element) /** * Creates an expression that checks if the array field contains a specific [element]. @@ -1696,7 +2015,31 @@ abstract class Expr internal constructor() { FunctionExpr("cond", condition, thenValue, elseValue) /** @return A new [Expr] representing the exists operation. */ - @JvmStatic fun exists(expr: Expr) = BooleanExpr("exists", expr) + @JvmStatic fun exists(expr: Expr): BooleanExpr = BooleanExpr("exists", expr) + + /** + * Creates an expression that returns the document ID from a path. + * + * @param documentPath An expression the evaluates to document path. + * @return A new [Expr] representing the documentId operation. + */ + @JvmStatic fun documentId(documentPath: Expr): Expr = FunctionExpr("document_id", documentPath) + + /** + * Creates an expression that returns the document ID from a path. + * + * @param documentPath The string representation of the document path. + * @return A new [Expr] representing the documentId operation. + */ + @JvmStatic fun documentId(documentPath: String): Expr = documentId(constant(documentPath)) + + /** + * Creates an expression that returns the document ID from a [DocumentReference]. + * + * @param docRef The [DocumentReference]. + * @return A new [Expr] representing the documentId operation. + */ + @JvmStatic fun documentId(docRef: DocumentReference): Expr = documentId(constant(docRef)) } /** @@ -1798,6 +2141,13 @@ abstract class Expr internal constructor() { */ open fun alias(alias: String) = ExprWithAlias(alias, this) + /** + * Creates an expression that returns the document ID from this path expression. + * + * @return A new [Expr] representing the documentId operation. + */ + fun documentId(): Expr = Companion.documentId(this) + /** * Creates an expression that adds this expression to another expression. * @@ -1957,25 +2307,41 @@ abstract class Expr internal constructor() { /** */ - fun strContains(substring: Expr) = Companion.strContains(this, substring) + fun strContains(substring: Expr): BooleanExpr = Companion.strContains(this, substring) /** */ - fun strContains(substring: String) = Companion.strContains(this, substring) + fun strContains(substring: String): BooleanExpr = Companion.strContains(this, substring) /** + * Creates an expression that checks if this string expression starts with a given [prefix]. + * + * @param prefix The prefix string expression to check for. + * @return A new [Expr] representing the the 'starts with' comparison. */ - fun startsWith(prefix: Expr) = Companion.startsWith(this, prefix) + fun startsWith(prefix: Expr): BooleanExpr = Companion.startsWith(this, prefix) /** + * Creates an expression that checks if this string expression starts with a given [prefix]. + * + * @param prefix The prefix string expression to check for. + * @return A new [Expr] representing the 'starts with' comparison. */ - fun startsWith(prefix: String) = Companion.startsWith(this, prefix) + fun startsWith(prefix: String): BooleanExpr = Companion.startsWith(this, prefix) /** + * Creates an expression that checks if this string expression ends with a given [suffix]. + * + * @param suffix The suffix string expression to check for. + * @return A new [Expr] representing the 'ends with' comparison. */ - fun endsWith(suffix: Expr) = Companion.endsWith(this, suffix) + fun endsWith(suffix: Expr): BooleanExpr = Companion.endsWith(this, suffix) /** + * Creates an expression that checks if this string expression ends with a given [suffix]. + * + * @param suffix The suffix string to check for. + * @return A new [Expr] representing the the 'ends with' comparison. */ fun endsWith(suffix: String) = Companion.endsWith(this, suffix) @@ -2249,8 +2615,8 @@ abstract class Expr internal constructor() { fun count(): AggregateFunction = AggregateFunction.count(this) /** - * Creates an aggregation that calculates the sum of this numeric expression across multiple - * stage inputs. + * Creates an aggregation that calculates the sum of this numeric expression across multiple stage + * inputs. * * @return A new [AggregateFunction] representing the 'sum' aggregation. */ @@ -2295,56 +2661,106 @@ abstract class Expr internal constructor() { fun descending(): Ordering = Ordering.descending(this) /** + * Creates an expression that checks if this and [other] expression are equal. + * + * @param other The expression to compare to. + * @return A new [BooleanExpr] representing the equality comparison. */ - fun eq(other: Expr) = Companion.eq(this, other) + fun eq(other: Expr): BooleanExpr = Companion.eq(this, other) /** + * Creates an expression that checks if this expression is equal to a [value]. + * + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the equality comparison. */ - fun eq(other: Any) = Companion.eq(this, other) + fun eq(value: Any): BooleanExpr = Companion.eq(this, value) /** + * Creates an expression that checks if this expressions is not equal to the [other] expression. + * + * @param other The expression to compare to. + * @return A new [BooleanExpr] representing the inequality comparison. */ - fun neq(other: Expr) = Companion.neq(this, other) + fun neq(other: Expr): BooleanExpr = Companion.neq(this, other) /** + * Creates an expression that checks if this expression is not equal to a [value]. + * + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the inequality comparison. */ - fun neq(other: Any) = Companion.neq(this, other) + fun neq(value: Any): BooleanExpr = Companion.neq(this, value) /** + * Creates an expression that checks if this expression is greater than the [other] expression. + * + * @param other The expression to compare to. + * @return A new [BooleanExpr] representing the greater than comparison. */ - fun gt(other: Expr) = Companion.gt(this, other) + fun gt(other: Expr): BooleanExpr = Companion.gt(this, other) /** + * Creates an expression that checks if this expression is greater than a [value]. + * + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the greater than comparison. */ - fun gt(other: Any) = Companion.gt(this, other) + fun gt(value: Any): BooleanExpr = Companion.gt(this, value) /** + * Creates an expression that checks if this expression is greater than or equal to the [other] + * expression. + * + * @param other The expression to compare to. + * @return A new [BooleanExpr] representing the greater than or equal to comparison. */ - fun gte(other: Expr) = Companion.gte(this, other) + fun gte(other: Expr): BooleanExpr = Companion.gte(this, other) /** + * Creates an expression that checks if this expression is greater than or equal to a [value]. + * + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the greater than or equal to comparison. */ - fun gte(other: Any) = Companion.gte(this, other) + fun gte(value: Any): BooleanExpr = Companion.gte(this, value) /** + * Creates an expression that checks if this expression is less than the [other] expression. + * + * @param other The expression to compare to. + * @return A new [BooleanExpr] representing the less than comparison. */ - fun lt(other: Expr) = Companion.lt(this, other) + fun lt(other: Expr): BooleanExpr = Companion.lt(this, other) /** + * Creates an expression that checks if this expression is less than a value. + * + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the less than comparison. */ - fun lt(other: Any) = Companion.lt(this, other) + fun lt(value: Any): BooleanExpr = Companion.lt(this, value) /** + * Creates an expression that checks if this expression is less than or equal to the [other] + * expression. + * + * @param other The expression to compare to. + * @return A new [BooleanExpr] representing the less than or equal to comparison. */ - fun lte(other: Expr) = Companion.lte(this, other) + fun lte(other: Expr): BooleanExpr = Companion.lte(this, other) /** + * Creates an expression that checks if this expression is less than or equal to a [value]. + * + * @param value The value to compare to. + * @return A new [BooleanExpr] representing the less than or equal to comparison. */ - fun lte(other: Any) = Companion.lte(this, other) + fun lte(value: Any): BooleanExpr = Companion.lte(this, value) /** */ - fun exists() = Companion.exists(this) + fun exists(): BooleanExpr = Companion.exists(this) internal abstract fun toProto(userDataReader: UserDataReader): Value } @@ -2472,7 +2888,7 @@ open class BooleanExpr internal constructor(name: String, params: Array Date: Wed, 30 Apr 2025 11:00:15 -0400 Subject: [PATCH 52/77] More expression work --- .../firestore/pipeline/expressions.kt | 116 +++++++++++++++++- 1 file changed, 111 insertions(+), 5 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index e3a97589292..74f854a8926 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -2014,8 +2014,45 @@ abstract class Expr internal constructor() { fun cond(condition: BooleanExpr, thenValue: Any, elseValue: Any): Expr = FunctionExpr("cond", condition, thenValue, elseValue) - /** @return A new [Expr] representing the exists operation. */ - @JvmStatic fun exists(expr: Expr): BooleanExpr = BooleanExpr("exists", expr) + /** + * Creates an expression that checks if a field exists. + * + * @param value An expression evaluates to the name of the field to check. + * @return A new [Expr] representing the exists check. + */ + @JvmStatic fun exists(value: Expr): BooleanExpr = BooleanExpr("exists", value) + + /** + * Creates an expression that checks if a field exists. + * + * @param fieldName The field name to check. + * @return A new [Expr] representing the exists check. + */ + @JvmStatic fun exists(fieldName: String): BooleanExpr = BooleanExpr("exists", fieldName) + + /** + * Creates an expression that returns the [catchExpr] argument if there is an + * error, else return the result of the [tryExpr] argument evaluation. + * + * @param tryExpr The try expression. + * @param catchExpr The catch expression that will be evaluated and + * returned if the [tryExpr] produces an error. + * @return A new [Expr] representing the ifError operation. + */ + @JvmStatic + fun ifError(tryExpr: Expr, catchExpr: Expr): Expr = FunctionExpr("if_error", tryExpr, catchExpr) + + /** + * Creates an expression that returns the [catchValue] argument if there is an + * error, else return the result of the [tryExpr] argument evaluation. + * + * @param tryExpr The try expression. + * @param catchValue The value that will be returned if the [tryExpr] produces an error. + * @return A new [Expr] representing the ifError operation. + */ + @JvmStatic + fun ifError(tryExpr: Expr, catchValue: Any): Expr = + FunctionExpr("if_error", tryExpr, catchValue) /** * Creates an expression that returns the document ID from a path. @@ -2207,13 +2244,43 @@ abstract class Expr internal constructor() { fun mod(other: Any) = Companion.mod(this, other) /** + * Creates an expression that checks if this expression, when evaluated, is equal to any of the + * provided [values]. + * + * @param values The values to check against. + * @return A new [BooleanExpr] representing the 'IN' comparison. */ fun eqAny(values: List) = Companion.eqAny(this, values) /** + * Creates an expression that checks if this expression, when evaluated, is equal to any of the + * elements of [arrayExpression]. + * + * @param arrayExpression An expression that evaluates to an array, whose elements to check for + * equality to the input. + * @return A new [BooleanExpr] representing the 'IN' comparison. + */ + fun eqAny(arrayExpression: Expr) = Companion.eqAny(this, arrayExpression) + + /** + * Creates an expression that checks if this expression, when evaluated, is not equal to all the + * provided [values]. + * + * @param values The values to check against. + * @return A new [BooleanExpr] representing the 'NOT IN' comparison. */ fun notEqAny(values: List) = Companion.notEqAny(this, values) + /** + * Creates an expression that checks if this expression, when evaluated, is not equal to all the + * elements of [arrayExpression]. + * + * @param arrayExpression An expression that evaluates to an array, whose elements to check for + * equality to the input. + * @return A new [BooleanExpr] representing the 'NOT IN' comparison. + */ + fun notEqAny(arrayExpression: Expr) = Companion.notEqAny(this, arrayExpression) + /** */ fun isNan() = Companion.isNan(this) @@ -2759,9 +2826,32 @@ abstract class Expr internal constructor() { fun lte(value: Any): BooleanExpr = Companion.lte(this, value) /** + * Creates an expression that checks if this expression evaluates to a name of the field that + * exists. + * + * @return A new [Expr] representing the exists check. */ fun exists(): BooleanExpr = Companion.exists(this) + /** + * Creates an expression that returns the [catchExpr] argument if there is an + * error, else return the result of this expression. + * + * @param catchExpr The catch expression that will be evaluated and + * returned if the this expression produces an error. + * @return A new [Expr] representing the ifError operation. + */ + fun ifError(catchExpr: Expr): Expr = Companion.ifError(this, catchExpr) + + /** + * Creates an expression that returns the [catchValue] argument if there is an + * error, else return the result of this expression. + * + * @param catchValue The value that will be returned if this expression produces an error. + * @return A new [Expr] representing the ifError operation. + */ + fun ifError(catchValue: Any): Expr = Companion.ifError(this, catchValue) + internal abstract fun toProto(userDataReader: UserDataReader): Value } @@ -2838,17 +2928,24 @@ internal constructor( private val params: Array, private val options: InternalOptions = InternalOptions.EMPTY ) : Expr() { + internal constructor(name: String, param: Expr) : this(name, arrayOf(param)) internal constructor( name: String, param: Expr, vararg params: Any ) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) + internal constructor( + name: String, + param1: Expr, + param2: Expr + ) : this(name, arrayOf(param1, param2)) internal constructor( name: String, param1: Expr, param2: Expr, vararg params: Any ) : this(name, arrayOf(param1, param2, *toArrayOfExprOrConstant(params))) + internal constructor(name: String, fieldName: String) : this(name, arrayOf(field(fieldName))) internal constructor( name: String, fieldName: String, @@ -2866,18 +2963,27 @@ internal constructor( } } -/** An interface that represents a filter condition. */ +/** A class that represents a filter condition. */ open class BooleanExpr internal constructor(name: String, params: Array) : FunctionExpr(name, params, InternalOptions.EMPTY) { internal constructor( name: String, - params: List - ) : this(name, toArrayOfExprOrConstant(params)) + param: Expr + ) : this(name, arrayOf(param)) internal constructor( name: String, param: Expr, vararg params: Any ) : this(name, arrayOf(param, *toArrayOfExprOrConstant(params))) + internal constructor( + name: String, + param1: Expr, + param2: Expr + ) : this(name, arrayOf(param1, param2)) + internal constructor( + name: String, + fieldName: String + ) : this(name, arrayOf(field(fieldName))) internal constructor( name: String, fieldName: String, From 1ae8be71113cffea2498633c041c54c5b342000e Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 1 May 2025 11:05:25 -0400 Subject: [PATCH 53/77] More expression work --- .../firestore/pipeline/expressions.kt | 161 +++++++++++++----- 1 file changed, 116 insertions(+), 45 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 74f854a8926..ffb4148123f 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -794,28 +794,88 @@ abstract class Expr internal constructor() { fun notEqAny(fieldName: String, arrayExpression: Expr): BooleanExpr = BooleanExpr("not_eq_any", fieldName, arrayExpression) - /** @return A new [Expr] representing the isNan operation. */ + /** + * Creates an expression that returns true if a value is absent. Otherwise, returns false even + * if the value is null. + * + * @param value The expression to check. + * @return A new [BooleanExpr] representing the isAbsent operation. + */ + @JvmStatic fun isAbsent(value: Expr): BooleanExpr = BooleanExpr("is_absent", value) + + /** + * Creates an expression that returns true if a field is absent. Otherwise, returns false even + * if the field value is null. + * + * @param fieldName The field to check. + * @return A new [BooleanExpr] representing the isAbsent operation. + */ + @JvmStatic fun isAbsent(fieldName: String): BooleanExpr = BooleanExpr("is_absent", fieldName) + + /** + * Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number). + * + * @param expr The expression to check. + * @return A new [BooleanExpr] representing the isNan operation. + */ @JvmStatic fun isNan(expr: Expr): BooleanExpr = BooleanExpr("is_nan", expr) - /** @return A new [Expr] representing the isNan operation. */ + /** + * Creates an expression that checks if [expr] evaluates to 'NaN' (Not a Number). + * + * @param fieldName The field to check. + * @return A new [BooleanExpr] representing the isNan operation. + */ @JvmStatic fun isNan(fieldName: String): BooleanExpr = BooleanExpr("is_nan", fieldName) - /** @return A new [Expr] representing the isNotNan operation. */ + /** + * Creates an expression that checks if the results of [expr] is NOT 'NaN' (Not a + * Number). + * + * @param expr The expression to check. + * @return A new [BooleanExpr] representing the isNotNan operation. + */ @JvmStatic fun isNotNan(expr: Expr): BooleanExpr = BooleanExpr("is_not_nan", expr) - /** @return A new [Expr] representing the isNotNan operation. */ + /** + * Creates an expression that checks if the results of this expression is NOT 'NaN' (Not a + * Number). + * + * @param fieldName The field to check. + * @return A new [BooleanExpr] representing the isNotNan operation. + */ @JvmStatic fun isNotNan(fieldName: String): BooleanExpr = BooleanExpr("is_not_nan", fieldName) - /** @return A new [Expr] representing the isNull operation. */ + /** + * Creates an expression that checks if tbe result of [expr] is null. + * + * @param expr The expression to check. + * @return A new [BooleanExpr] representing the isNull operation. + */ @JvmStatic fun isNull(expr: Expr): BooleanExpr = BooleanExpr("is_null", expr) - /** @return A new [Expr] representing the isNull operation. */ + /** + * Creates an expression that checks if tbe value of a field is null. + * + * @param fieldName The field to check. + * @return A new [BooleanExpr] representing the isNull operation. + */ @JvmStatic fun isNull(fieldName: String): BooleanExpr = BooleanExpr("is_null", fieldName) - /** @return A new [Expr] representing the isNotNull operation. */ + /** + * Creates an expression that checks if tbe result of [expr] is not null. + * + * @param expr The expression to check. + * @return A new [BooleanExpr] representing the isNotNull operation. + */ @JvmStatic fun isNotNull(expr: Expr): BooleanExpr = BooleanExpr("is_not_null", expr) - /** @return A new [Expr] representing the isNotNull operation. */ + /** + * Creates an expression that checks if tbe value of a field is not null. + * + * @param fieldName The field to check. + * @return A new [BooleanExpr] representing the isNotNull operation. + */ @JvmStatic fun isNotNull(fieldName: String): BooleanExpr = BooleanExpr("is_not_null", fieldName) /** @return A new [Expr] representing the replaceFirst operation. */ @@ -2031,20 +2091,20 @@ abstract class Expr internal constructor() { @JvmStatic fun exists(fieldName: String): BooleanExpr = BooleanExpr("exists", fieldName) /** - * Creates an expression that returns the [catchExpr] argument if there is an - * error, else return the result of the [tryExpr] argument evaluation. + * Creates an expression that returns the [catchExpr] argument if there is an error, else return + * the result of the [tryExpr] argument evaluation. * * @param tryExpr The try expression. - * @param catchExpr The catch expression that will be evaluated and - * returned if the [tryExpr] produces an error. + * @param catchExpr The catch expression that will be evaluated and returned if the [tryExpr] + * produces an error. * @return A new [Expr] representing the ifError operation. */ @JvmStatic fun ifError(tryExpr: Expr, catchExpr: Expr): Expr = FunctionExpr("if_error", tryExpr, catchExpr) /** - * Creates an expression that returns the [catchValue] argument if there is an - * error, else return the result of the [tryExpr] argument evaluation. + * Creates an expression that returns the [catchValue] argument if there is an error, else + * return the result of the [tryExpr] argument evaluation. * * @param tryExpr The try expression. * @param catchValue The value that will be returned if the [tryExpr] produces an error. @@ -2250,7 +2310,7 @@ abstract class Expr internal constructor() { * @param values The values to check against. * @return A new [BooleanExpr] representing the 'IN' comparison. */ - fun eqAny(values: List) = Companion.eqAny(this, values) + fun eqAny(values: List): BooleanExpr = Companion.eqAny(this, values) /** * Creates an expression that checks if this expression, when evaluated, is equal to any of the @@ -2260,7 +2320,7 @@ abstract class Expr internal constructor() { * equality to the input. * @return A new [BooleanExpr] representing the 'IN' comparison. */ - fun eqAny(arrayExpression: Expr) = Companion.eqAny(this, arrayExpression) + fun eqAny(arrayExpression: Expr): BooleanExpr = Companion.eqAny(this, arrayExpression) /** * Creates an expression that checks if this expression, when evaluated, is not equal to all the @@ -2269,7 +2329,7 @@ abstract class Expr internal constructor() { * @param values The values to check against. * @return A new [BooleanExpr] representing the 'NOT IN' comparison. */ - fun notEqAny(values: List) = Companion.notEqAny(this, values) + fun notEqAny(values: List): BooleanExpr = Companion.notEqAny(this, values) /** * Creates an expression that checks if this expression, when evaluated, is not equal to all the @@ -2279,23 +2339,36 @@ abstract class Expr internal constructor() { * equality to the input. * @return A new [BooleanExpr] representing the 'NOT IN' comparison. */ - fun notEqAny(arrayExpression: Expr) = Companion.notEqAny(this, arrayExpression) + fun notEqAny(arrayExpression: Expr): BooleanExpr = Companion.notEqAny(this, arrayExpression) /** + * Creates an expression that checks if this expression evaluates to 'NaN' (Not a Number). + * + * @return A new [BooleanExpr] representing the isNan operation. */ - fun isNan() = Companion.isNan(this) + fun isNan(): BooleanExpr = Companion.isNan(this) /** + * Creates an expression that checks if the results of this expression is NOT 'NaN' (Not a + * Number). + * + * @return A new [BooleanExpr] representing the isNotNan operation. */ - fun isNotNan() = Companion.isNotNan(this) + fun isNotNan(): BooleanExpr = Companion.isNotNan(this) /** + * Creates an expression that checks if tbe result of this expression is null. + * + * @return A new [BooleanExpr] representing the isNull operation. */ - fun isNull() = Companion.isNull(this) + fun isNull(): BooleanExpr = Companion.isNull(this) /** + * Creates an expression that checks if tbe result of this expression is not null. + * + * @return A new [BooleanExpr] representing the isNotNull operation. */ - fun isNotNull() = Companion.isNotNull(this) + fun isNotNull(): BooleanExpr = Companion.isNotNull(this) /** */ @@ -2463,7 +2536,7 @@ abstract class Expr internal constructor() { * @param vector The other vector (represented as an Expr) to compare against. * @return A new [Expr] representing the cosine distance between the two vectors. */ - fun cosineDistance(vector: Expr) = Companion.cosineDistance(this, vector) + fun cosineDistance(vector: Expr): Expr = Companion.cosineDistance(this, vector) /** * Calculates the Cosine distance between this vector expression and a vector literal. @@ -2471,7 +2544,7 @@ abstract class Expr internal constructor() { * @param vector The other vector (as an array of doubles) to compare against. * @return A new [Expr] representing the cosine distance between the two vectors. */ - fun cosineDistance(vector: DoubleArray) = Companion.cosineDistance(this, vector) + fun cosineDistance(vector: DoubleArray): Expr = Companion.cosineDistance(this, vector) /** * Calculates the Cosine distance between this vector expression and a vector literal. @@ -2479,7 +2552,7 @@ abstract class Expr internal constructor() { * @param vector The other vector (represented as an [VectorValue]) to compare against. * @return A new [Expr] representing the cosine distance between the two vectors. */ - fun cosineDistance(vector: VectorValue) = Companion.cosineDistance(this, vector) + fun cosineDistance(vector: VectorValue): Expr = Companion.cosineDistance(this, vector) /** * Calculates the dot product distance between this and another vector expression. @@ -2487,7 +2560,7 @@ abstract class Expr internal constructor() { * @param vector The other vector (represented as an Expr) to compare against. * @return A new [Expr] representing the dot product distance between the two vectors. */ - fun dotProduct(vector: Expr) = Companion.dotProduct(this, vector) + fun dotProduct(vector: Expr): Expr = Companion.dotProduct(this, vector) /** * Calculates the dot product distance between this vector expression and a vector literal. @@ -2495,7 +2568,7 @@ abstract class Expr internal constructor() { * @param vector The other vector (as an array of doubles) to compare against. * @return A new [Expr] representing the dot product distance between the two vectors. */ - fun dotProduct(vector: DoubleArray) = Companion.dotProduct(this, vector) + fun dotProduct(vector: DoubleArray): Expr = Companion.dotProduct(this, vector) /** * Calculates the dot product distance between this vector expression and a vector literal. @@ -2503,7 +2576,7 @@ abstract class Expr internal constructor() { * @param vector The other vector (represented as an [VectorValue]) to compare against. * @return A new [Expr] representing the dot product distance between the two vectors. */ - fun dotProduct(vector: VectorValue) = Companion.dotProduct(this, vector) + fun dotProduct(vector: VectorValue): Expr = Companion.dotProduct(this, vector) /** * Calculates the Euclidean distance between this and another vector expression. @@ -2511,7 +2584,7 @@ abstract class Expr internal constructor() { * @param vector The other vector (represented as an Expr) to compare against. * @return A new [Expr] representing the Euclidean distance between the two vectors. */ - fun euclideanDistance(vector: Expr) = Companion.euclideanDistance(this, vector) + fun euclideanDistance(vector: Expr): Expr = Companion.euclideanDistance(this, vector) /** * Calculates the Euclidean distance between this vector expression and a vector literal. @@ -2519,11 +2592,15 @@ abstract class Expr internal constructor() { * @param vector The other vector (as an array of doubles) to compare against. * @return A new [Expr] representing the Euclidean distance between the two vectors. */ - fun euclideanDistance(vector: DoubleArray) = Companion.euclideanDistance(this, vector) + fun euclideanDistance(vector: DoubleArray): Expr = Companion.euclideanDistance(this, vector) /** + * Calculates the Euclidean distance between this vector expression and a vector literal. + * + * @param vector The other vector (represented as an [VectorValue]) to compare against. + * @return A new [Expr] representing the Euclidean distance between the two vectors. */ - fun euclideanDistance(vector: VectorValue) = Companion.euclideanDistance(this, vector) + fun euclideanDistance(vector: VectorValue): Expr = Companion.euclideanDistance(this, vector) /** */ @@ -2834,18 +2911,18 @@ abstract class Expr internal constructor() { fun exists(): BooleanExpr = Companion.exists(this) /** - * Creates an expression that returns the [catchExpr] argument if there is an - * error, else return the result of this expression. + * Creates an expression that returns the [catchExpr] argument if there is an error, else return + * the result of this expression. * - * @param catchExpr The catch expression that will be evaluated and - * returned if the this expression produces an error. + * @param catchExpr The catch expression that will be evaluated and returned if the this + * expression produces an error. * @return A new [Expr] representing the ifError operation. */ fun ifError(catchExpr: Expr): Expr = Companion.ifError(this, catchExpr) /** - * Creates an expression that returns the [catchValue] argument if there is an - * error, else return the result of this expression. + * Creates an expression that returns the [catchValue] argument if there is an error, else return + * the result of this expression. * * @param catchValue The value that will be returned if this expression produces an error. * @return A new [Expr] representing the ifError operation. @@ -2966,10 +3043,7 @@ internal constructor( /** A class that represents a filter condition. */ open class BooleanExpr internal constructor(name: String, params: Array) : FunctionExpr(name, params, InternalOptions.EMPTY) { - internal constructor( - name: String, - param: Expr - ) : this(name, arrayOf(param)) + internal constructor(name: String, param: Expr) : this(name, arrayOf(param)) internal constructor( name: String, param: Expr, @@ -2980,10 +3054,7 @@ open class BooleanExpr internal constructor(name: String, params: Array Date: Thu, 1 May 2025 14:07:40 -0400 Subject: [PATCH 54/77] More expression work --- .../firebase/firestore/PipelineTest.java | 6 +- .../firestore/pipeline/expressions.kt | 183 +++++++++++++----- 2 files changed, 135 insertions(+), 54 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index a17dc79ab42..12a4a5aa1d7 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -25,7 +25,7 @@ import static com.google.firebase.firestore.pipeline.Expr.euclideanDistance; import static com.google.firebase.firestore.pipeline.Expr.field; import static com.google.firebase.firestore.pipeline.Expr.gt; -import static com.google.firebase.firestore.pipeline.Expr.logicalMax; +import static com.google.firebase.firestore.pipeline.Expr.logicalMaximum; import static com.google.firebase.firestore.pipeline.Expr.lt; import static com.google.firebase.firestore.pipeline.Expr.lte; import static com.google.firebase.firestore.pipeline.Expr.mapGet; @@ -724,8 +724,8 @@ public void testLogicalMax() { .collection(randomCol) .where(field("author").eq("Douglas Adams")) .select( - field("rating").logicalMax(4.5).alias("max_rating"), - logicalMax(field("published"), 1900).alias("max_published")) + field("rating").logicalMaximum(4.5).alias("max_rating"), + logicalMaximum(field("published"), 1900).alias("max_published")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index ffb4148123f..34b70aa546d 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -829,8 +829,7 @@ abstract class Expr internal constructor() { @JvmStatic fun isNan(fieldName: String): BooleanExpr = BooleanExpr("is_nan", fieldName) /** - * Creates an expression that checks if the results of [expr] is NOT 'NaN' (Not a - * Number). + * Creates an expression that checks if the results of [expr] is NOT 'NaN' (Not a Number). * * @param expr The expression to check. * @return A new [BooleanExpr] representing the isNotNan operation. @@ -942,19 +941,48 @@ abstract class Expr internal constructor() { */ @JvmStatic fun byteLength(fieldName: String): Expr = FunctionExpr("byte_length", fieldName) - /** @return A new [Expr] representing the like operation. */ - @JvmStatic fun like(expr: Expr, pattern: Expr): BooleanExpr = BooleanExpr("like", expr, pattern) + /** + * Creates an expression that performs a case-sensitive wildcard string comparison. + * + * @param stringExpression The expression representing the string to perform the comparison on. + * @param pattern The pattern to search for. You can use "%" as a wildcard character. + * @return A new [BooleanExpr] representing the like operation. + */ + @JvmStatic + fun like(stringExpression: Expr, pattern: Expr): BooleanExpr = + BooleanExpr("like", stringExpression, pattern) - /** @return A new [Expr] representing the like operation. */ + /** + * Creates an expression that performs a case-sensitive wildcard string comparison. + * + * @param stringExpression The expression representing the string to perform the comparison on. + * @param pattern The pattern to search for. You can use "%" as a wildcard character. + * @return A new [BooleanExpr] representing the like operation. + */ @JvmStatic - fun like(expr: Expr, pattern: String): BooleanExpr = BooleanExpr("like", expr, pattern) + fun like(stringExpression: Expr, pattern: String): BooleanExpr = + BooleanExpr("like", stringExpression, pattern) - /** @return A new [Expr] representing the like operation. */ + /** + * Creates an expression that performs a case-sensitive wildcard string comparison against a + * field. + * + * @param fieldName The name of the field containing the string. + * @param pattern The pattern to search for. You can use "%" as a wildcard character. + * @return A new [BooleanExpr] representing the like comparison. + */ @JvmStatic fun like(fieldName: String, pattern: Expr): BooleanExpr = BooleanExpr("like", fieldName, pattern) - /** @return A new [Expr] representing the like operation. */ + /** + * Creates an expression that performs a case-sensitive wildcard string comparison against a + * field. + * + * @param fieldName The name of the field containing the string. + * @param pattern The pattern to search for. You can use "%" as a wildcard character. + * @return A new [BooleanExpr] representing the like comparison. + */ @JvmStatic fun like(fieldName: String, pattern: String): BooleanExpr = BooleanExpr("like", fieldName, pattern) @@ -999,41 +1027,53 @@ abstract class Expr internal constructor() { fun regexMatch(fieldName: String, pattern: String) = BooleanExpr("regex_match", fieldName, pattern) - /** @return A new [Expr] representing the logicalMax operation. */ - @JvmStatic - fun logicalMax(left: Expr, right: Expr): Expr = FunctionExpr("logical_max", left, right) - - /** @return A new [Expr] representing the logicalMax operation. */ - @JvmStatic - fun logicalMax(left: Expr, right: Any): Expr = FunctionExpr("logical_max", left, right) - - /** @return A new [Expr] representing the logicalMax operation. */ - @JvmStatic - fun logicalMax(fieldName: String, other: Expr): Expr = - FunctionExpr("logical_max", fieldName, other) - - /** @return A new [Expr] representing the logicalMax operation. */ - @JvmStatic - fun logicalMax(fieldName: String, other: Any): Expr = - FunctionExpr("logical_max", fieldName, other) - - /** @return A new [Expr] representing the logicalMin operation. */ + /** + * Creates an expression that returns the largest value between multiple input expressions or + * literal values. Based on Firestore's value type ordering. + * + * @param expr The first operand expression. + * @param others Optional additional expressions or literals. + * @return A new [Expr] representing the logical maximum operation. + */ @JvmStatic - fun logicalMin(left: Expr, right: Expr): Expr = FunctionExpr("logical_min", left, right) + fun logicalMaximum(expr: Expr, vararg others: Any): Expr = + FunctionExpr("logical_max", expr, *others) - /** @return A new [Expr] representing the logicalMin operation. */ + /** + * Creates an expression that returns the largest value between multiple input expressions or + * literal values. Based on Firestore's value type ordering. + * + * @param fieldName The first operand field name. + * @param others Optional additional expressions or literals. + * @return A new [Expr] representing the logical maximum operation. + */ @JvmStatic - fun logicalMin(left: Expr, right: Any): Expr = FunctionExpr("logical_min", left, right) + fun logicalMaximum(fieldName: String, vararg others: Any): Expr = + FunctionExpr("logical_max", fieldName, *others) - /** @return A new [Expr] representing the logicalMin operation. */ + /** + * Creates an expression that returns the smallest value between multiple input expressions or + * literal values. Based on Firestore's value type ordering. + * + * @param expr The first operand expression. + * @param others Optional additional expressions or literals. + * @return A new [Expr] representing the logical minimum operation. + */ @JvmStatic - fun logicalMin(fieldName: String, other: Expr): Expr = - FunctionExpr("logical_min", fieldName, other) + fun logicalMinimum(expr: Expr, vararg others: Any): Expr = + FunctionExpr("logical_min", expr, *others) - /** @return A new [Expr] representing the logicalMin operation. */ + /** + * Creates an expression that returns the smallest value between multiple input expressions or + * literal values. Based on Firestore's value type ordering. + * + * @param fieldName The first operand field name. + * @param others Optional additional expressions or literals. + * @return A new [Expr] representing the logical minimum operation. + */ @JvmStatic - fun logicalMin(fieldName: String, other: Any): Expr = - FunctionExpr("logical_min", fieldName, other) + fun logicalMinimum(fieldName: String, vararg others: Any): Expr = + FunctionExpr("logical_min", fieldName, *others) /** @return A new [Expr] representing the reverse operation. */ @JvmStatic fun reverse(expr: Expr): Expr = FunctionExpr("reverse", expr) @@ -1193,9 +1233,14 @@ abstract class Expr internal constructor() { internal fun map(elements: Array): Expr = FunctionExpr("map", elements) - /** @return A new [Expr] representing the map operation. */ + /** + * Creates an expression that creates a Firestore map value from an input object. + * + * @param elements The input map to evaluate in the expression. + * @return A new [Expr] representing the map function. + */ @JvmStatic - fun map(elements: Map) = + fun map(elements: Map): Expr = map(elements.flatMap { listOf(constant(it.key), toExprOrConstant(it.value)) }.toTypedArray()) /** @return A new [Expr] representing the mapGet operation. */ @@ -1215,12 +1260,12 @@ abstract class Expr internal constructor() { /** @return A new [Expr] representing the mapMerge operation. */ @JvmStatic fun mapMerge(firstMap: Expr, secondMap: Expr, vararg otherMaps: Expr): Expr = - FunctionExpr("map_merge", firstMap, secondMap, otherMaps) + FunctionExpr("map_merge", firstMap, secondMap, *otherMaps) /** @return A new [Expr] representing the mapMerge operation. */ @JvmStatic fun mapMerge(mapField: String, secondMap: Expr, vararg otherMaps: Expr): Expr = - FunctionExpr("map_merge", mapField, secondMap, otherMaps) + FunctionExpr("map_merge", mapField, secondMap, *otherMaps) /** @return A new [Expr] representing the mapRemove operation. */ @JvmStatic @@ -2341,6 +2386,14 @@ abstract class Expr internal constructor() { */ fun notEqAny(arrayExpression: Expr): BooleanExpr = Companion.notEqAny(this, arrayExpression) + /** + * Creates an expression that returns true if yhe result of this expression is absent. Otherwise, + * returns false even if the value is null. + * + * @return A new [BooleanExpr] representing the isAbsent operation. + */ + fun isAbsent(): BooleanExpr = Companion.isAbsent(this) + /** * Creates an expression that checks if this expression evaluates to 'NaN' (Not a Number). * @@ -2402,48 +2455,76 @@ abstract class Expr internal constructor() { fun byteLength(): Expr = Companion.byteLength(this) /** + * Creates an expression that performs a case-sensitive wildcard string comparison. + * + * @param pattern The pattern to search for. You can use "%" as a wildcard character. + * @return A new [BooleanExpr] representing the like operation. */ - fun like(pattern: Expr) = Companion.like(this, pattern) + fun like(pattern: Expr): BooleanExpr = Companion.like(this, pattern) /** + * Creates an expression that performs a case-sensitive wildcard string comparison. + * + * @param pattern The pattern to search for. You can use "%" as a wildcard character. + * @return A new [BooleanExpr] representing the like operation. */ - fun like(pattern: String) = Companion.like(this, pattern) + fun like(pattern: String): BooleanExpr = Companion.like(this, pattern) /** */ - fun regexContains(pattern: Expr) = Companion.regexContains(this, pattern) + fun regexContains(pattern: Expr): BooleanExpr = Companion.regexContains(this, pattern) /** */ - fun regexContains(pattern: String) = Companion.regexContains(this, pattern) + fun regexContains(pattern: String): BooleanExpr = Companion.regexContains(this, pattern) /** */ - fun regexMatch(pattern: Expr) = Companion.regexMatch(this, pattern) + fun regexMatch(pattern: Expr): BooleanExpr = Companion.regexMatch(this, pattern) /** */ - fun regexMatch(pattern: String) = Companion.regexMatch(this, pattern) + fun regexMatch(pattern: String): BooleanExpr = Companion.regexMatch(this, pattern) /** + * Creates an expression that returns the largest value between multiple input expressions or + * literal values. Based on Firestore's value type ordering. + * + * @param others Expressions or literals. + * @return A new [Expr] representing the logical maximum operation. */ - fun logicalMax(other: Expr) = Companion.logicalMax(this, other) + fun logicalMaximum(vararg others: Expr): Expr = Companion.logicalMaximum(this, *others) /** + * Creates an expression that returns the largest value between multiple input expressions or + * literal values. Based on Firestore's value type ordering. + * + * @param others Expressions or literals. + * @return A new [Expr] representing the logical maximum operation. */ - fun logicalMax(other: Any) = Companion.logicalMax(this, other) + fun logicalMaximum(vararg others: Any): Expr = Companion.logicalMaximum(this, *others) /** + * Creates an expression that returns the smallest value between multiple input expressions or + * literal values. Based on Firestore's value type ordering. + * + * @param others Expressions or literals. + * @return A new [Expr] representing the logical minimum operation. */ - fun logicalMin(other: Expr) = Companion.logicalMin(this, other) + fun logicalMinimum(vararg others: Expr): Expr = Companion.logicalMinimum(this, *others) /** + * Creates an expression that returns the smallest value between multiple input expressions or + * literal values. Based on Firestore's value type ordering. + * + * @param others Expressions or literals. + * @return A new [Expr] representing the logical minimum operation. */ - fun logicalMin(other: Any) = Companion.logicalMin(this, other) + fun logicalMinimum(vararg others: Any): Expr = Companion.logicalMinimum(this, *others) /** */ - fun reverse() = Companion.reverse(this) + fun reverse(): Expr = Companion.reverse(this) /** */ From c32429818b8cbf144d8356092bc37cc4c8c10133 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 5 May 2025 11:28:02 -0400 Subject: [PATCH 55/77] More expression work --- .../firestore/pipeline/expressions.kt | 147 +++++++++++++++--- 1 file changed, 125 insertions(+), 22 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 34b70aa546d..771e4c60c98 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -570,6 +570,53 @@ abstract class Expr internal constructor() { fun bitRightShift(bitsFieldName: String, number: Int): Expr = FunctionExpr("bit_right_shift", bitsFieldName, number) + @JvmStatic + fun round(numericExpr: Expr, decimalPlace: Int): Expr = + FunctionExpr("round", numericExpr, constant(decimalPlace)) + + @JvmStatic + fun round(numericField: String, decimalPlace: Int): Expr = + FunctionExpr("round", numericField, constant(decimalPlace)) + + @JvmStatic fun round(numericExpr: Expr): Expr = FunctionExpr("round", numericExpr) + + @JvmStatic fun round(numericField: String): Expr = FunctionExpr("round", numericField) + + @JvmStatic + fun round(numericExpr: Expr, decimalPlace: Expr): Expr = + FunctionExpr("round", numericExpr, decimalPlace) + + @JvmStatic + fun round(numericField: String, decimalPlace: Expr): Expr = + FunctionExpr("round", numericField, decimalPlace) + + @JvmStatic fun ceil(numericExpr: Expr): Expr = FunctionExpr("ceil", numericExpr) + + @JvmStatic fun ceil(numericField: String): Expr = FunctionExpr("ceil", numericField) + + @JvmStatic fun floor(numericExpr: Expr): Expr = FunctionExpr("floor", numericExpr) + + @JvmStatic fun floor(numericField: String): Expr = FunctionExpr("floor", numericField) + + @JvmStatic + fun pow(numericExpr: Expr, exponent: Number): Expr = + FunctionExpr("pow", numericExpr, constant(exponent)) + + @JvmStatic + fun pow(numericField: String, exponent: Number): Expr = + FunctionExpr("pow", numericField, constant(exponent)) + + @JvmStatic + fun pow(numericExpr: Expr, exponent: Expr): Expr = FunctionExpr("pow", numericExpr, exponent) + + @JvmStatic + fun pow(numericField: String, exponent: Expr): Expr = + FunctionExpr("pow", numericField, exponent) + + @JvmStatic fun sqrt(numericExpr: Expr): Expr = FunctionExpr("sqrt", numericExpr) + + @JvmStatic fun sqrt(numericField: String): Expr = FunctionExpr("sqrt", numericField) + /** * Creates an expression that adds this expression to another expression. * @@ -1243,35 +1290,69 @@ abstract class Expr internal constructor() { fun map(elements: Map): Expr = map(elements.flatMap { listOf(constant(it.key), toExprOrConstant(it.value)) }.toTypedArray()) - /** @return A new [Expr] representing the mapGet operation. */ - @JvmStatic fun mapGet(map: Expr, key: Expr): Expr = FunctionExpr("map_get", map, key) - - /** @return A new [Expr] representing the mapGet operation. */ - @JvmStatic fun mapGet(map: Expr, key: String): Expr = FunctionExpr("map_get", map, key) - - /** @return A new [Expr] representing the mapGet operation. */ + /** + * Accesses a value from a map (object) field using the provided [key]. + * + * @param mapExpression The expression representing the map. + * @param key The key to access in the map. + * @return A new [Expr] representing the value associated with the given key in the map. + */ @JvmStatic - fun mapGet(fieldName: String, key: Expr): Expr = FunctionExpr("map_get", fieldName, key) + fun mapGet(mapExpression: Expr, key: String): Expr = FunctionExpr("map_get", mapExpression, key) - /** @return A new [Expr] representing the mapGet operation. */ + /** + * Accesses a value from a map (object) field using the provided [key]. + * + * @param fieldName The field name of the map field. + * @param key The key to access in the map. + * @return A new [Expr] representing the value associated with the given key in the map. + */ @JvmStatic fun mapGet(fieldName: String, key: String): Expr = FunctionExpr("map_get", fieldName, key) - /** @return A new [Expr] representing the mapMerge operation. */ + /** + * Creates an expression that merges multiple maps into a single map. If multiple maps have the + * same key, the later value is used. + * + * @param firstMap First map expression that will be merged. + * @param secondMap Second map expression that will be merged. + * @param otherMaps Additional maps to merge. + * @return A new [Expr] representing the mapMerge operation. + */ @JvmStatic fun mapMerge(firstMap: Expr, secondMap: Expr, vararg otherMaps: Expr): Expr = FunctionExpr("map_merge", firstMap, secondMap, *otherMaps) - /** @return A new [Expr] representing the mapMerge operation. */ + /** + * Creates an expression that merges multiple maps into a single map. If multiple maps have the + * same key, the later value is used. + * + * @param firstMapFieldName First map field name that will be merged. + * @param secondMap Second map expression that will be merged. + * @param otherMaps Additional maps to merge. + * @return A new [Expr] representing the mapMerge operation. + */ @JvmStatic - fun mapMerge(mapField: String, secondMap: Expr, vararg otherMaps: Expr): Expr = - FunctionExpr("map_merge", mapField, secondMap, *otherMaps) + fun mapMerge(firstMapFieldName: String, secondMap: Expr, vararg otherMaps: Expr): Expr = + FunctionExpr("map_merge", firstMapFieldName, secondMap, *otherMaps) - /** @return A new [Expr] representing the mapRemove operation. */ + /** + * Creates an expression that removes a key from the map produced by evaluating an expression. + * + * @param mapExpr An expression return a map value. + * @param key The name of the key to remove from the input map. + * @return A new [Expr] that evaluates to a modified map. + */ @JvmStatic - fun mapRemove(firstMap: Expr, key: Expr): Expr = FunctionExpr("map_remove", firstMap, key) + fun mapRemove(mapExpr: Expr, key: Expr): Expr = FunctionExpr("map_remove", mapExpr, key) - /** @return A new [Expr] representing the mapRemove operation. */ + /** + * Creates an expression that removes a key from the map produced by evaluating an expression. + * + * @param mapField The name of a field containing a map value. + * @param key The name of the key to remove from the input map. + * @return A new [Expr] that evaluates to a modified map. + */ @JvmStatic fun mapRemove(mapField: String, key: Expr): Expr = FunctionExpr("map_remove", mapField, key) @@ -2348,6 +2429,22 @@ abstract class Expr internal constructor() { */ fun mod(other: Any) = Companion.mod(this, other) + fun round() = Companion.round(this) + + fun round(decimalPlace: Int) = Companion.round(this, decimalPlace) + + fun round(decimalPlace: Expr) = Companion.round(this, decimalPlace) + + fun ceil() = Companion.ceil(this) + + fun floor() = Companion.floor(this) + + fun pow(exponentExpr: Number) = Companion.pow(this, exponentExpr) + + fun pow(exponentExpr: Expr) = Companion.pow(this, exponentExpr) + + fun sqrt() = Companion.sqrt(this) + /** * Creates an expression that checks if this expression, when evaluated, is equal to any of the * provided [values]. @@ -2591,17 +2688,23 @@ abstract class Expr internal constructor() { fun strConcat(vararg string: Any) = Companion.strConcat(this, *string) /** - */ - fun mapGet(key: Expr) = Companion.mapGet(this, key) - - /** + * Accesses a map (object) value using the provided [key]. + * + * @param key The key to access in the map. + * @return A new [Expr] representing the value associated with the given key in the map. */ fun mapGet(key: String) = Companion.mapGet(this, key) /** + * Creates an expression that merges multiple maps into a single map. If multiple maps have the + * same key, the later value is used. + * + * @param mapExpr Map expression that will be merged. + * @param otherMaps Additional maps to merge. + * @return A new [Expr] representing the mapMerge operation. */ - fun mapMerge(secondMap: Expr, vararg otherMaps: Expr) = - Companion.mapMerge(this, secondMap, *otherMaps) + fun mapMerge(mapExpr: Expr, vararg otherMaps: Expr) = + Companion.mapMerge(this, mapExpr, *otherMaps) /** */ From 7e685f79c147da512d998c42f7a0ac856f1bbe88 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 5 May 2025 14:19:50 -0400 Subject: [PATCH 56/77] More expression work --- .../firestore/pipeline/expressions.kt | 192 +++++++++++++++++- 1 file changed, 186 insertions(+), 6 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 771e4c60c98..9a1af812b31 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -570,51 +570,175 @@ abstract class Expr internal constructor() { fun bitRightShift(bitsFieldName: String, number: Int): Expr = FunctionExpr("bit_right_shift", bitsFieldName, number) + /** + * Creates an expression that rounds [numericExpr] to nearest integer. + * + * Rounds away from zero in halfway cases. + * + * @param numericExpr An expression that returns number when evaluated. + * @return A new [Expr] representing an integer result from the round operation. + */ + @JvmStatic fun round(numericExpr: Expr): Expr = FunctionExpr("round", numericExpr) + + /** + * Creates an expression that rounds [numericField] to nearest integer. + * + * Rounds away from zero in halfway cases. + * + * @param numericField Name of field that returns number when evaluated. + * @return A new [Expr] representing an integer result from the round operation. + */ + @JvmStatic fun round(numericField: String): Expr = FunctionExpr("round", numericField) + + /** + * Creates an expression that rounds off [numericExpr] to [decimalPlace] decimal places if + * [decimalPlace] is positive, rounds off digits to the left of the decimal point if + * [decimalPlace] is negative. Rounds away from zero in halfway cases. + * + * @param numericExpr An expression that returns number when evaluated. + * @param decimalPlace The number of decimal places to round. + * @return A new [Expr] representing the round operation. + */ @JvmStatic fun round(numericExpr: Expr, decimalPlace: Int): Expr = FunctionExpr("round", numericExpr, constant(decimalPlace)) + /** + * Creates an expression that rounds off [numericField] to [decimalPlace] decimal places if + * [decimalPlace] is positive, rounds off digits to the left of the decimal point if + * [decimalPlace] is negative. Rounds away from zero in halfway cases. + * + * @param numericField Name of field that returns number when evaluated. + * @param decimalPlace The number of decimal places to round. + * @return A new [Expr] representing the round operation. + */ @JvmStatic fun round(numericField: String, decimalPlace: Int): Expr = FunctionExpr("round", numericField, constant(decimalPlace)) - @JvmStatic fun round(numericExpr: Expr): Expr = FunctionExpr("round", numericExpr) - - @JvmStatic fun round(numericField: String): Expr = FunctionExpr("round", numericField) - + /** + * Creates an expression that rounds off [numericExpr] to [decimalPlace] decimal places if + * [decimalPlace] is positive, rounds off digits to the left of the decimal point if + * [decimalPlace] is negative. Rounds away from zero in halfway cases. + * + * @param numericExpr An expression that returns number when evaluated. + * @param decimalPlace The number of decimal places to round. + * @return A new [Expr] representing the round operation. + */ @JvmStatic fun round(numericExpr: Expr, decimalPlace: Expr): Expr = FunctionExpr("round", numericExpr, decimalPlace) + /** + * Creates an expression that rounds off [numericField] to [decimalPlace] decimal places if + * [decimalPlace] is positive, rounds off digits to the left of the decimal point if + * [decimalPlace] is negative. Rounds away from zero in halfway cases. + * + * @param numericField Name of field that returns number when evaluated. + * @param decimalPlace The number of decimal places to round. + * @return A new [Expr] representing the round operation. + */ @JvmStatic fun round(numericField: String, decimalPlace: Expr): Expr = FunctionExpr("round", numericField, decimalPlace) + /** + * Creates an expression that returns the smalled integer that isn't less than [numericExpr]. + * + * @param numericExpr An expression that returns number when evaluated. + * @return A new [Expr] representing an integer result from the ceil operation. + */ @JvmStatic fun ceil(numericExpr: Expr): Expr = FunctionExpr("ceil", numericExpr) + /** + * Creates an expression that returns the smalled integer that isn't less than [numericField]. + * + * @param numericField Name of field that returns number when evaluated. + * @return A new [Expr] representing an integer result from the ceil operation. + */ @JvmStatic fun ceil(numericField: String): Expr = FunctionExpr("ceil", numericField) + /** + * Creates an expression that returns the largest integer that isn't less than [numericExpr]. + * + * @param numericExpr An expression that returns number when evaluated. + * @return A new [Expr] representing an integer result from the floor operation. + */ @JvmStatic fun floor(numericExpr: Expr): Expr = FunctionExpr("floor", numericExpr) + /** + * Creates an expression that returns the largest integer that isn't less than [numericField]. + * + * @param numericField Name of field that returns number when evaluated. + * @return A new [Expr] representing an integer result from the floor operation. + */ @JvmStatic fun floor(numericField: String): Expr = FunctionExpr("floor", numericField) + /** + * Creates an expression that returns the [numericExpr] raised to the power of the [exponent]. + * Returns infinity on overflow and zero on underflow. + * + * @param numericExpr An expression that returns number when evaluated. + * @param exponent The numeric power to raise the [numericExpr]. + * @return A new [Expr] representing a numeric result from raising [numericExpr] to the power of + * [exponent]. + */ @JvmStatic fun pow(numericExpr: Expr, exponent: Number): Expr = FunctionExpr("pow", numericExpr, constant(exponent)) + /** + * Creates an expression that returns the [numericField] raised to the power of the [exponent]. + * Returns infinity on overflow and zero on underflow. + * + * @param numericField Name of field that returns number when evaluated. + * @param exponent The numeric power to raise the [numericField]. + * @return A new [Expr] representing a numeric result from raising [numericField] to the power + * of [exponent]. + */ @JvmStatic fun pow(numericField: String, exponent: Number): Expr = FunctionExpr("pow", numericField, constant(exponent)) + /** + * Creates an expression that returns the [numericExpr] raised to the power of the [exponent]. + * Returns infinity on overflow and zero on underflow. + * + * @param numericExpr An expression that returns number when evaluated. + * @param exponent The numeric power to raise the [numericExpr]. + * @return A new [Expr] representing a numeric result from raising [numericExpr] to the power of + * [exponent]. + */ @JvmStatic fun pow(numericExpr: Expr, exponent: Expr): Expr = FunctionExpr("pow", numericExpr, exponent) + /** + * Creates an expression that returns the [numericField] raised to the power of the [exponent]. + * Returns infinity on overflow and zero on underflow. + * + * @param numericField Name of field that returns number when evaluated. + * @param exponent The numeric power to raise the [numericField]. + * @return A new [Expr] representing a numeric result from raising [numericField] to the power + * of [exponent]. + */ @JvmStatic fun pow(numericField: String, exponent: Expr): Expr = FunctionExpr("pow", numericField, exponent) + /** + * Creates an expression that returns the square root of [numericExpr]. + * + * @param numericExpr An expression that returns number when evaluated. + * @return A new [Expr] representing the numeric result of the square root operation. + */ @JvmStatic fun sqrt(numericExpr: Expr): Expr = FunctionExpr("sqrt", numericExpr) + /** + * Creates an expression that returns the square root of [numericField]. + * + * @param numericField Name of field that returns number when evaluated. + * @return A new [Expr] representing the numeric result of the square root operation. + */ @JvmStatic fun sqrt(numericField: String): Expr = FunctionExpr("sqrt", numericField) /** @@ -2429,20 +2553,76 @@ abstract class Expr internal constructor() { */ fun mod(other: Any) = Companion.mod(this, other) + /** + * Creates an expression that rounds this numeric expression to nearest integer. + * + * Rounds away from zero in halfway cases. + * + * @return A new [Expr] representing an integer result from the round operation. + */ fun round() = Companion.round(this) + /** + * Creates an expression that rounds off this numeric expression to [decimalPlace] decimal places + * if [decimalPlace] is positive, rounds off digits to the left of the decimal point if + * [decimalPlace] is negative. Rounds away from zero in halfway cases. + * + * @param decimalPlace The number of decimal places to round. + * @return A new [Expr] representing the round operation. + */ fun round(decimalPlace: Int) = Companion.round(this, decimalPlace) + /** + * Creates an expression that rounds off this numeric expression to [decimalPlace] decimal places + * if [decimalPlace] is positive, rounds off digits to the left of the decimal point if + * [decimalPlace] is negative. Rounds away from zero in halfway cases. + * + * @param decimalPlace The number of decimal places to round. + * @return A new [Expr] representing the round operation. + */ fun round(decimalPlace: Expr) = Companion.round(this, decimalPlace) + /** + * Creates an expression that returns the smalled integer that isn't less than this numeric + * expression. + * + * @return A new [Expr] representing an integer result from the ceil operation. + */ fun ceil() = Companion.ceil(this) + /** + * Creates an expression that returns the largest integer that isn't less than this numeric + * expression. + * + * @return A new [Expr] representing an integer result from the floor operation. + */ fun floor() = Companion.floor(this) - fun pow(exponentExpr: Number) = Companion.pow(this, exponentExpr) + /** + * Creates an expression that returns this numeric expression raised to the power of the + * [exponent]. Returns infinity on overflow and zero on underflow. + * + * @param exponent The numeric power to raise this numeric expression. + * @return A new [Expr] representing a numeric result from raising this numeric expression to the + * power of [exponent]. + */ + fun pow(exponent: Number) = Companion.pow(this, exponent) - fun pow(exponentExpr: Expr) = Companion.pow(this, exponentExpr) + /** + * Creates an expression that returns this numeric expression raised to the power of the + * [exponent]. Returns infinity on overflow and zero on underflow. + * + * @param exponent The numeric power to raise this numeric expression. + * @return A new [Expr] representing a numeric result from raising this numeric expression to the + * power of [exponent]. + */ + fun pow(exponent: Expr) = Companion.pow(this, exponent) + /** + * Creates an expression that returns the square root of this numeric expression. + * + * @return A new [Expr] representing the numeric result of the square root operation. + */ fun sqrt() = Companion.sqrt(this) /** From fec44cf881fc2f4e76e13214427eee9af97135fd Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 5 May 2025 14:31:29 -0400 Subject: [PATCH 57/77] Generate API.txt --- firebase-firestore/api.txt | 476 ++++++++++-------- .../firestore/pipeline/expressions.kt | 12 +- 2 files changed, 284 insertions(+), 204 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 592d2b24ba9..5129580877f 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -737,12 +737,12 @@ package com.google.firebase.firestore.pipeline { public final class AggregateWithAlias { } - public final class BooleanExpr extends com.google.firebase.firestore.pipeline.FunctionExpr { - method public com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); - method public com.google.firebase.firestore.pipeline.Expr cond(Object then, Object otherwise); - method public com.google.firebase.firestore.pipeline.AggregateFunction countIf(); - method public static com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); - method public com.google.firebase.firestore.pipeline.BooleanExpr not(); + public class BooleanExpr extends com.google.firebase.firestore.pipeline.FunctionExpr { + method public final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); + method public final com.google.firebase.firestore.pipeline.Expr cond(Object then, Object otherwise); + method public final com.google.firebase.firestore.pipeline.AggregateFunction countIf(); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public final com.google.firebase.firestore.pipeline.BooleanExpr not(); field public static final com.google.firebase.firestore.pipeline.BooleanExpr.Companion Companion; } @@ -826,82 +826,98 @@ package com.google.firebase.firestore.pipeline { } public abstract class Expr { - method public final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr add(Object other); - method public static final com.google.firebase.firestore.pipeline.Expr add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr add(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Object second, java.lang.Object... others); + method public final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public final com.google.firebase.firestore.pipeline.Expr add(Object second, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr add(String fieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr add(String fieldName, Object second, java.lang.Object... others); method public com.google.firebase.firestore.pipeline.ExprWithAlias alias(String alias); method public static final com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); - method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); - method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); - method public final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr... arrays); - method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); - method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(String fieldName, java.util.List arrays); - method public final com.google.firebase.firestore.pipeline.Expr arrayConcat(java.util.List arrays); - method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr value); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr value); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object value); - method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(Object value); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, com.google.firebase.firestore.pipeline.Expr value); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, Object value); + method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); + method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, Object secondArray, java.lang.Object... otherArrays); + method public final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); + method public final com.google.firebase.firestore.pipeline.Expr arrayConcat(Object secondArray, java.lang.Object... otherArrays); + method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(String firstArrayField, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); + method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(String firstArrayField, Object secondArray, java.lang.Object... otherArrays); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr element); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr element); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object element); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(Object element); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String arrayFieldName, com.google.firebase.firestore.pipeline.Expr element); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String arrayFieldName, Object element); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr arrayExpression); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String fieldName, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String arrayFieldName, com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String arrayFieldName, java.util.List values); method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(java.util.List values); + method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr arrayExpression); method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String fieldName, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String arrayFieldName, com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String arrayFieldName, java.util.List values); method public final com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(java.util.List values); method public final com.google.firebase.firestore.pipeline.Expr arrayLength(); method public static final com.google.firebase.firestore.pipeline.Expr arrayLength(com.google.firebase.firestore.pipeline.Expr array); - method public static final com.google.firebase.firestore.pipeline.Expr arrayLength(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Expr arrayLength(String arrayFieldName); + method public final com.google.firebase.firestore.pipeline.Expr arrayOffset(com.google.firebase.firestore.pipeline.Expr offset); + method public static final com.google.firebase.firestore.pipeline.Expr arrayOffset(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr offset); + method public static final com.google.firebase.firestore.pipeline.Expr arrayOffset(com.google.firebase.firestore.pipeline.Expr array, int offset); + method public final com.google.firebase.firestore.pipeline.Expr arrayOffset(int offset); + method public static final com.google.firebase.firestore.pipeline.Expr arrayOffset(String arrayFieldName, com.google.firebase.firestore.pipeline.Expr offset); + method public static final com.google.firebase.firestore.pipeline.Expr arrayOffset(String arrayFieldName, int offset); method public final com.google.firebase.firestore.pipeline.Expr arrayReverse(); method public static final com.google.firebase.firestore.pipeline.Expr arrayReverse(com.google.firebase.firestore.pipeline.Expr array); - method public static final com.google.firebase.firestore.pipeline.Expr arrayReverse(String fieldName); + method public static final com.google.firebase.firestore.pipeline.Expr arrayReverse(String arrayFieldName); method public final com.google.firebase.firestore.pipeline.Ordering ascending(); method public final com.google.firebase.firestore.pipeline.AggregateFunction avg(); - method public final com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr bitAnd(Object right); - method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.Expr bitAnd(byte[] bitsOther); + method public final com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr bits, byte[] bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(String bitsFieldName, byte[] bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitAnd(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr bitsOther); method public final com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr bits, int number); method public final com.google.firebase.firestore.pipeline.Expr bitLeftShift(int number); - method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(String fieldName, int number); + method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitLeftShift(String bitsFieldName, int number); method public final com.google.firebase.firestore.pipeline.Expr bitNot(); - method public static final com.google.firebase.firestore.pipeline.Expr bitNot(com.google.firebase.firestore.pipeline.Expr left); - method public static final com.google.firebase.firestore.pipeline.Expr bitNot(String fieldName); - method public final com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr bitOr(Object right); - method public static final com.google.firebase.firestore.pipeline.Expr bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr bitOr(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.Expr bitNot(com.google.firebase.firestore.pipeline.Expr bits); + method public static final com.google.firebase.firestore.pipeline.Expr bitNot(String bitsFieldName); + method public final com.google.firebase.firestore.pipeline.Expr bitOr(byte[] bitsOther); + method public final com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr bits, byte[] bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitOr(String bitsFieldName, byte[] bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitOr(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr bitsOther); method public final com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); + method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr bits, int number); method public final com.google.firebase.firestore.pipeline.Expr bitRightShift(int number); - method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(String fieldName, int number); - method public final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr bitXor(Object right); - method public static final com.google.firebase.firestore.pipeline.Expr bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr bitXor(String fieldName, Object right); + method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public static final com.google.firebase.firestore.pipeline.Expr bitRightShift(String bitsFieldName, int number); + method public final com.google.firebase.firestore.pipeline.Expr bitXor(byte[] bitsOther); + method public final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr bits, byte[] bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitXor(String bitsFieldName, byte[] bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr bitXor(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr bitsOther); method public final com.google.firebase.firestore.pipeline.Expr byteLength(); method public static final com.google.firebase.firestore.pipeline.Expr byteLength(com.google.firebase.firestore.pipeline.Expr value); method public static final com.google.firebase.firestore.pipeline.Expr byteLength(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr ceil(); + method public static final com.google.firebase.firestore.pipeline.Expr ceil(com.google.firebase.firestore.pipeline.Expr numericExpr); + method public static final com.google.firebase.firestore.pipeline.Expr ceil(String numericField); method public final com.google.firebase.firestore.pipeline.Expr charLength(); - method public static final com.google.firebase.firestore.pipeline.Expr charLength(com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.Expr charLength(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Expr charLength(String fieldName); - method public static final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); - method public static final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object otherwise); - method public static final com.google.firebase.firestore.pipeline.Expr constant(boolean value); + method public static final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr thenExpr, com.google.firebase.firestore.pipeline.Expr elseExpr); + method public static final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object thenValue, Object elseValue); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr constant(boolean value); + method public static final com.google.firebase.firestore.pipeline.Expr constant(byte[] value); method public static final com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.Blob value); method public static final com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.DocumentReference ref); method public static final com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.GeoPoint value); @@ -916,9 +932,10 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); method public final com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.VectorValue vector); method public final com.google.firebase.firestore.pipeline.Expr cosineDistance(double[] vector); - method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, double[] vector); + method public final com.google.firebase.firestore.pipeline.AggregateFunction count(); method public final com.google.firebase.firestore.pipeline.Ordering descending(); method public final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); @@ -926,28 +943,35 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Expr divide(Object other); method public static final com.google.firebase.firestore.pipeline.Expr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.Expr divide(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.Expr documentId(); + method public static final com.google.firebase.firestore.pipeline.Expr documentId(com.google.firebase.firestore.DocumentReference docRef); + method public static final com.google.firebase.firestore.pipeline.Expr documentId(com.google.firebase.firestore.pipeline.Expr documentPath); + method public static final com.google.firebase.firestore.pipeline.Expr documentId(String documentPath); method public final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector); method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); method public final com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.VectorValue vector); method public final com.google.firebase.firestore.pipeline.Expr dotProduct(double[] vector); - method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(String vectorFieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(String vectorFieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Expr dotProduct(String vectorFieldName, double[] vector); method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr suffix); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr suffix); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, String suffix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, com.google.firebase.firestore.pipeline.Expr suffix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, String suffix); method public final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String suffix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr suffix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, String suffix); method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(Object other); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); + method public final com.google.firebase.firestore.pipeline.BooleanExpr eq(Object value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object value); + method public final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr expression, com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr expression, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, com.google.firebase.firestore.pipeline.Expr arrayExpression); method public static final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, java.util.List values); method public final com.google.firebase.firestore.pipeline.BooleanExpr eqAny(java.util.List values); method public final com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector); @@ -956,26 +980,37 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); method public final com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.VectorValue vector); method public final com.google.firebase.firestore.pipeline.Expr euclideanDistance(double[] vector); - method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, double[] vector); + method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(String vectorFieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(String vectorFieldName, com.google.firebase.firestore.VectorValue vector); + method public static final com.google.firebase.firestore.pipeline.Expr euclideanDistance(String vectorFieldName, double[] vector); method public final com.google.firebase.firestore.pipeline.BooleanExpr exists(); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr exists(String fieldName); method public static final com.google.firebase.firestore.pipeline.Field field(com.google.firebase.firestore.FieldPath fieldPath); method public static final com.google.firebase.firestore.pipeline.Field field(String name); + method public final com.google.firebase.firestore.pipeline.Expr floor(); + method public static final com.google.firebase.firestore.pipeline.Expr floor(com.google.firebase.firestore.pipeline.Expr numericExpr); + method public static final com.google.firebase.firestore.pipeline.Expr floor(String numericField); method public static final com.google.firebase.firestore.pipeline.FunctionExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(Object other); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(Object value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, Object value); method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(Object other); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(Object value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object value); + method public final com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr catchExpr); + method public static final com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr tryExpr, com.google.firebase.firestore.pipeline.Expr catchExpr); + method public static final com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr tryExpr, Object catchValue); + method public final com.google.firebase.firestore.pipeline.Expr ifError(Object catchValue); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(com.google.firebase.firestore.pipeline.Expr value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(String fieldName); method public final com.google.firebase.firestore.pipeline.BooleanExpr isNan(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); @@ -989,47 +1024,40 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNull(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNull(String fieldName); method public final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr pattern); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr stringExpression, String pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr like(String pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, String pattern); - method public final com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr logicalMax(Object other); - method public static final com.google.firebase.firestore.pipeline.Expr logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr logicalMax(String fieldName, Object other); - method public final com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr logicalMin(Object other); - method public static final com.google.firebase.firestore.pipeline.Expr logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr logicalMin(String fieldName, Object other); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMaximum(com.google.firebase.firestore.pipeline.Expr expr, java.lang.Object... others); + method public final com.google.firebase.firestore.pipeline.Expr logicalMaximum(com.google.firebase.firestore.pipeline.Expr... others); + method public final com.google.firebase.firestore.pipeline.Expr logicalMaximum(java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMaximum(String fieldName, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMinimum(com.google.firebase.firestore.pipeline.Expr expr, java.lang.Object... others); + method public final com.google.firebase.firestore.pipeline.Expr logicalMinimum(com.google.firebase.firestore.pipeline.Expr... others); + method public final com.google.firebase.firestore.pipeline.Expr logicalMinimum(java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr logicalMinimum(String fieldName, java.lang.Object... others); method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(Object other); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lt(Object value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, Object right); method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(Object other); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr lte(Object value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object value); method public static final com.google.firebase.firestore.pipeline.Expr map(java.util.Map elements); - method public final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); + method public static final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr mapExpression, String key); method public final com.google.firebase.firestore.pipeline.Expr mapGet(String key); - method public static final com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); method public static final com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, String key); method public static final com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public final com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public static final com.google.firebase.firestore.pipeline.Expr mapMerge(String mapField, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public final com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr mapExpr, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public static final com.google.firebase.firestore.pipeline.Expr mapMerge(String firstMapFieldName, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); method public final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr key); + method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr mapExpr, com.google.firebase.firestore.pipeline.Expr key); method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); method public final com.google.firebase.firestore.pipeline.Expr mapRemove(String key); method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); @@ -1051,15 +1079,24 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(Object other); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, Object right); + method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(Object value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, Object value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr not(com.google.firebase.firestore.pipeline.BooleanExpr condition); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); + method public final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr expression, com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr expression, java.util.List values); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(String fieldName, com.google.firebase.firestore.pipeline.Expr arrayExpression); method public static final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(String fieldName, java.util.List values); method public final com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(java.util.List values); method public static final com.google.firebase.firestore.pipeline.Expr nullValue(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr or(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + method public final com.google.firebase.firestore.pipeline.Expr pow(com.google.firebase.firestore.pipeline.Expr exponent); + method public static final com.google.firebase.firestore.pipeline.Expr pow(com.google.firebase.firestore.pipeline.Expr numericExpr, com.google.firebase.firestore.pipeline.Expr exponent); + method public static final com.google.firebase.firestore.pipeline.Expr pow(com.google.firebase.firestore.pipeline.Expr numericExpr, Number exponent); + method public final com.google.firebase.firestore.pipeline.Expr pow(Number exponent); + method public static final com.google.firebase.firestore.pipeline.Expr pow(String numericField, com.google.firebase.firestore.pipeline.Expr exponent); + method public static final com.google.firebase.firestore.pipeline.Expr pow(String numericField, Number exponent); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); @@ -1085,9 +1122,21 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Expr reverse(); method public static final com.google.firebase.firestore.pipeline.Expr reverse(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Expr reverse(String fieldName); + method public final com.google.firebase.firestore.pipeline.Expr round(); + method public static final com.google.firebase.firestore.pipeline.Expr round(com.google.firebase.firestore.pipeline.Expr numericExpr); + method public static final com.google.firebase.firestore.pipeline.Expr round(String numericField); + method public final com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public static final com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr numericExpr, com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public static final com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr numericExpr, int decimalPlace); + method public final com.google.firebase.firestore.pipeline.Expr roundToDecimal(int decimalPlace); + method public static final com.google.firebase.firestore.pipeline.Expr roundToDecimal(String numericField, com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public static final com.google.firebase.firestore.pipeline.Expr roundToDecimal(String numericField, int decimalPlace); + method public final com.google.firebase.firestore.pipeline.Expr sqrt(); + method public static final com.google.firebase.firestore.pipeline.Expr sqrt(com.google.firebase.firestore.pipeline.Expr numericExpr); + method public static final com.google.firebase.firestore.pipeline.Expr sqrt(String numericField); method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr prefix); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr prefix); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, String prefix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, com.google.firebase.firestore.pipeline.Expr prefix); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, String prefix); method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); @@ -1160,56 +1209,67 @@ package com.google.firebase.firestore.pipeline { } public static final class Expr.Companion { - method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr add(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Expr add(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Object second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr add(String fieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr add(String fieldName, Object second, java.lang.Object... others); method public com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); - method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr... arrays); - method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr array, java.util.List arrays); - method public com.google.firebase.firestore.pipeline.Expr arrayConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... arrays); - method public com.google.firebase.firestore.pipeline.Expr arrayConcat(String fieldName, java.util.List arrays); - method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr value); - method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object value); - method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, com.google.firebase.firestore.pipeline.Expr value); - method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String fieldName, Object value); + method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); + method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, Object secondArray, java.lang.Object... otherArrays); + method public com.google.firebase.firestore.pipeline.Expr arrayConcat(String firstArrayField, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); + method public com.google.firebase.firestore.pipeline.Expr arrayConcat(String firstArrayField, Object secondArray, java.lang.Object... otherArrays); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr element); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(com.google.firebase.firestore.pipeline.Expr array, Object element); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String arrayFieldName, com.google.firebase.firestore.pipeline.Expr element); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContains(String arrayFieldName, Object element); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr arrayExpression); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); - method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String fieldName, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String arrayFieldName, com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAll(String arrayFieldName, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr arrayExpression); method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(com.google.firebase.firestore.pipeline.Expr array, java.util.List values); - method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String fieldName, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String arrayFieldName, com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public com.google.firebase.firestore.pipeline.BooleanExpr arrayContainsAny(String arrayFieldName, java.util.List values); method public com.google.firebase.firestore.pipeline.Expr arrayLength(com.google.firebase.firestore.pipeline.Expr array); - method public com.google.firebase.firestore.pipeline.Expr arrayLength(String fieldName); + method public com.google.firebase.firestore.pipeline.Expr arrayLength(String arrayFieldName); + method public com.google.firebase.firestore.pipeline.Expr arrayOffset(com.google.firebase.firestore.pipeline.Expr array, com.google.firebase.firestore.pipeline.Expr offset); + method public com.google.firebase.firestore.pipeline.Expr arrayOffset(com.google.firebase.firestore.pipeline.Expr array, int offset); + method public com.google.firebase.firestore.pipeline.Expr arrayOffset(String arrayFieldName, com.google.firebase.firestore.pipeline.Expr offset); + method public com.google.firebase.firestore.pipeline.Expr arrayOffset(String arrayFieldName, int offset); method public com.google.firebase.firestore.pipeline.Expr arrayReverse(com.google.firebase.firestore.pipeline.Expr array); - method public com.google.firebase.firestore.pipeline.Expr arrayReverse(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr bitAnd(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr bitAnd(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(String fieldName, int number); - method public com.google.firebase.firestore.pipeline.Expr bitNot(com.google.firebase.firestore.pipeline.Expr left); - method public com.google.firebase.firestore.pipeline.Expr bitNot(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr bitOr(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr bitOr(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr left, int number); - method public com.google.firebase.firestore.pipeline.Expr bitRightShift(String fieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); - method public com.google.firebase.firestore.pipeline.Expr bitRightShift(String fieldName, int number); - method public com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr bitXor(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr bitXor(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.Expr arrayReverse(String arrayFieldName); + method public com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr bits, byte[] bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitAnd(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitAnd(String bitsFieldName, byte[] bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitAnd(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(com.google.firebase.firestore.pipeline.Expr bits, int number); + method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Expr bitLeftShift(String bitsFieldName, int number); + method public com.google.firebase.firestore.pipeline.Expr bitNot(com.google.firebase.firestore.pipeline.Expr bits); + method public com.google.firebase.firestore.pipeline.Expr bitNot(String bitsFieldName); + method public com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr bits, byte[] bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitOr(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitOr(String bitsFieldName, byte[] bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitOr(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Expr bitRightShift(com.google.firebase.firestore.pipeline.Expr bits, int number); + method public com.google.firebase.firestore.pipeline.Expr bitRightShift(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr numberExpr); + method public com.google.firebase.firestore.pipeline.Expr bitRightShift(String bitsFieldName, int number); + method public com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr bits, byte[] bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitXor(String bitsFieldName, byte[] bitsOther); + method public com.google.firebase.firestore.pipeline.Expr bitXor(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr bitsOther); method public com.google.firebase.firestore.pipeline.Expr byteLength(com.google.firebase.firestore.pipeline.Expr value); method public com.google.firebase.firestore.pipeline.Expr byteLength(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr charLength(com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.Expr ceil(com.google.firebase.firestore.pipeline.Expr numericExpr); + method public com.google.firebase.firestore.pipeline.Expr ceil(String numericField); + method public com.google.firebase.firestore.pipeline.Expr charLength(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Expr charLength(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); - method public com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object then, Object otherwise); - method public com.google.firebase.firestore.pipeline.Expr constant(boolean value); + method public com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.Expr thenExpr, com.google.firebase.firestore.pipeline.Expr elseExpr); + method public com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.BooleanExpr condition, Object thenValue, Object elseValue); + method public com.google.firebase.firestore.pipeline.BooleanExpr constant(boolean value); + method public com.google.firebase.firestore.pipeline.Expr constant(byte[] value); method public com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.Blob value); method public com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.DocumentReference ref); method public com.google.firebase.firestore.pipeline.Expr constant(com.google.firebase.firestore.GeoPoint value); @@ -1221,47 +1281,59 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); method public com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); method public com.google.firebase.firestore.pipeline.Expr cosineDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String fieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, double[] vector); method public com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.Expr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); method public com.google.firebase.firestore.pipeline.Expr divide(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr documentId(com.google.firebase.firestore.DocumentReference docRef); + method public com.google.firebase.firestore.pipeline.Expr documentId(com.google.firebase.firestore.pipeline.Expr documentPath); + method public com.google.firebase.firestore.pipeline.Expr documentId(String documentPath); method public com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); method public com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); method public com.google.firebase.firestore.pipeline.Expr dotProduct(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.Expr dotProduct(String fieldName, double[] vector); - method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr suffix); - method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr expr, String suffix); + method public com.google.firebase.firestore.pipeline.Expr dotProduct(String vectorFieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Expr dotProduct(String vectorFieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Expr dotProduct(String vectorFieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, com.google.firebase.firestore.pipeline.Expr suffix); + method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, String suffix); method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr suffix); method public com.google.firebase.firestore.pipeline.BooleanExpr endsWith(String fieldName, String suffix); method public com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr eq(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object right); - method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public com.google.firebase.firestore.pipeline.BooleanExpr eq(String fieldName, Object value); + method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr expression, com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(com.google.firebase.firestore.pipeline.Expr expression, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, com.google.firebase.firestore.pipeline.Expr arrayExpression); method public com.google.firebase.firestore.pipeline.BooleanExpr eqAny(String fieldName, java.util.List values); method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.pipeline.Expr vector2); method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, com.google.firebase.firestore.VectorValue vector2); method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(com.google.firebase.firestore.pipeline.Expr vector1, double[] vector2); - method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, com.google.firebase.firestore.pipeline.Expr vector); - method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, com.google.firebase.firestore.VectorValue vector); - method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(String fieldName, double[] vector); - method public com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(String vectorFieldName, com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(String vectorFieldName, com.google.firebase.firestore.VectorValue vector); + method public com.google.firebase.firestore.pipeline.Expr euclideanDistance(String vectorFieldName, double[] vector); + method public com.google.firebase.firestore.pipeline.BooleanExpr exists(com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.BooleanExpr exists(String fieldName); method public com.google.firebase.firestore.pipeline.Field field(com.google.firebase.firestore.FieldPath fieldPath); method public com.google.firebase.firestore.pipeline.Field field(String name); + method public com.google.firebase.firestore.pipeline.Expr floor(com.google.firebase.firestore.pipeline.Expr numericExpr); + method public com.google.firebase.firestore.pipeline.Expr floor(String numericField); method public com.google.firebase.firestore.pipeline.FunctionExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, Object value); method public com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object value); + method public com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr tryExpr, com.google.firebase.firestore.pipeline.Expr catchExpr); + method public com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr tryExpr, Object catchValue); + method public com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(com.google.firebase.firestore.pipeline.Expr value); + method public com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(com.google.firebase.firestore.pipeline.Expr expr); @@ -1270,34 +1342,28 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr isNotNull(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr isNull(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.BooleanExpr isNull(String fieldName); - method public com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); - method public com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr like(com.google.firebase.firestore.pipeline.Expr stringExpression, String pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr like(String fieldName, String pattern); - method public com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr logicalMax(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr logicalMax(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Expr logicalMax(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr logicalMin(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr logicalMin(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Expr logicalMin(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr logicalMaximum(com.google.firebase.firestore.pipeline.Expr expr, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr logicalMaximum(String fieldName, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr logicalMinimum(com.google.firebase.firestore.pipeline.Expr expr, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr logicalMinimum(String fieldName, java.lang.Object... others); method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr lt(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr right); + method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); method public com.google.firebase.firestore.pipeline.BooleanExpr lt(String fieldName, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr lte(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object value); method public com.google.firebase.firestore.pipeline.Expr map(java.util.Map elements); - method public com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr map, com.google.firebase.firestore.pipeline.Expr key); - method public com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr map, String key); - method public com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr mapExpression, String key); method public com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, String key); method public com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public com.google.firebase.firestore.pipeline.Expr mapMerge(String mapField, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr key); + method public com.google.firebase.firestore.pipeline.Expr mapMerge(String firstMapFieldName, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); + method public com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr mapExpr, com.google.firebase.firestore.pipeline.Expr key); method public com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); method public com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); method public com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, String key); @@ -1311,13 +1377,19 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr multiply(String fieldName, Object other); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, Object right); + method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); + method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, Object value); method public com.google.firebase.firestore.pipeline.BooleanExpr not(com.google.firebase.firestore.pipeline.BooleanExpr condition); - method public com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr value, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr expression, com.google.firebase.firestore.pipeline.Expr arrayExpression); + method public com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(com.google.firebase.firestore.pipeline.Expr expression, java.util.List values); + method public com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(String fieldName, com.google.firebase.firestore.pipeline.Expr arrayExpression); method public com.google.firebase.firestore.pipeline.BooleanExpr notEqAny(String fieldName, java.util.List values); method public com.google.firebase.firestore.pipeline.Expr nullValue(); method public com.google.firebase.firestore.pipeline.BooleanExpr or(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + method public com.google.firebase.firestore.pipeline.Expr pow(com.google.firebase.firestore.pipeline.Expr numericExpr, com.google.firebase.firestore.pipeline.Expr exponent); + method public com.google.firebase.firestore.pipeline.Expr pow(com.google.firebase.firestore.pipeline.Expr numericExpr, Number exponent); + method public com.google.firebase.firestore.pipeline.Expr pow(String numericField, com.google.firebase.firestore.pipeline.Expr exponent); + method public com.google.firebase.firestore.pipeline.Expr pow(String numericField, Number exponent); method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); @@ -1334,8 +1406,16 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr replaceFirst(String fieldName, String find, String replace); method public com.google.firebase.firestore.pipeline.Expr reverse(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Expr reverse(String fieldName); - method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr prefix); - method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr expr, String prefix); + method public com.google.firebase.firestore.pipeline.Expr round(com.google.firebase.firestore.pipeline.Expr numericExpr); + method public com.google.firebase.firestore.pipeline.Expr round(String numericField); + method public com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr numericExpr, com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr numericExpr, int decimalPlace); + method public com.google.firebase.firestore.pipeline.Expr roundToDecimal(String numericField, com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public com.google.firebase.firestore.pipeline.Expr roundToDecimal(String numericField, int decimalPlace); + method public com.google.firebase.firestore.pipeline.Expr sqrt(com.google.firebase.firestore.pipeline.Expr numericExpr); + method public com.google.firebase.firestore.pipeline.Expr sqrt(String numericField); + method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, com.google.firebase.firestore.pipeline.Expr prefix); + method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, String prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); method public com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 9a1af812b31..44e35d146a9 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -600,7 +600,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the round operation. */ @JvmStatic - fun round(numericExpr: Expr, decimalPlace: Int): Expr = + fun roundToDecimal(numericExpr: Expr, decimalPlace: Int): Expr = FunctionExpr("round", numericExpr, constant(decimalPlace)) /** @@ -613,7 +613,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the round operation. */ @JvmStatic - fun round(numericField: String, decimalPlace: Int): Expr = + fun roundToDecimal(numericField: String, decimalPlace: Int): Expr = FunctionExpr("round", numericField, constant(decimalPlace)) /** @@ -626,7 +626,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the round operation. */ @JvmStatic - fun round(numericExpr: Expr, decimalPlace: Expr): Expr = + fun roundToDecimal(numericExpr: Expr, decimalPlace: Expr): Expr = FunctionExpr("round", numericExpr, decimalPlace) /** @@ -639,7 +639,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the round operation. */ @JvmStatic - fun round(numericField: String, decimalPlace: Expr): Expr = + fun roundToDecimal(numericField: String, decimalPlace: Expr): Expr = FunctionExpr("round", numericField, decimalPlace) /** @@ -2570,7 +2570,7 @@ abstract class Expr internal constructor() { * @param decimalPlace The number of decimal places to round. * @return A new [Expr] representing the round operation. */ - fun round(decimalPlace: Int) = Companion.round(this, decimalPlace) + fun roundToDecimal(decimalPlace: Int) = Companion.roundToDecimal(this, decimalPlace) /** * Creates an expression that rounds off this numeric expression to [decimalPlace] decimal places @@ -2580,7 +2580,7 @@ abstract class Expr internal constructor() { * @param decimalPlace The number of decimal places to round. * @return A new [Expr] representing the round operation. */ - fun round(decimalPlace: Expr) = Companion.round(this, decimalPlace) + fun roundToDecimal(decimalPlace: Expr) = Companion.roundToDecimal(this, decimalPlace) /** * Creates an expression that returns the smalled integer that isn't less than this numeric From c320e1e1e024d861251efee90c8f666c9f19cc77 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 5 May 2025 22:45:48 -0400 Subject: [PATCH 58/77] More expression work --- firebase-firestore/api.txt | 98 +++--- .../firestore/pipeline/expressions.kt | 332 +++++++++++++----- 2 files changed, 295 insertions(+), 135 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 5129580877f..4de6a67fff5 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -827,11 +827,11 @@ package com.google.firebase.firestore.pipeline { public abstract class Expr { method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Object second, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Number second, java.lang.Object... others); method public final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public final com.google.firebase.firestore.pipeline.Expr add(Object second, java.lang.Object... others); - method public static final com.google.firebase.firestore.pipeline.Expr add(String fieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public static final com.google.firebase.firestore.pipeline.Expr add(String fieldName, Object second, java.lang.Object... others); + method public final com.google.firebase.firestore.pipeline.Expr add(Number second, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, Number second, java.lang.Object... others); method public com.google.firebase.firestore.pipeline.ExprWithAlias alias(String alias); method public static final com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); @@ -937,12 +937,12 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, double[] vector); method public final com.google.firebase.firestore.pipeline.AggregateFunction count(); method public final com.google.firebase.firestore.pipeline.Ordering descending(); - method public final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr divide(Object other); - method public static final com.google.firebase.firestore.pipeline.Expr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr divide(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr divisor); + method public static final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr dividend, com.google.firebase.firestore.pipeline.Expr divisor); + method public static final com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr dividend, Number divisor); + method public final com.google.firebase.firestore.pipeline.Expr divide(Number divisor); + method public static final com.google.firebase.firestore.pipeline.Expr divide(String dividendFieldName, com.google.firebase.firestore.pipeline.Expr divisor); + method public static final com.google.firebase.firestore.pipeline.Expr divide(String dividendFieldName, Number divisor); method public final com.google.firebase.firestore.pipeline.Expr documentId(); method public static final com.google.firebase.firestore.pipeline.Expr documentId(com.google.firebase.firestore.DocumentReference docRef); method public static final com.google.firebase.firestore.pipeline.Expr documentId(com.google.firebase.firestore.pipeline.Expr documentPath); @@ -1058,24 +1058,24 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Expr mapMerge(String firstMapFieldName, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); method public final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr key); method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr mapExpr, com.google.firebase.firestore.pipeline.Expr key); - method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); + method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr mapExpr, String key); method public final com.google.firebase.firestore.pipeline.Expr mapRemove(String key); method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, String key); method public final com.google.firebase.firestore.pipeline.AggregateFunction max(); method public final com.google.firebase.firestore.pipeline.AggregateFunction min(); - method public final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr mod(Object other); - method public static final com.google.firebase.firestore.pipeline.Expr mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr mod(String fieldName, Object other); - method public final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr multiply(Object other); - method public static final com.google.firebase.firestore.pipeline.Expr multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr multiply(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr divisor); + method public static final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr dividend, com.google.firebase.firestore.pipeline.Expr divisor); + method public static final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr dividend, Number divisor); + method public final com.google.firebase.firestore.pipeline.Expr mod(Number divisor); + method public static final com.google.firebase.firestore.pipeline.Expr mod(String dividendFieldName, com.google.firebase.firestore.pipeline.Expr divisor); + method public static final com.google.firebase.firestore.pipeline.Expr mod(String dividendFieldName, Number divisor); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, Number second, java.lang.Object... others); + method public final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public final com.google.firebase.firestore.pipeline.Expr multiply(Number second, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, Number second, java.lang.Object... others); method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); @@ -1153,12 +1153,12 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); - method public final com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public static final com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public final com.google.firebase.firestore.pipeline.Expr subtract(Object other); - method public static final com.google.firebase.firestore.pipeline.Expr subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public static final com.google.firebase.firestore.pipeline.Expr subtract(String fieldName, Object other); + method public final com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr subtrahend); + method public static final com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr minuend, com.google.firebase.firestore.pipeline.Expr subtrahend); + method public static final com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr minuend, Number subtrahend); + method public final com.google.firebase.firestore.pipeline.Expr subtract(Number subtrahend); + method public static final com.google.firebase.firestore.pipeline.Expr subtract(String numericFieldName, com.google.firebase.firestore.pipeline.Expr subtrahend); + method public static final com.google.firebase.firestore.pipeline.Expr subtract(String numericFieldName, Number subtrahend); method public final com.google.firebase.firestore.pipeline.AggregateFunction sum(); method public final com.google.firebase.firestore.pipeline.Expr timestampAdd(com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); method public static final com.google.firebase.firestore.pipeline.Expr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); @@ -1210,9 +1210,9 @@ package com.google.firebase.firestore.pipeline { public static final class Expr.Companion { method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Object second, java.lang.Object... others); - method public com.google.firebase.firestore.pipeline.Expr add(String fieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public com.google.firebase.firestore.pipeline.Expr add(String fieldName, Object second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Number second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, Number second, java.lang.Object... others); method public com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, Object secondArray, java.lang.Object... otherArrays); @@ -1284,10 +1284,10 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, com.google.firebase.firestore.pipeline.Expr vector); method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, com.google.firebase.firestore.VectorValue vector); method public com.google.firebase.firestore.pipeline.Expr cosineDistance(String vectorFieldName, double[] vector); - method public com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr divide(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Expr divide(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr dividend, com.google.firebase.firestore.pipeline.Expr divisor); + method public com.google.firebase.firestore.pipeline.Expr divide(com.google.firebase.firestore.pipeline.Expr dividend, Number divisor); + method public com.google.firebase.firestore.pipeline.Expr divide(String dividendFieldName, com.google.firebase.firestore.pipeline.Expr divisor); + method public com.google.firebase.firestore.pipeline.Expr divide(String dividendFieldName, Number divisor); method public com.google.firebase.firestore.pipeline.Expr documentId(com.google.firebase.firestore.DocumentReference docRef); method public com.google.firebase.firestore.pipeline.Expr documentId(com.google.firebase.firestore.pipeline.Expr documentPath); method public com.google.firebase.firestore.pipeline.Expr documentId(String documentPath); @@ -1364,17 +1364,17 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); method public com.google.firebase.firestore.pipeline.Expr mapMerge(String firstMapFieldName, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); method public com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr mapExpr, com.google.firebase.firestore.pipeline.Expr key); - method public com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr firstMap, String key); + method public com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr mapExpr, String key); method public com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); method public com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, String key); - method public com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr mod(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Expr mod(String fieldName, Object other); - method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr multiply(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Expr multiply(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr dividend, com.google.firebase.firestore.pipeline.Expr divisor); + method public com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr dividend, Number divisor); + method public com.google.firebase.firestore.pipeline.Expr mod(String dividendFieldName, com.google.firebase.firestore.pipeline.Expr divisor); + method public com.google.firebase.firestore.pipeline.Expr mod(String dividendFieldName, Number divisor); + method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, Number second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, Number second, java.lang.Object... others); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); @@ -1426,10 +1426,10 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, String substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); - method public com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); - method public com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr left, Object right); - method public com.google.firebase.firestore.pipeline.Expr subtract(String fieldName, com.google.firebase.firestore.pipeline.Expr other); - method public com.google.firebase.firestore.pipeline.Expr subtract(String fieldName, Object other); + method public com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr minuend, com.google.firebase.firestore.pipeline.Expr subtrahend); + method public com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr minuend, Number subtrahend); + method public com.google.firebase.firestore.pipeline.Expr subtract(String numericFieldName, com.google.firebase.firestore.pipeline.Expr subtrahend); + method public com.google.firebase.firestore.pipeline.Expr subtract(String numericFieldName, Number subtrahend); method public com.google.firebase.firestore.pipeline.Expr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); method public com.google.firebase.firestore.pipeline.Expr timestampAdd(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); method public com.google.firebase.firestore.pipeline.Expr timestampAdd(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 44e35d146a9..d33f41dddda 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -325,8 +325,13 @@ abstract class Expr internal constructor() { fun xor(condition: BooleanExpr, vararg conditions: BooleanExpr) = BooleanExpr("xor", condition, *conditions) - /** @return A new [Expr] representing the not operation. */ - @JvmStatic fun not(condition: BooleanExpr) = BooleanExpr("not", condition) + /** + * Creates an expression that negates a boolean expression. + * + * @param condition The boolean expression to negate. + * @return A new [Expr] representing the not operation. + */ + @JvmStatic fun not(condition: BooleanExpr): BooleanExpr = BooleanExpr("not", condition) /** * Creates an expression that applies a bitwise AND operation between two expressions. @@ -742,11 +747,11 @@ abstract class Expr internal constructor() { @JvmStatic fun sqrt(numericField: String): Expr = FunctionExpr("sqrt", numericField) /** - * Creates an expression that adds this expression to another expression. + * Creates an expression that adds numeric expressions and constants. * - * @param first The first expression to add. - * @param second The second expression to add to first expression. - * @param others Additional expression or literal to add. + * @param first Numeric expression to add. + * @param second Numeric expression to add. + * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ @JvmStatic @@ -754,116 +759,219 @@ abstract class Expr internal constructor() { FunctionExpr("add", first, second, *others) /** - * Creates an expression that adds this expression to another expression. + * Creates an expression that adds numeric expressions and constants. * - * @param first The first expression to add. - * @param second The second expression or literal to add to first expression. - * @param others Additional expression or literal to add. + * @param first Numeric expression to add. + * @param second Constant to add. + * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ @JvmStatic - fun add(first: Expr, second: Any, vararg others: Any): Expr = + fun add(first: Expr, second: Number, vararg others: Any): Expr = FunctionExpr("add", first, second, *others) /** - * Creates an expression that adds a field's value to an expression. + * Creates an expression that adds a numeric field with numeric expressions and constants. * - * @param fieldName The name of the field containing the value to add. - * @param second The second expression to add to field value. - * @param others Additional expression or literal to add. + * @param numericFieldName Numeric field to add. + * @param second Numeric expression to add to field value. + * @param others Additional numeric expressions or constants to add. + * @return A new [Expr] representing the addition operation. */ @JvmStatic - fun add(fieldName: String, second: Expr, vararg others: Any): Expr = - FunctionExpr("add", fieldName, second, *others) + fun add(numericFieldName: String, second: Expr, vararg others: Any): Expr = + FunctionExpr("add", numericFieldName, second, *others) /** - * Creates an expression that adds a field's value to an expression. + * Creates an expression that adds a numeric field with numeric expressions and constants. * - * @param fieldName The name of the field containing the value to add. - * @param second The second expression or literal to add to field value. - * @param others Additional expression or literal to add. + * @param numericFieldName Numeric field to add. + * @param second Constant to add. + * @param others Additional numeric expressions or constants to add. + * @return A new [Expr] representing the addition operation. */ @JvmStatic - fun add(fieldName: String, second: Any, vararg others: Any): Expr = - FunctionExpr("add", fieldName, second, *others) + fun add(numericFieldName: String, second: Number, vararg others: Any): Expr = + FunctionExpr("add", numericFieldName, second, *others) - /** @return A new [Expr] representing the subtract operation. */ - @JvmStatic fun subtract(left: Expr, right: Expr): Expr = FunctionExpr("subtract", left, right) + /** + * Creates an expression that subtracts two expressions. + * + * @param minuend Numeric expression to subtract from. + * @param subtrahend Numeric expression to subtract. + * @return A new [Expr] representing the subtract operation. + */ + @JvmStatic + fun subtract(minuend: Expr, subtrahend: Expr): Expr = + FunctionExpr("subtract", minuend, subtrahend) - /** @return A new [Expr] representing the subtract operation. */ - @JvmStatic fun subtract(left: Expr, right: Any): Expr = FunctionExpr("subtract", left, right) + /** + * Creates an expression that subtracts a constant value from a numeric expression. + * + * @param minuend Numeric expression to subtract from. + * @param subtrahend Constant to subtract. + * @return A new [Expr] representing the subtract operation. + */ + @JvmStatic + fun subtract(minuend: Expr, subtrahend: Number): Expr = + FunctionExpr("subtract", minuend, subtrahend) - /** @return A new [Expr] representing the subtract operation. */ + /** + * Creates an expression that subtracts a numeric expressions from numeric field. + * + * @param numericFieldName Numeric field to subtract from. + * @param subtrahend Numeric expression to subtract. + * @return A new [Expr] representing the subtract operation. + */ @JvmStatic - fun subtract(fieldName: String, other: Expr): Expr = FunctionExpr("subtract", fieldName, other) + fun subtract(numericFieldName: String, subtrahend: Expr): Expr = + FunctionExpr("subtract", numericFieldName, subtrahend) - /** @return A new [Expr] representing the subtract operation. */ + /** + * Creates an expression that subtracts a constant from numeric field. + * + * @param numericFieldName Numeric field to subtract from. + * @param subtrahend Constant to subtract. + * @return A new [Expr] representing the subtract operation. + */ @JvmStatic - fun subtract(fieldName: String, other: Any): Expr = FunctionExpr("subtract", fieldName, other) + fun subtract(numericFieldName: String, subtrahend: Number): Expr = + FunctionExpr("subtract", numericFieldName, subtrahend) - /** @return A new [Expr] representing the multiply operation. */ - @JvmStatic fun multiply(left: Expr, right: Expr): Expr = FunctionExpr("multiply", left, right) + /** + * Creates an expression that multiplies numeric expressions and constants. + * + * @param first Numeric expression to multiply. + * @param second Numeric expression to multiply. + * @param others Additional numeric expressions or constants to multiply. + * @return A new [Expr] representing the multiplication operation. + */ + @JvmStatic + fun multiply(first: Expr, second: Expr, vararg others: Any): Expr = + FunctionExpr("multiply", first, second, *others) - /** @return A new [Expr] representing the multiply operation. */ - @JvmStatic fun multiply(left: Expr, right: Any): Expr = FunctionExpr("multiply", left, right) + /** + * Creates an expression that multiplies numeric expressions and constants. + * + * @param first Numeric expression to multiply. + * @param second Constant to multiply. + * @param others Additional numeric expressions or constants to multiply. + * @return A new [Expr] representing the multiplication operation. + */ + @JvmStatic + fun multiply(first: Expr, second: Number, vararg others: Any): Expr = + FunctionExpr("multiply", first, second, *others) - /** @return A new [Expr] representing the multiply operation. */ + /** + * Creates an expression that multiplies a numeric field with numeric expressions and constants. + * + * @param numericFieldName Numeric field to multiply. + * @param second Numeric expression to add to field multiply. + * @param others Additional numeric expressions or constants to multiply. + * @return A new [Expr] representing the multiplication operation. + */ @JvmStatic - fun multiply(fieldName: String, other: Expr): Expr = FunctionExpr("multiply", fieldName, other) + fun multiply(numericFieldName: String, second: Expr, vararg others: Any): Expr = + FunctionExpr("multiply", numericFieldName, second, *others) - /** @return A new [Expr] representing the multiply operation. */ + /** + * Creates an expression that multiplies a numeric field with numeric expressions and constants. + * + * @param numericFieldName Numeric field to multiply. + * @param second Constant to multiply. + * @param others Additional numeric expressions or constants to multiply. + * @return A new [Expr] representing the multiplication operation. + */ @JvmStatic - fun multiply(fieldName: String, other: Any): Expr = FunctionExpr("multiply", fieldName, other) + fun multiply(numericFieldName: String, second: Number, vararg others: Any): Expr = + FunctionExpr("multiply", numericFieldName, second, *others) /** - * Creates an expression that divides two expressions. + * Creates an expression that divides two numeric expressions. * - * @param left The expression to be divided. - * @param right The expression to divide by. + * @param dividend The numeric expression to be divided. + * @param divisor The numeric expression to divide by. * @return A new [Expr] representing the division operation. */ - @JvmStatic fun divide(left: Expr, right: Expr): Expr = FunctionExpr("divide", left, right) + @JvmStatic + fun divide(dividend: Expr, divisor: Expr): Expr = FunctionExpr("divide", dividend, divisor) /** - * Creates an expression that divides an expression by an expression by a value. + * Creates an expression that divides a numeric expression by a constant. * - * @param left The expression to be divided. - * @param right The value to divide by. + * @param dividend The numeric expression to be divided. + * @param divisor The constant to divide by. * @return A new [Expr] representing the division operation. */ - @JvmStatic fun divide(left: Expr, right: Any): Expr = FunctionExpr("divide", left, right) + @JvmStatic + fun divide(dividend: Expr, divisor: Number): Expr = FunctionExpr("divide", dividend, divisor) /** - * Creates an expression that divides a field's value by an expression. + * Creates an expression that divides numeric field by a numeric expression. * - * @param fieldName The field name to be divided. - * @param other The expression to divide by. + * @param dividendFieldName The numeric field name to be divided. + * @param divisor The numeric expression to divide by. * @return A new [Expr] representing the divide operation. */ @JvmStatic - fun divide(fieldName: String, other: Expr): Expr = FunctionExpr("divide", fieldName, other) + fun divide(dividendFieldName: String, divisor: Expr): Expr = + FunctionExpr("divide", dividendFieldName, divisor) /** - * Creates an expression that divides a field's value by a value. + * Creates an expression that divides a numeric field by a constant. * - * @param fieldName The field name to be divided. - * @param other The value to divide by. + * @param dividendFieldName The numeric field name to be divided. + * @param divisor The constant to divide by. * @return A new [Expr] representing the divide operation. */ @JvmStatic - fun divide(fieldName: String, other: Any): Expr = FunctionExpr("divide", fieldName, other) + fun divide(dividendFieldName: String, divisor: Number): Expr = + FunctionExpr("divide", dividendFieldName, divisor) - /** @return A new [Expr] representing the mod operation. */ - @JvmStatic fun mod(left: Expr, right: Expr): Expr = FunctionExpr("mod", left, right) + /** + * Creates an expression that calculates the modulo (remainder) of dividing two numeric + * expressions. + * + * @param dividend The numeric expression to be divided. + * @param divisor The numeric expression to divide by. + * @return A new [Expr] representing the modulo operation. + */ + @JvmStatic fun mod(dividend: Expr, divisor: Expr): Expr = FunctionExpr("mod", dividend, divisor) - /** @return A new [Expr] representing the mod operation. */ - @JvmStatic fun mod(left: Expr, right: Any): Expr = FunctionExpr("mod", left, right) + /** + * Creates an expression that calculates the modulo (remainder) of dividing a numeric expression + * by a constant. + * + * @param dividend The numeric expression to be divided. + * @param divisor The constant to divide by. + * @return A new [Expr] representing the modulo operation. + */ + @JvmStatic + fun mod(dividend: Expr, divisor: Number): Expr = FunctionExpr("mod", dividend, divisor) - /** @return A new [Expr] representing the mod operation. */ - @JvmStatic fun mod(fieldName: String, other: Expr): Expr = FunctionExpr("mod", fieldName, other) + /** + * Creates an expression that calculates the modulo (remainder) of dividing a numeric field by a + * constant. + * + * @param dividendFieldName The numeric field name to be divided. + * @param divisor The numeric expression to divide by. + * @return A new [Expr] representing the modulo operation. + */ + @JvmStatic + fun mod(dividendFieldName: String, divisor: Expr): Expr = + FunctionExpr("mod", dividendFieldName, divisor) - /** @return A new [Expr] representing the mod operation. */ - @JvmStatic fun mod(fieldName: String, other: Any): Expr = FunctionExpr("mod", fieldName, other) + /** + * Creates an expression that calculates the modulo (remainder) of dividing a numeric field by a + * constant. + * + * @param dividendFieldName The numeric field name to be divided. + * @param divisor The constant to divide by. + * @return A new [Expr] representing the modulo operation. + */ + @JvmStatic + fun mod(dividendFieldName: String, divisor: Number): Expr = + FunctionExpr("mod", dividendFieldName, divisor) /** * Creates an expression that checks if an [expression], when evaluated, is equal to any of the @@ -1463,7 +1571,7 @@ abstract class Expr internal constructor() { /** * Creates an expression that removes a key from the map produced by evaluating an expression. * - * @param mapExpr An expression return a map value. + * @param mapExpr An expression that evaluates to a map. * @param key The name of the key to remove from the input map. * @return A new [Expr] that evaluates to a modified map. */ @@ -1480,11 +1588,23 @@ abstract class Expr internal constructor() { @JvmStatic fun mapRemove(mapField: String, key: Expr): Expr = FunctionExpr("map_remove", mapField, key) - /** @return A new [Expr] representing the mapRemove operation. */ + /** + * Creates an expression that removes a key from the map produced by evaluating an expression. + * + * @param mapExpr An expression that evaluates to a map. + * @param key The name of the key to remove from the input map. + * @return A new [Expr] that evaluates to a modified map. + */ @JvmStatic - fun mapRemove(firstMap: Expr, key: String): Expr = FunctionExpr("map_remove", firstMap, key) + fun mapRemove(mapExpr: Expr, key: String): Expr = FunctionExpr("map_remove", mapExpr, key) - /** @return A new [Expr] representing the mapRemove operation. */ + /** + * Creates an expression that removes a key from the map produced by evaluating an expression. + * + * @param mapField The name of a field containing a map value. + * @param key The name of the key to remove from the input map. + * @return A new [Expr] that evaluates to a modified map. + */ @JvmStatic fun mapRemove(mapField: String, key: String): Expr = FunctionExpr("map_remove", mapField, key) @@ -2496,62 +2616,94 @@ abstract class Expr internal constructor() { fun documentId(): Expr = Companion.documentId(this) /** - * Creates an expression that adds this expression to another expression. + * Creates an expression that adds this numeric expression to other numeric expressions and + * constants. * - * @param second The second expression to add to this expression. - * @param others Additional expression or literal to add to this expression. + * @param second Numeric expression to add. + * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ fun add(second: Expr, vararg others: Any) = Companion.add(this, second, *others) /** - * Creates an expression that adds this expression to another expression. + * Creates an expression that adds this numeric expression to other numeric expressions and + * constants. * - * @param second The second expression or literal to add to this expression. - * @param others Additional expression or literal to add to this expression. + * @param second Constant to add. + * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ - fun add(second: Any, vararg others: Any) = Companion.add(this, second, *others) + fun add(second: Number, vararg others: Any) = Companion.add(this, second, *others) /** + * Creates an expression that subtracts a constant from this numeric expression. + * + * @param subtrahend Numeric expression to subtract. + * @return A new [Expr] representing the subtract operation. */ - fun subtract(other: Expr) = Companion.subtract(this, other) + fun subtract(subtrahend: Expr) = Companion.subtract(this, subtrahend) /** + * Creates an expression that subtracts a numeric expressions from this numeric expression. + * + * @param subtrahend Constant to subtract. + * @return A new [Expr] representing the subtract operation. */ - fun subtract(other: Any) = Companion.subtract(this, other) + fun subtract(subtrahend: Number) = Companion.subtract(this, subtrahend) /** + * Creates an expression that multiplies this numeric expression to other numeric expressions and + * constants. + * + * @param second Numeric expression to multiply. + * @param others Additional numeric expressions or constants to multiply. + * @return A new [Expr] representing the multiplication operation. */ - fun multiply(other: Expr) = Companion.multiply(this, other) + fun multiply(second: Expr, vararg others: Any) = Companion.multiply(this, second, *others) /** + * Creates an expression that multiplies this numeric expression to other numeric expressions and + * constants. + * + * @param second Constant to multiply. + * @param others Additional numeric expressions or constants to multiply. + * @return A new [Expr] representing the multiplication operation. */ - fun multiply(other: Any) = Companion.multiply(this, other) + fun multiply(second: Number, vararg others: Any) = Companion.multiply(this, second, *others) /** - * Creates an expression that divides this expression by another expression. + * Creates an expression that divides this numeric expression by another numeric expression. * - * @param other The expression to divide by. + * @param divisor Numeric expression to divide this numeric expression by. * @return A new [Expr] representing the division operation. */ - fun divide(other: Expr) = Companion.divide(this, other) + fun divide(divisor: Expr) = Companion.divide(this, divisor) /** - * Creates an expression that divides this expression by a value. + * Creates an expression that divides this numeric expression by a constant. * - * @param other The value to divide by. + * @param divisor Constant to divide this expression by. * @return A new [Expr] representing the division operation. */ - fun divide(other: Any) = Companion.divide(this, other) + fun divide(divisor: Number) = Companion.divide(this, divisor) /** + * Creates an expression that calculates the modulo (remainder) of dividing this numeric + * expressions by another numeric expression. + * + * @param divisor The numeric expression to divide this expression by. + * @return A new [Expr] representing the modulo operation. */ - fun mod(other: Expr) = Companion.mod(this, other) + fun mod(divisor: Expr) = Companion.mod(this, divisor) /** + * Creates an expression that calculates the modulo (remainder) of dividing this numeric + * expressions by a constant. + * + * @param divisor The constant to divide this expression by. + * @return A new [Expr] representing the modulo operation. */ - fun mod(other: Any) = Companion.mod(this, other) + fun mod(divisor: Number) = Companion.mod(this, divisor) /** * Creates an expression that rounds this numeric expression to nearest integer. @@ -2887,10 +3039,18 @@ abstract class Expr internal constructor() { Companion.mapMerge(this, mapExpr, *otherMaps) /** + * Creates an expression that removes a key from this map expression. + * + * @param key The name of the key to remove from this map expression. + * @return A new [Expr] that evaluates to a modified map. */ fun mapRemove(key: Expr) = Companion.mapRemove(this, key) /** + * Creates an expression that removes a key from this map expression. + * + * @param key The name of the key to remove from this map expression. + * @return A new [Expr] that evaluates to a modified map. */ fun mapRemove(key: String) = Companion.mapRemove(this, key) From 8a81354869015a4d3ada32c6c2a286c4a71441aa Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 6 May 2025 12:00:58 -0400 Subject: [PATCH 59/77] More expression work --- firebase-firestore/api.txt | 42 +-- .../firestore/pipeline/expressions.kt | 285 +++++++++++++++--- 2 files changed, 267 insertions(+), 60 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 4de6a67fff5..15ce01132b9 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -1097,30 +1097,33 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Expr pow(Number exponent); method public static final com.google.firebase.firestore.pipeline.Expr pow(String numericField, com.google.firebase.firestore.pipeline.Expr exponent); method public static final com.google.firebase.firestore.pipeline.Expr pow(String numericField, Number exponent); + method public static final com.google.firebase.firestore.pipeline.Expr rand(); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr pattern); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr stringExpression, String pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, String pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr pattern); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr pattern); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr stringExpression, String pattern); method public final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public static final com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, String pattern); method public final com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public static final com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public static final com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr stringExpression, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceAll(String fieldName, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); method public final com.google.firebase.firestore.pipeline.Expr replaceAll(String find, String replace); method public static final com.google.firebase.firestore.pipeline.Expr replaceAll(String fieldName, String find, String replace); method public final com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public static final com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public static final com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr stringExpression, String find, String replace); + method public static final com.google.firebase.firestore.pipeline.Expr replaceFirst(String fieldName, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); method public final com.google.firebase.firestore.pipeline.Expr replaceFirst(String find, String replace); method public static final com.google.firebase.firestore.pipeline.Expr replaceFirst(String fieldName, String find, String replace); method public final com.google.firebase.firestore.pipeline.Expr reverse(); - method public static final com.google.firebase.firestore.pipeline.Expr reverse(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Expr reverse(com.google.firebase.firestore.pipeline.Expr stringExpression); method public static final com.google.firebase.firestore.pipeline.Expr reverse(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr round(); method public static final com.google.firebase.firestore.pipeline.Expr round(com.google.firebase.firestore.pipeline.Expr numericExpr); @@ -1390,21 +1393,24 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr pow(com.google.firebase.firestore.pipeline.Expr numericExpr, Number exponent); method public com.google.firebase.firestore.pipeline.Expr pow(String numericField, com.google.firebase.firestore.pipeline.Expr exponent); method public com.google.firebase.firestore.pipeline.Expr pow(String numericField, Number exponent); - method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); - method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public com.google.firebase.firestore.pipeline.Expr rand(); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(com.google.firebase.firestore.pipeline.Expr stringExpression, String pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexContains(String fieldName, String pattern); - method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr pattern); - method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr expr, String pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr pattern); + method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(com.google.firebase.firestore.pipeline.Expr stringExpression, String pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, com.google.firebase.firestore.pipeline.Expr pattern); method public com.google.firebase.firestore.pipeline.BooleanExpr regexMatch(String fieldName, String pattern); - method public com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public com.google.firebase.firestore.pipeline.Expr replaceAll(com.google.firebase.firestore.pipeline.Expr stringExpression, String find, String replace); + method public com.google.firebase.firestore.pipeline.Expr replaceAll(String fieldName, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); method public com.google.firebase.firestore.pipeline.Expr replaceAll(String fieldName, String find, String replace); - method public com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); - method public com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr value, String find, String replace); + method public com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); + method public com.google.firebase.firestore.pipeline.Expr replaceFirst(com.google.firebase.firestore.pipeline.Expr stringExpression, String find, String replace); + method public com.google.firebase.firestore.pipeline.Expr replaceFirst(String fieldName, com.google.firebase.firestore.pipeline.Expr find, com.google.firebase.firestore.pipeline.Expr replace); method public com.google.firebase.firestore.pipeline.Expr replaceFirst(String fieldName, String find, String replace); - method public com.google.firebase.firestore.pipeline.Expr reverse(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Expr reverse(com.google.firebase.firestore.pipeline.Expr stringExpression); method public com.google.firebase.firestore.pipeline.Expr reverse(String fieldName); method public com.google.firebase.firestore.pipeline.Expr round(com.google.firebase.firestore.pipeline.Expr numericExpr); method public com.google.firebase.firestore.pipeline.Expr round(String numericField); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index d33f41dddda..4bc8983da21 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -1156,32 +1156,111 @@ abstract class Expr internal constructor() { */ @JvmStatic fun isNotNull(fieldName: String): BooleanExpr = BooleanExpr("is_not_null", fieldName) - /** @return A new [Expr] representing the replaceFirst operation. */ + /** + * Creates an expression that replaces the first occurrence of a substring within the + * [stringExpression]. + * + * @param stringExpression The expression representing the string to perform the replacement on. + * @param find The expression representing the substring to search for in [stringExpression]. + * @param replace The expression representing the replacement for the first occurrence of [find] + * . + * @return A new [Expr] representing the string with the first occurrence replaced. + */ @JvmStatic - fun replaceFirst(value: Expr, find: Expr, replace: Expr): Expr = - FunctionExpr("replace_first", value, find, replace) + fun replaceFirst(stringExpression: Expr, find: Expr, replace: Expr): Expr = + FunctionExpr("replace_first", stringExpression, find, replace) - /** @return A new [Expr] representing the replaceFirst operation. */ + /** + * Creates an expression that replaces the first occurrence of a substring within the + * [stringExpression]. + * + * @param stringExpression The expression representing the string to perform the replacement on. + * @param find The substring to search for in [stringExpression]. + * @param replace The replacement for the first occurrence of [find] with. + * @return A new [Expr] representing the string with the first occurrence replaced. + */ @JvmStatic - fun replaceFirst(value: Expr, find: String, replace: String): Expr = - FunctionExpr("replace_first", value, find, replace) + fun replaceFirst(stringExpression: Expr, find: String, replace: String): Expr = + FunctionExpr("replace_first", stringExpression, find, replace) - /** @return A new [Expr] representing the replaceFirst operation. */ + /** + * Creates an expression that replaces the first occurrence of a substring within the specified + * string field. + * + * @param fieldName The name of the field representing the string to perform the replacement on. + * @param find The expression representing the substring to search for in specified string + * field. + * @param replace The expression representing the replacement for the first occurrence of [find] + * with. + * @return A new [Expr] representing the string with the first occurrence replaced. + */ + @JvmStatic + fun replaceFirst(fieldName: String, find: Expr, replace: Expr): Expr = + FunctionExpr("replace_first", fieldName, find, replace) + + /** + * Creates an expression that replaces the first occurrence of a substring within the specified + * string field. + * + * @param fieldName The name of the field representing the string to perform the replacement on. + * @param find The substring to search for in specified string field. + * @param replace The replacement for the first occurrence of [find] with. + * @return A new [Expr] representing the string with the first occurrence replaced. + */ @JvmStatic fun replaceFirst(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_first", fieldName, find, replace) - /** @return A new [Expr] representing the replaceAll operation. */ + /** + * Creates an expression that replaces all occurrences of a substring within the + * [stringExpression]. + * + * @param stringExpression The expression representing the string to perform the replacement on. + * @param find The expression representing the substring to search for in [stringExpression]. + * @param replace The expression representing the replacement for all occurrences of [find]. + * @return A new [Expr] representing the string with all occurrences replaced. + */ + @JvmStatic + fun replaceAll(stringExpression: Expr, find: Expr, replace: Expr): Expr = + FunctionExpr("replace_all", stringExpression, find, replace) + + /** + * Creates an expression that replaces all occurrences of a substring within the + * [stringExpression]. + * + * @param stringExpression The expression representing the string to perform the replacement on. + * @param find The substring to search for in [stringExpression]. + * @param replace The replacement for all occurrences of [find] with. + * @return A new [Expr] representing the string with all occurrences replaced. + */ @JvmStatic - fun replaceAll(value: Expr, find: Expr, replace: Expr): Expr = - FunctionExpr("replace_all", value, find, replace) + fun replaceAll(stringExpression: Expr, find: String, replace: String): Expr = + FunctionExpr("replace_all", stringExpression, find, replace) - /** @return A new [Expr] representing the replaceAll operation. */ + /** + * Creates an expression that replaces all occurrences of a substring within the specified + * string field. + * + * @param fieldName The name of the field representing the string to perform the replacement on. + * @param find The expression representing the substring to search for in specified string + * field. + * @param replace The expression representing the replacement for all occurrences of [find] + * with. + * @return A new [Expr] representing the string with all occurrences replaced. + */ @JvmStatic - fun replaceAll(value: Expr, find: String, replace: String): Expr = - FunctionExpr("replace_all", value, find, replace) + fun replaceAll(fieldName: String, find: Expr, replace: Expr): Expr = + FunctionExpr("replace_all", fieldName, find, replace) - /** @return A new [Expr] representing the replaceAll operation. */ + /** + * Creates an expression that replaces all occurrences of a substring within the specified + * string field. + * + * @param fieldName The name of the field representing the string to perform the replacement on. + * @param find The substring to search for in specified string field. + * @param replace The replacement for all occurrences of [find] with. + * @return A new [Expr] representing the string with all occurrences replaced. + */ @JvmStatic fun replaceAll(fieldName: String, find: String, replace: String): Expr = FunctionExpr("replace_all", fieldName, find, replace) @@ -1266,42 +1345,102 @@ abstract class Expr internal constructor() { fun like(fieldName: String, pattern: String): BooleanExpr = BooleanExpr("like", fieldName, pattern) - /** @return A new [Expr] representing the regexContains operation. */ + /** + * Creates an expression that return a pseudo-random number of type double in the range of [0, + * 1), inclusive of 0 and exclusive of 1. + * + * @return A new [Expr] representing the random number operation. + */ + @JvmStatic fun rand(): Expr = FunctionExpr("rand") + + /** + * Creates an expression that checks if a string expression contains a specified regular + * expression as a substring. + * + * @param stringExpression The expression representing the string to perform the comparison on. + * @param pattern The regular expression to use for the search. + * @return A new [BooleanExpr] representing the contains regular expression comparison. + */ @JvmStatic - fun regexContains(expr: Expr, pattern: Expr): BooleanExpr = - BooleanExpr("regex_contains", expr, pattern) + fun regexContains(stringExpression: Expr, pattern: Expr): BooleanExpr = + BooleanExpr("regex_contains", stringExpression, pattern) - /** @return A new [Expr] representing the regexContains operation. */ + /** + * Creates an expression that checks if a string expression contains a specified regular + * expression as a substring. + * + * @param stringExpression The expression representing the string to perform the comparison on. + * @param pattern The regular expression to use for the search. + * @return A new [BooleanExpr] representing the contains regular expression comparison. + */ @JvmStatic - fun regexContains(expr: Expr, pattern: String): BooleanExpr = - BooleanExpr("regex_contains", expr, pattern) + fun regexContains(stringExpression: Expr, pattern: String): BooleanExpr = + BooleanExpr("regex_contains", stringExpression, pattern) - /** @return A new [Expr] representing the regexContains operation. */ + /** + * Creates an expression that checks if a string field contains a specified regular expression + * as a substring. + * + * @param fieldName The name of the field containing the string. + * @param pattern The regular expression to use for the search. + * @return A new [BooleanExpr] representing the contains regular expression comparison. + */ @JvmStatic fun regexContains(fieldName: String, pattern: Expr) = BooleanExpr("regex_contains", fieldName, pattern) - /** @return A new [Expr] representing the regexContains operation. */ + /** + * Creates an expression that checks if a string field contains a specified regular expression + * as a substring. + * + * @param fieldName The name of the field containing the string. + * @param pattern The regular expression to use for the search. + * @return A new [BooleanExpr] representing the contains regular expression comparison. + */ @JvmStatic fun regexContains(fieldName: String, pattern: String) = BooleanExpr("regex_contains", fieldName, pattern) - /** @return A new [Expr] representing the regexMatch operation. */ + /** + * Creates an expression that checks if a string field matches a specified regular expression. + * + * @param stringExpression The expression representing the string to match against. + * @param pattern The regular expression to use for the match. + * @return A new [BooleanExpr] representing the regular expression match comparison. + */ @JvmStatic - fun regexMatch(expr: Expr, pattern: Expr): BooleanExpr = - BooleanExpr("regex_match", expr, pattern) + fun regexMatch(stringExpression: Expr, pattern: Expr): BooleanExpr = + BooleanExpr("regex_match", stringExpression, pattern) - /** @return A new [Expr] representing the regexMatch operation. */ + /** + * Creates an expression that checks if a string field matches a specified regular expression. + * + * @param stringExpression The expression representing the string to match against. + * @param pattern The regular expression to use for the match. + * @return A new [BooleanExpr] representing the regular expression match comparison. + */ @JvmStatic - fun regexMatch(expr: Expr, pattern: String): BooleanExpr = - BooleanExpr("regex_match", expr, pattern) + fun regexMatch(stringExpression: Expr, pattern: String): BooleanExpr = + BooleanExpr("regex_match", stringExpression, pattern) - /** @return A new [Expr] representing the regexMatch operation. */ + /** + * Creates an expression that checks if a string field matches a specified regular expression. + * + * @param fieldName The name of the field containing the string. + * @param pattern The regular expression to use for the match. + * @return A new [BooleanExpr] representing the regular expression match comparison. + */ @JvmStatic fun regexMatch(fieldName: String, pattern: Expr) = BooleanExpr("regex_match", fieldName, pattern) - /** @return A new [Expr] representing the regexMatch operation. */ + /** + * Creates an expression that checks if a string field matches a specified regular expression. + * + * @param fieldName The name of the field containing the string. + * @param pattern The regular expression to use for the match. + * @return A new [BooleanExpr] representing the regular expression match comparison. + */ @JvmStatic fun regexMatch(fieldName: String, pattern: String) = BooleanExpr("regex_match", fieldName, pattern) @@ -1354,13 +1493,27 @@ abstract class Expr internal constructor() { fun logicalMinimum(fieldName: String, vararg others: Any): Expr = FunctionExpr("logical_min", fieldName, *others) - /** @return A new [Expr] representing the reverse operation. */ - @JvmStatic fun reverse(expr: Expr): Expr = FunctionExpr("reverse", expr) + /** + * Creates an expression that reverses a string. + * + * @param stringExpression An expression evaluating to a string value, which will be reversed. + * @return A new [Expr] representing the reversed string. + */ + @JvmStatic fun reverse(stringExpression: Expr): Expr = FunctionExpr("reverse", stringExpression) - /** @return A new [Expr] representing the reverse operation. */ + /** + * Creates an expression that reverses a string value from the specified field. + * + * @param fieldName The name of the field that contains the string to reverse. + * @return A new [Expr] representing the reversed string. + */ @JvmStatic fun reverse(fieldName: String): Expr = FunctionExpr("reverse", fieldName) - /** @return A new [Expr] representing the strContains operation. */ + /** + * Creates an expression that checks if a string expression contains a specified substring. + * + * @return A new [BooleanExpr] representing the contains comparison. + */ @JvmStatic fun strContains(expr: Expr, substring: Expr): BooleanExpr = BooleanExpr("str_contains", expr, substring) @@ -2712,7 +2865,7 @@ abstract class Expr internal constructor() { * * @return A new [Expr] representing an integer result from the round operation. */ - fun round() = Companion.round(this) + fun round(): Expr = Companion.round(this) /** * Creates an expression that rounds off this numeric expression to [decimalPlace] decimal places @@ -2722,7 +2875,7 @@ abstract class Expr internal constructor() { * @param decimalPlace The number of decimal places to round. * @return A new [Expr] representing the round operation. */ - fun roundToDecimal(decimalPlace: Int) = Companion.roundToDecimal(this, decimalPlace) + fun roundToDecimal(decimalPlace: Int): Expr = Companion.roundToDecimal(this, decimalPlace) /** * Creates an expression that rounds off this numeric expression to [decimalPlace] decimal places @@ -2732,7 +2885,7 @@ abstract class Expr internal constructor() { * @param decimalPlace The number of decimal places to round. * @return A new [Expr] representing the round operation. */ - fun roundToDecimal(decimalPlace: Expr) = Companion.roundToDecimal(this, decimalPlace) + fun roundToDecimal(decimalPlace: Expr): Expr = Companion.roundToDecimal(this, decimalPlace) /** * Creates an expression that returns the smalled integer that isn't less than this numeric @@ -2740,7 +2893,7 @@ abstract class Expr internal constructor() { * * @return A new [Expr] representing an integer result from the ceil operation. */ - fun ceil() = Companion.ceil(this) + fun ceil(): Expr = Companion.ceil(this) /** * Creates an expression that returns the largest integer that isn't less than this numeric @@ -2748,7 +2901,7 @@ abstract class Expr internal constructor() { * * @return A new [Expr] representing an integer result from the floor operation. */ - fun floor() = Companion.floor(this) + fun floor(): Expr = Companion.floor(this) /** * Creates an expression that returns this numeric expression raised to the power of the @@ -2758,7 +2911,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing a numeric result from raising this numeric expression to the * power of [exponent]. */ - fun pow(exponent: Number) = Companion.pow(this, exponent) + fun pow(exponent: Number): Expr = Companion.pow(this, exponent) /** * Creates an expression that returns this numeric expression raised to the power of the @@ -2768,14 +2921,14 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing a numeric result from raising this numeric expression to the * power of [exponent]. */ - fun pow(exponent: Expr) = Companion.pow(this, exponent) + fun pow(exponent: Expr): Expr = Companion.pow(this, exponent) /** * Creates an expression that returns the square root of this numeric expression. * * @return A new [Expr] representing the numeric result of the square root operation. */ - fun sqrt() = Companion.sqrt(this) + fun sqrt(): Expr = Companion.sqrt(this) /** * Creates an expression that checks if this expression, when evaluated, is equal to any of the @@ -2853,18 +3006,42 @@ abstract class Expr internal constructor() { fun isNotNull(): BooleanExpr = Companion.isNotNull(this) /** + * Creates an expression that replaces the first occurrence of a substring within this string + * expression. + * + * @param find The expression representing the substring to search for in this expressions. + * @param replace The expression representing the replacement for the first occurrence of [find]. + * @return A new [Expr] representing the string with the first occurrence replaced. */ fun replaceFirst(find: Expr, replace: Expr) = Companion.replaceFirst(this, find, replace) /** + * Creates an expression that replaces the first occurrence of a substring within this string + * expression. + * + * @param find The substring to search for in this string expression. + * @param replace The replacement for the first occurrence of [find] with. + * @return A new [Expr] representing the string with the first occurrence replaced. */ fun replaceFirst(find: String, replace: String) = Companion.replaceFirst(this, find, replace) /** + * Creates an expression that replaces all occurrences of a substring within this string + * expression. + * + * @param find The expression representing the substring to search for in this string expression. + * @param replace The expression representing the replacement for all occurrences of [find]. + * @return A new [Expr] representing the string with all occurrences replaced. */ fun replaceAll(find: Expr, replace: Expr) = Companion.replaceAll(this, find, replace) /** + * Creates an expression that replaces all occurrences of a substring within this string + * expression. + * + * @param find The substring to search for in this string expression. + * @param replace The replacement for all occurrences of [find] with. + * @return A new [Expr] representing the string with all occurrences replaced. */ fun replaceAll(find: String, replace: String) = Companion.replaceAll(this, find, replace) @@ -2900,18 +3077,38 @@ abstract class Expr internal constructor() { fun like(pattern: String): BooleanExpr = Companion.like(this, pattern) /** + * Creates an expression that checks if this string expression contains a specified regular + * expression as a substring. + * + * @param pattern The regular expression to use for the search. + * @return A new [BooleanExpr] representing the contains regular expression comparison. */ fun regexContains(pattern: Expr): BooleanExpr = Companion.regexContains(this, pattern) /** + * Creates an expression that checks if this string expression contains a specified regular + * expression as a substring. + * + * @param pattern The regular expression to use for the search. + * @return A new [BooleanExpr] representing the contains regular expression comparison. */ fun regexContains(pattern: String): BooleanExpr = Companion.regexContains(this, pattern) /** + * Creates an expression that checks if this string expression matches a specified regular + * expression. + * + * @param pattern The regular expression to use for the match. + * @return A new [BooleanExpr] representing the regular expression match comparison. */ fun regexMatch(pattern: Expr): BooleanExpr = Companion.regexMatch(this, pattern) /** + * Creates an expression that checks if this string expression matches a specified regular + * expression. + * + * @param pattern The regular expression to use for the match. + * @return A new [BooleanExpr] representing the regular expression match comparison. */ fun regexMatch(pattern: String): BooleanExpr = Companion.regexMatch(this, pattern) @@ -2952,6 +3149,9 @@ abstract class Expr internal constructor() { fun logicalMinimum(vararg others: Any): Expr = Companion.logicalMinimum(this, *others) /** + * Creates an expression that reverses this string expression. + * + * @return A new [Expr] representing the reversed string. */ fun reverse(): Expr = Companion.reverse(this) @@ -3529,6 +3729,7 @@ internal constructor( private val params: Array, private val options: InternalOptions = InternalOptions.EMPTY ) : Expr() { + internal constructor(name: String) : this(name, emptyArray()) internal constructor(name: String, param: Expr) : this(name, arrayOf(param)) internal constructor( name: String, From 8817f81f953b0563765a1fc92d6cc9e29b1ce479 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 6 May 2025 12:41:01 -0400 Subject: [PATCH 60/77] More expression work --- .../firestore/pipeline/expressions.kt | 129 ++++++++++++++---- 1 file changed, 99 insertions(+), 30 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 4bc8983da21..985ce468850 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -1512,23 +1512,43 @@ abstract class Expr internal constructor() { /** * Creates an expression that checks if a string expression contains a specified substring. * + * @param stringExpression The expression representing the string to perform the comparison on. + * @param substring The expression representing the substring to search for. * @return A new [BooleanExpr] representing the contains comparison. */ @JvmStatic - fun strContains(expr: Expr, substring: Expr): BooleanExpr = - BooleanExpr("str_contains", expr, substring) + fun strContains(stringExpression: Expr, substring: Expr): BooleanExpr = + BooleanExpr("str_contains", stringExpression, substring) - /** @return A new [Expr] representing the strContains operation. */ + /** + * Creates an expression that checks if a string expression contains a specified substring. + * + * @param stringExpression The expression representing the string to perform the comparison on. + * @param substring The substring to search for. + * @return A new [BooleanExpr] representing the contains comparison. + */ @JvmStatic - fun strContains(expr: Expr, substring: String): BooleanExpr = - BooleanExpr("str_contains", expr, substring) + fun strContains(stringExpression: Expr, substring: String): BooleanExpr = + BooleanExpr("str_contains", stringExpression, substring) - /** @return A new [BooleanExpr] representing the strContains operation. */ + /** + * Creates an expression that checks if a string field contains a specified substring. + * + * @param fieldName The name of the field to perform the comparison on. + * @param substring The expression representing the substring to search for. + * @return A new [BooleanExpr] representing the contains comparison. + */ @JvmStatic fun strContains(fieldName: String, substring: Expr): BooleanExpr = BooleanExpr("str_contains", fieldName, substring) - /** @return A new [BooleanExpr] representing the strContains operation. */ + /** + * Creates an expression that checks if a string field contains a specified substring. + * + * @param fieldName The name of the field to perform the comparison on. + * @param substring The substring to search for. + * @return A new [BooleanExpr] representing the contains comparison. + */ @JvmStatic fun strContains(fieldName: String, substring: String): BooleanExpr = BooleanExpr("str_contains", fieldName, substring) @@ -1645,23 +1665,51 @@ abstract class Expr internal constructor() { /** @return A new [Expr] representing the trim operation. */ @JvmStatic fun trim(fieldName: String): Expr = FunctionExpr("trim", fieldName) - /** @return A new [Expr] representing the strConcat operation. */ + /** + * Creates an expression that concatenates string expressions together. + * + * @param firstString The expression representing the initial string value. + * @param otherStrings Optional additional string expressions to concatenate. + * @return A new [Expr] representing the concatenated string. + */ @JvmStatic - fun strConcat(first: Expr, vararg rest: Expr): Expr = FunctionExpr("str_concat", first, *rest) + fun strConcat(firstString: Expr, vararg otherStrings: Expr): Expr = + FunctionExpr("str_concat", firstString, *otherStrings) - /** @return A new [Expr] representing the strConcat operation. */ + /** + * Creates an expression that concatenates string expressions together. + * + * @param firstString The expression representing the initial string value. + * @param otherStrings Optional additional string expressions or string constants to + * concatenate. + * @return A new [Expr] representing the concatenated string. + */ @JvmStatic - fun strConcat(first: Expr, vararg rest: Any): Expr = FunctionExpr("str_concat", first, *rest) + fun strConcat(firstString: Expr, vararg otherStrings: Any): Expr = + FunctionExpr("str_concat", firstString, *otherStrings) - /** @return A new [Expr] representing the strConcat operation. */ + /** + * Creates an expression that concatenates string expressions together. + * + * @param fieldName The field name containing the initial string value. + * @param otherStrings Optional additional string expressions to concatenate. + * @return A new [Expr] representing the concatenated string. + */ @JvmStatic - fun strConcat(fieldName: String, vararg rest: Expr): Expr = - FunctionExpr("str_concat", fieldName, *rest) + fun strConcat(fieldName: String, vararg otherStrings: Expr): Expr = + FunctionExpr("str_concat", fieldName, *otherStrings) - /** @return A new [Expr] representing the strConcat operation. */ + /** + * Creates an expression that concatenates string expressions together. + * + * @param fieldName The field name containing the initial string value. + * @param otherStrings Optional additional string expressions or string constants to + * concatenate. + * @return A new [Expr] representing the concatenated string. + */ @JvmStatic - fun strConcat(fieldName: String, vararg rest: Any): Expr = - FunctionExpr("str_concat", fieldName, *rest) + fun strConcat(fieldName: String, vararg otherStrings: Any): Expr = + FunctionExpr("str_concat", fieldName, *otherStrings) internal fun map(elements: Array): Expr = FunctionExpr("map", elements) @@ -2776,7 +2824,7 @@ abstract class Expr internal constructor() { * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ - fun add(second: Expr, vararg others: Any) = Companion.add(this, second, *others) + fun add(second: Expr, vararg others: Any): Expr = Companion.add(this, second, *others) /** * Creates an expression that adds this numeric expression to other numeric expressions and @@ -2786,7 +2834,7 @@ abstract class Expr internal constructor() { * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ - fun add(second: Number, vararg others: Any) = Companion.add(this, second, *others) + fun add(second: Number, vararg others: Any): Expr = Companion.add(this, second, *others) /** * Creates an expression that subtracts a constant from this numeric expression. @@ -2794,7 +2842,7 @@ abstract class Expr internal constructor() { * @param subtrahend Numeric expression to subtract. * @return A new [Expr] representing the subtract operation. */ - fun subtract(subtrahend: Expr) = Companion.subtract(this, subtrahend) + fun subtract(subtrahend: Expr): Expr = Companion.subtract(this, subtrahend) /** * Creates an expression that subtracts a numeric expressions from this numeric expression. @@ -2802,7 +2850,7 @@ abstract class Expr internal constructor() { * @param subtrahend Constant to subtract. * @return A new [Expr] representing the subtract operation. */ - fun subtract(subtrahend: Number) = Companion.subtract(this, subtrahend) + fun subtract(subtrahend: Number): Expr = Companion.subtract(this, subtrahend) /** * Creates an expression that multiplies this numeric expression to other numeric expressions and @@ -2812,7 +2860,7 @@ abstract class Expr internal constructor() { * @param others Additional numeric expressions or constants to multiply. * @return A new [Expr] representing the multiplication operation. */ - fun multiply(second: Expr, vararg others: Any) = Companion.multiply(this, second, *others) + fun multiply(second: Expr, vararg others: Any): Expr = Companion.multiply(this, second, *others) /** * Creates an expression that multiplies this numeric expression to other numeric expressions and @@ -2822,7 +2870,7 @@ abstract class Expr internal constructor() { * @param others Additional numeric expressions or constants to multiply. * @return A new [Expr] representing the multiplication operation. */ - fun multiply(second: Number, vararg others: Any) = Companion.multiply(this, second, *others) + fun multiply(second: Number, vararg others: Any): Expr = Companion.multiply(this, second, *others) /** * Creates an expression that divides this numeric expression by another numeric expression. @@ -2830,7 +2878,7 @@ abstract class Expr internal constructor() { * @param divisor Numeric expression to divide this numeric expression by. * @return A new [Expr] representing the division operation. */ - fun divide(divisor: Expr) = Companion.divide(this, divisor) + fun divide(divisor: Expr): Expr = Companion.divide(this, divisor) /** * Creates an expression that divides this numeric expression by a constant. @@ -2838,7 +2886,7 @@ abstract class Expr internal constructor() { * @param divisor Constant to divide this expression by. * @return A new [Expr] representing the division operation. */ - fun divide(divisor: Number) = Companion.divide(this, divisor) + fun divide(divisor: Number): Expr = Companion.divide(this, divisor) /** * Creates an expression that calculates the modulo (remainder) of dividing this numeric @@ -2847,7 +2895,7 @@ abstract class Expr internal constructor() { * @param divisor The numeric expression to divide this expression by. * @return A new [Expr] representing the modulo operation. */ - fun mod(divisor: Expr) = Companion.mod(this, divisor) + fun mod(divisor: Expr): Expr = Companion.mod(this, divisor) /** * Creates an expression that calculates the modulo (remainder) of dividing this numeric @@ -2856,7 +2904,7 @@ abstract class Expr internal constructor() { * @param divisor The constant to divide this expression by. * @return A new [Expr] representing the modulo operation. */ - fun mod(divisor: Number) = Companion.mod(this, divisor) + fun mod(divisor: Number): Expr = Companion.mod(this, divisor) /** * Creates an expression that rounds this numeric expression to nearest integer. @@ -3156,10 +3204,18 @@ abstract class Expr internal constructor() { fun reverse(): Expr = Companion.reverse(this) /** + * Creates an expression that checks if this string expression contains a specified substring. + * + * @param substring The expression representing the substring to search for. + * @return A new [BooleanExpr] representing the contains comparison. */ fun strContains(substring: Expr): BooleanExpr = Companion.strContains(this, substring) /** + * Creates an expression that checks if this string expression contains a specified substring. + * + * @param substring The substring to search for. + * @return A new [BooleanExpr] representing the contains comparison. */ fun strContains(substring: String): BooleanExpr = Companion.strContains(this, substring) @@ -3208,16 +3264,29 @@ abstract class Expr internal constructor() { fun trim() = Companion.trim(this) /** + * Creates an expression that concatenates string expressions together. + * + * @param stringExpressions The string expressions to concatenate. + * @return A new [Expr] representing the concatenated string. */ - fun strConcat(vararg expr: Expr) = Companion.strConcat(this, *expr) + fun strConcat(vararg stringExpressions: Expr): Expr = + Companion.strConcat(this, *stringExpressions) /** + * Creates an expression that concatenates this string expression with string constants. + * + * @param strings The string constants to concatenate. + * @return A new [Expr] representing the concatenated string. */ - fun strConcat(vararg string: String) = Companion.strConcat(this, *string) + fun strConcat(vararg strings: String): Expr = Companion.strConcat(this, *strings) /** + * Creates an expression that concatenates string expressions and string constants together. + * + * @param strings The string expressions or string constants to concatenate. + * @return A new [Expr] representing the concatenated string. */ - fun strConcat(vararg string: Any) = Companion.strConcat(this, *string) + fun strConcat(vararg strings: Any): Expr = Companion.strConcat(this, *strings) /** * Accesses a map (object) value using the provided [key]. From 891cefd9fa57f7f42257352782813f7c016884b6 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 6 May 2025 16:38:42 -0400 Subject: [PATCH 61/77] More expression work --- firebase-firestore/api.txt | 50 +++---- .../firestore/pipeline/expressions.kt | 124 +++++++++++++++--- 2 files changed, 131 insertions(+), 43 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 15ce01132b9..d94afe25ee3 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -1128,12 +1128,12 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Expr round(); method public static final com.google.firebase.firestore.pipeline.Expr round(com.google.firebase.firestore.pipeline.Expr numericExpr); method public static final com.google.firebase.firestore.pipeline.Expr round(String numericField); - method public final com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr decimalPlace); - method public static final com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr numericExpr, com.google.firebase.firestore.pipeline.Expr decimalPlace); - method public static final com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr numericExpr, int decimalPlace); - method public final com.google.firebase.firestore.pipeline.Expr roundToDecimal(int decimalPlace); - method public static final com.google.firebase.firestore.pipeline.Expr roundToDecimal(String numericField, com.google.firebase.firestore.pipeline.Expr decimalPlace); - method public static final com.google.firebase.firestore.pipeline.Expr roundToDecimal(String numericField, int decimalPlace); + method public final com.google.firebase.firestore.pipeline.Expr roundToPrecision(com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public static final com.google.firebase.firestore.pipeline.Expr roundToPrecision(com.google.firebase.firestore.pipeline.Expr numericExpr, com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public static final com.google.firebase.firestore.pipeline.Expr roundToPrecision(com.google.firebase.firestore.pipeline.Expr numericExpr, int decimalPlace); + method public final com.google.firebase.firestore.pipeline.Expr roundToPrecision(int decimalPlace); + method public static final com.google.firebase.firestore.pipeline.Expr roundToPrecision(String numericField, com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public static final com.google.firebase.firestore.pipeline.Expr roundToPrecision(String numericField, int decimalPlace); method public final com.google.firebase.firestore.pipeline.Expr sqrt(); method public static final com.google.firebase.firestore.pipeline.Expr sqrt(com.google.firebase.firestore.pipeline.Expr numericExpr); method public static final com.google.firebase.firestore.pipeline.Expr sqrt(String numericField); @@ -1143,16 +1143,16 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); method public static final com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); - method public static final com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); - method public static final com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); - method public final com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr... expr); - method public final com.google.firebase.firestore.pipeline.Expr strConcat(java.lang.Object... string); - method public static final com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); - method public static final com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, java.lang.Object... rest); - method public final com.google.firebase.firestore.pipeline.Expr strConcat(java.lang.String... string); + method public static final com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr firstString, com.google.firebase.firestore.pipeline.Expr... otherStrings); + method public static final com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr firstString, java.lang.Object... otherStrings); + method public final com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr... stringExpressions); + method public final com.google.firebase.firestore.pipeline.Expr strConcat(java.lang.Object... strings); + method public static final com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... otherStrings); + method public static final com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, java.lang.Object... otherStrings); + method public final com.google.firebase.firestore.pipeline.Expr strConcat(java.lang.String... strings); method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr substring); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr substring); - method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, String substring); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr substring); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr stringExpression, String substring); method public final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); method public static final com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); @@ -1414,22 +1414,22 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr reverse(String fieldName); method public com.google.firebase.firestore.pipeline.Expr round(com.google.firebase.firestore.pipeline.Expr numericExpr); method public com.google.firebase.firestore.pipeline.Expr round(String numericField); - method public com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr numericExpr, com.google.firebase.firestore.pipeline.Expr decimalPlace); - method public com.google.firebase.firestore.pipeline.Expr roundToDecimal(com.google.firebase.firestore.pipeline.Expr numericExpr, int decimalPlace); - method public com.google.firebase.firestore.pipeline.Expr roundToDecimal(String numericField, com.google.firebase.firestore.pipeline.Expr decimalPlace); - method public com.google.firebase.firestore.pipeline.Expr roundToDecimal(String numericField, int decimalPlace); + method public com.google.firebase.firestore.pipeline.Expr roundToPrecision(com.google.firebase.firestore.pipeline.Expr numericExpr, com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public com.google.firebase.firestore.pipeline.Expr roundToPrecision(com.google.firebase.firestore.pipeline.Expr numericExpr, int decimalPlace); + method public com.google.firebase.firestore.pipeline.Expr roundToPrecision(String numericField, com.google.firebase.firestore.pipeline.Expr decimalPlace); + method public com.google.firebase.firestore.pipeline.Expr roundToPrecision(String numericField, int decimalPlace); method public com.google.firebase.firestore.pipeline.Expr sqrt(com.google.firebase.firestore.pipeline.Expr numericExpr); method public com.google.firebase.firestore.pipeline.Expr sqrt(String numericField); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, com.google.firebase.firestore.pipeline.Expr prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(com.google.firebase.firestore.pipeline.Expr stringExpr, String prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, com.google.firebase.firestore.pipeline.Expr prefix); method public com.google.firebase.firestore.pipeline.BooleanExpr startsWith(String fieldName, String prefix); - method public com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr... rest); - method public com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr first, java.lang.Object... rest); - method public com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... rest); - method public com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, java.lang.Object... rest); - method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, com.google.firebase.firestore.pipeline.Expr substring); - method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr expr, String substring); + method public com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr firstString, com.google.firebase.firestore.pipeline.Expr... otherStrings); + method public com.google.firebase.firestore.pipeline.Expr strConcat(com.google.firebase.firestore.pipeline.Expr firstString, java.lang.Object... otherStrings); + method public com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, com.google.firebase.firestore.pipeline.Expr... otherStrings); + method public com.google.firebase.firestore.pipeline.Expr strConcat(String fieldName, java.lang.Object... otherStrings); + method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr stringExpression, com.google.firebase.firestore.pipeline.Expr substring); + method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(com.google.firebase.firestore.pipeline.Expr stringExpression, String substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, com.google.firebase.firestore.pipeline.Expr substring); method public com.google.firebase.firestore.pipeline.BooleanExpr strContains(String fieldName, String substring); method public com.google.firebase.firestore.pipeline.Expr subtract(com.google.firebase.firestore.pipeline.Expr minuend, com.google.firebase.firestore.pipeline.Expr subtrahend); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 985ce468850..1497373ebd9 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -605,7 +605,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the round operation. */ @JvmStatic - fun roundToDecimal(numericExpr: Expr, decimalPlace: Int): Expr = + fun roundToPrecision(numericExpr: Expr, decimalPlace: Int): Expr = FunctionExpr("round", numericExpr, constant(decimalPlace)) /** @@ -618,7 +618,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the round operation. */ @JvmStatic - fun roundToDecimal(numericField: String, decimalPlace: Int): Expr = + fun roundToPrecision(numericField: String, decimalPlace: Int): Expr = FunctionExpr("round", numericField, constant(decimalPlace)) /** @@ -631,7 +631,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the round operation. */ @JvmStatic - fun roundToDecimal(numericExpr: Expr, decimalPlace: Expr): Expr = + fun roundToPrecision(numericExpr: Expr, decimalPlace: Expr): Expr = FunctionExpr("round", numericExpr, decimalPlace) /** @@ -644,7 +644,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the round operation. */ @JvmStatic - fun roundToDecimal(numericField: String, decimalPlace: Expr): Expr = + fun roundToPrecision(numericField: String, decimalPlace: Expr): Expr = FunctionExpr("round", numericField, decimalPlace) /** @@ -2067,42 +2067,106 @@ abstract class Expr internal constructor() { fun timestampToUnixSeconds(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_seconds", fieldName) - /** @return A new [Expr] representing the timestampAdd operation. */ + /** + * Creates an expression that adds a specified amount of time to a timestamp. + * + * @param timestamp The expression representing the timestamp. + * @param unit The expression representing the unit of time to add. Valid units include + * "microsecond", "millisecond", "second", "minute", "hour" and "day". + * @param amount The expression representing the amount of time to add. + * @return A new [Expr] representing the resulting timestamp. + */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) - /** @return A new [Expr] representing the timestampAdd operation. */ + /** + * Creates an expression that adds a specified amount of time to a timestamp. + * + * @param timestamp The expression representing the timestamp. + * @param unit The unit of time to add. Valid units include "microsecond", "millisecond", + * "second", "minute", "hour" and "day". + * @param amount The amount of time to add. + * @return A new [Expr] representing the resulting timestamp. + */ @JvmStatic fun timestampAdd(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", timestamp, unit, amount) - /** @return A new [Expr] representing the timestampAdd operation. */ + /** + * Creates an expression that adds a specified amount of time to a timestamp. + * + * @param fieldName The name of the field that contains the timestamp. + * @param unit The expression representing the unit of time to add. Valid units include + * "microsecond", "millisecond", "second", "minute", "hour" and "day". + * @param amount The expression representing the amount of time to add. + * @return A new [Expr] representing the resulting timestamp. + */ @JvmStatic fun timestampAdd(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) - /** @return A new [Expr] representing the timestampAdd operation. */ + /** + * Creates an expression that adds a specified amount of time to a timestamp. + * + * @param fieldName The name of the field that contains the timestamp. + * @param unit The unit of time to add. Valid units include "microsecond", "millisecond", + * "second", "minute", "hour" and "day". + * @param amount The amount of time to add. + * @return A new [Expr] representing the resulting timestamp. + */ @JvmStatic fun timestampAdd(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_add", fieldName, unit, amount) - /** @return A new [Expr] representing the timestampSub operation. */ + /** + * Creates an expression that subtracts a specified amount of time to a timestamp. + * + * @param timestamp The expression representing the timestamp. + * @param unit The expression representing the unit of time to subtract. Valid units include + * "microsecond", "millisecond", "second", "minute", "hour" and "day". + * @param amount The expression representing the amount of time to subtract. + * @return A new [Expr] representing the resulting timestamp. + */ @JvmStatic fun timestampSub(timestamp: Expr, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) - /** @return A new [Expr] representing the timestampSub operation. */ + /** + * Creates an expression that subtracts a specified amount of time to a timestamp. + * + * @param timestamp The expression representing the timestamp. + * @param unit The unit of time to subtract. Valid units include "microsecond", "millisecond", + * "second", "minute", "hour" and "day". + * @param amount The amount of time to subtract. + * @return A new [Expr] representing the resulting timestamp. + */ @JvmStatic fun timestampSub(timestamp: Expr, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", timestamp, unit, amount) - /** @return A new [Expr] representing the timestampSub operation. */ + /** + * Creates an expression that subtracts a specified amount of time to a timestamp. + * + * @param fieldName The name of the field that contains the timestamp. + * @param unit The unit of time to subtract. Valid units include "microsecond", "millisecond", + * "second", "minute", "hour" and "day". + * @param amount The amount of time to subtract. + * @return A new [Expr] representing the resulting timestamp. + */ @JvmStatic fun timestampSub(fieldName: String, unit: Expr, amount: Expr): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) - /** @return A new [Expr] representing the timestampSub operation. */ + /** + * Creates an expression that subtracts a specified amount of time to a timestamp. + * + * @param fieldName The name of the field that contains the timestamp. + * @param unit The unit of time to subtract. Valid units include "microsecond", "millisecond", + * "second", "minute", "hour" and "day". + * @param amount The amount of time to subtract. + * @return A new [Expr] representing the resulting timestamp. + */ @JvmStatic fun timestampSub(fieldName: String, unit: String, amount: Double): Expr = FunctionExpr("timestamp_sub", fieldName, unit, amount) @@ -2923,7 +2987,7 @@ abstract class Expr internal constructor() { * @param decimalPlace The number of decimal places to round. * @return A new [Expr] representing the round operation. */ - fun roundToDecimal(decimalPlace: Int): Expr = Companion.roundToDecimal(this, decimalPlace) + fun roundToPrecision(decimalPlace: Int): Expr = Companion.roundToPrecision(this, decimalPlace) /** * Creates an expression that rounds off this numeric expression to [decimalPlace] decimal places @@ -2933,7 +2997,7 @@ abstract class Expr internal constructor() { * @param decimalPlace The number of decimal places to round. * @return A new [Expr] representing the round operation. */ - fun roundToDecimal(decimalPlace: Expr): Expr = Companion.roundToDecimal(this, decimalPlace) + fun roundToPrecision(decimalPlace: Expr): Expr = Companion.roundToPrecision(this, decimalPlace) /** * Creates an expression that returns the smalled integer that isn't less than this numeric @@ -3424,20 +3488,44 @@ abstract class Expr internal constructor() { fun timestampToUnixSeconds() = Companion.timestampToUnixSeconds(this) /** + * Creates an expression that adds a specified amount of time to this timestamp expression. + * + * @param unit The expression representing the unit of time to add. Valid units include + * "microsecond", "millisecond", "second", "minute", "hour" and "day". + * @param amount The expression representing the amount of time to add. + * @return A new [Expr] representing the resulting timestamp. */ - fun timestampAdd(unit: Expr, amount: Expr) = Companion.timestampAdd(this, unit, amount) + fun timestampAdd(unit: Expr, amount: Expr): Expr = Companion.timestampAdd(this, unit, amount) /** + * Creates an expression that adds a specified amount of time to this timestamp expression. + * + * @param unit The unit of time to add. Valid units include "microsecond", "millisecond", + * "second", "minute", "hour" and "day". + * @param amount The amount of time to add. + * @return A new [Expr] representing the resulting timestamp. */ - fun timestampAdd(unit: String, amount: Double) = Companion.timestampAdd(this, unit, amount) + fun timestampAdd(unit: String, amount: Double): Expr = Companion.timestampAdd(this, unit, amount) /** + * Creates an expression that subtracts a specified amount of time to this timestamp expression. + * + * @param unit The expression representing the unit of time to subtract. Valid units include + * "microsecond", "millisecond", "second", "minute", "hour" and "day". + * @param amount The expression representing the amount of time to subtract. + * @return A new [Expr] representing the resulting timestamp. */ - fun timestampSub(unit: Expr, amount: Expr) = Companion.timestampSub(this, unit, amount) + fun timestampSub(unit: Expr, amount: Expr): Expr = Companion.timestampSub(this, unit, amount) /** + * Creates an expression that subtracts a specified amount of time to this timestamp expression. + * + * @param unit The unit of time to subtract. Valid units include "microsecond", "millisecond", + * "second", "minute", "hour" and "day". + * @param amount The amount of time to subtract. + * @return A new [Expr] representing the resulting timestamp. */ - fun timestampSub(unit: String, amount: Double) = Companion.timestampSub(this, unit, amount) + fun timestampSub(unit: String, amount: Double): Expr = Companion.timestampSub(this, unit, amount) /** * Creates an expression that concatenates a field's array value with other arrays. From eb02ca420e97c4af94ea16e8ca4e63983c675006 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Wed, 7 May 2025 11:41:40 -0400 Subject: [PATCH 62/77] More expression work --- firebase-firestore/api.txt | 28 ++-- .../firestore/pipeline/expressions.kt | 136 ++++++++++++++---- 2 files changed, 123 insertions(+), 41 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index d94afe25ee3..5da5bd2fad6 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -1176,28 +1176,28 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Expr timestampSub(String unit, double amount); method public static final com.google.firebase.firestore.pipeline.Expr timestampSub(String fieldName, String unit, double amount); method public final com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(); - method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(); - method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(); - method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr toLower(); - method public static final com.google.firebase.firestore.pipeline.Expr toLower(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Expr toLower(com.google.firebase.firestore.pipeline.Expr stringExpression); method public static final com.google.firebase.firestore.pipeline.Expr toLower(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr toUpper(); - method public static final com.google.firebase.firestore.pipeline.Expr toUpper(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Expr toUpper(com.google.firebase.firestore.pipeline.Expr stringExpression); method public static final com.google.firebase.firestore.pipeline.Expr toUpper(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr trim(); - method public static final com.google.firebase.firestore.pipeline.Expr trim(com.google.firebase.firestore.pipeline.Expr expr); + method public static final com.google.firebase.firestore.pipeline.Expr trim(com.google.firebase.firestore.pipeline.Expr stringExpression); method public static final com.google.firebase.firestore.pipeline.Expr trim(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(); method public static final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); method public static final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(); - method public static final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(); method public static final com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); @@ -1444,21 +1444,21 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr timestampSub(com.google.firebase.firestore.pipeline.Expr timestamp, String unit, double amount); method public com.google.firebase.firestore.pipeline.Expr timestampSub(String fieldName, com.google.firebase.firestore.pipeline.Expr unit, com.google.firebase.firestore.pipeline.Expr amount); method public com.google.firebase.firestore.pipeline.Expr timestampSub(String fieldName, String unit, double amount); - method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMicros(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Expr timestampToUnixMillis(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Expr timestampToUnixSeconds(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr toLower(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Expr toLower(com.google.firebase.firestore.pipeline.Expr stringExpression); method public com.google.firebase.firestore.pipeline.Expr toLower(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr toUpper(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Expr toUpper(com.google.firebase.firestore.pipeline.Expr stringExpression); method public com.google.firebase.firestore.pipeline.Expr toUpper(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr trim(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.Expr trim(com.google.firebase.firestore.pipeline.Expr stringExpression); method public com.google.firebase.firestore.pipeline.Expr trim(String fieldName); method public com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); method public com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(String fieldName); method public com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); method public com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(String fieldName); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 1497373ebd9..4a5d2a4eb34 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -1641,28 +1641,54 @@ abstract class Expr internal constructor() { fun endsWith(fieldName: String, suffix: String): BooleanExpr = BooleanExpr("ends_with", fieldName, suffix) - /** @return A new [Expr] representing the toLower operation. */ - @JvmStatic fun toLower(expr: Expr): Expr = FunctionExpr("to_lower", expr) - - /** @return A new [Expr] representing the toLower operation. */ + /** + * Creates an expression that converts a string expression to lowercase. + * + * @param stringExpression The expression representing the string to convert to lowercase. + * @return A new [Expr] representing the lowercase string. + */ @JvmStatic - fun toLower( - fieldName: String, - ): Expr = FunctionExpr("to_lower", fieldName) + fun toLower(stringExpression: Expr): Expr = FunctionExpr("to_lower", stringExpression) - /** @return A new [Expr] representing the toUpper operation. */ - @JvmStatic fun toUpper(expr: Expr): Expr = FunctionExpr("to_upper", expr) + /** + * Creates an expression that converts a string field to lowercase. + * + * @param fieldName The name of the field containing the string to convert to lowercase. + * @return A new [Expr] representing the lowercase string. + */ + @JvmStatic fun toLower(fieldName: String): Expr = FunctionExpr("to_lower", fieldName) - /** @return A new [Expr] representing the toUpper operation. */ + /** + * Creates an expression that converts a string expression to uppercase. + * + * @param stringExpression The expression representing the string to convert to uppercase. + * @return A new [Expr] representing the lowercase string. + */ @JvmStatic - fun toUpper( - fieldName: String, - ): Expr = FunctionExpr("to_upper", fieldName) + fun toUpper(stringExpression: Expr): Expr = FunctionExpr("to_upper", stringExpression) + + /** + * Creates an expression that converts a string field to uppercase. + * + * @param fieldName The name of the field containing the string to convert to uppercase. + * @return A new [Expr] representing the lowercase string. + */ + @JvmStatic fun toUpper(fieldName: String): Expr = FunctionExpr("to_upper", fieldName) - /** @return A new [Expr] representing the trim operation. */ - @JvmStatic fun trim(expr: Expr): Expr = FunctionExpr("trim", expr) + /** + * Creates an expression that removes leading and trailing whitespace from a string expression. + * + * @param stringExpression The expression representing the string to trim. + * @return A new [Expr] representing the trimmed string. + */ + @JvmStatic fun trim(stringExpression: Expr): Expr = FunctionExpr("trim", stringExpression) - /** @return A new [Expr] representing the trim operation. */ + /** + * Creates an expression that removes leading and trailing whitespace from a string field. + * + * @param fieldName The name of the field containing the string to trim. + * @return A new [Expr] representing the trimmed string. + */ @JvmStatic fun trim(fieldName: String): Expr = FunctionExpr("trim", fieldName) /** @@ -2022,29 +2048,52 @@ abstract class Expr internal constructor() { fun unixMicrosToTimestamp(fieldName: String): Expr = FunctionExpr("unix_micros_to_timestamp", fieldName) - /** @return A new [Expr] representing the timestampToUnixMicros operation. */ + /** + * Creates an expression that converts a timestamp expression to the number of microseconds + * since the Unix epoch (1970-01-01 00:00:00 UTC). + * + * @param expr The expression representing the timestamp. + * @return A new [Expr] representing the number of microseconds since epoch. + */ @JvmStatic - fun timestampToUnixMicros(input: Expr): Expr = FunctionExpr("timestamp_to_unix_micros", input) + fun timestampToUnixMicros(expr: Expr): Expr = FunctionExpr("timestamp_to_unix_micros", expr) - /** @return A new [Expr] representing the timestampToUnixMicros operation. */ + /** + * Creates an expression that converts a timestamp field to the number of microseconds since the + * Unix epoch (1970-01-01 00:00:00 UTC). + * + * @param fieldName The name of the field that contains the timestamp. + * @return A new [Expr] representing the number of microseconds since epoch. + */ @JvmStatic fun timestampToUnixMicros(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_micros", fieldName) - /** @return A new [Expr] representing the unixMillisToTimestamp operation. */ @JvmStatic - fun unixMillisToTimestamp(input: Expr): Expr = FunctionExpr("unix_millis_to_timestamp", input) + fun unixMillisToTimestamp(expr: Expr): Expr = FunctionExpr("unix_millis_to_timestamp", expr) /** @return A new [Expr] representing the unixMillisToTimestamp operation. */ @JvmStatic fun unixMillisToTimestamp(fieldName: String): Expr = FunctionExpr("unix_millis_to_timestamp", fieldName) - /** @return A new [Expr] representing the timestampToUnixMillis operation. */ + /** + * Creates an expression that converts a timestamp expression to the number of milliseconds + * since the Unix epoch (1970-01-01 00:00:00 UTC). + * + * @param expr The expression representing the timestamp. + * @return A new [Expr] representing the number of milliseconds since epoch. + */ @JvmStatic - fun timestampToUnixMillis(input: Expr): Expr = FunctionExpr("timestamp_to_unix_millis", input) + fun timestampToUnixMillis(expr: Expr): Expr = FunctionExpr("timestamp_to_unix_millis", expr) - /** @return A new [Expr] representing the timestampToUnixMillis operation. */ + /** + * Creates an expression that converts a timestamp field to the number of milliseconds since the + * Unix epoch (1970-01-01 00:00:00 UTC). + * + * @param fieldName The name of the field that contains the timestamp. + * @return A new [Expr] representing the number of milliseconds since epoch. + */ @JvmStatic fun timestampToUnixMillis(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_millis", fieldName) @@ -2058,11 +2107,23 @@ abstract class Expr internal constructor() { fun unixSecondsToTimestamp(fieldName: String): Expr = FunctionExpr("unix_seconds_to_timestamp", fieldName) - /** @return A new [Expr] representing the timestampToUnixSeconds operation. */ + /** + * Creates an expression that converts a timestamp expression to the number of seconds since the + * Unix epoch (1970-01-01 00:00:00 UTC). + * + * @param expr The expression representing the timestamp. + * @return A new [Expr] representing the number of seconds since epoch. + */ @JvmStatic - fun timestampToUnixSeconds(input: Expr): Expr = FunctionExpr("timestamp_to_unix_seconds", input) + fun timestampToUnixSeconds(expr: Expr): Expr = FunctionExpr("timestamp_to_unix_seconds", expr) - /** @return A new [Expr] representing the timestampToUnixSeconds operation. */ + /** + * Creates an expression that converts a timestamp field to the number of seconds since the Unix + * epoch (1970-01-01 00:00:00 UTC). + * + * @param fieldName The name of the field that contains the timestamp. + * @return A new [Expr] representing the number of seconds since epoch. + */ @JvmStatic fun timestampToUnixSeconds(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_seconds", fieldName) @@ -3316,14 +3377,23 @@ abstract class Expr internal constructor() { fun endsWith(suffix: String) = Companion.endsWith(this, suffix) /** + * Creates an expression that converts this string expression to lowercase. + * + * @return A new [Expr] representing the lowercase string. */ fun toLower() = Companion.toLower(this) /** + * Creates an expression that converts this string expression to uppercase. + * + * @return A new [Expr] representing the lowercase string. */ fun toUpper() = Companion.toUpper(this) /** + * Creates an expression that removes leading and trailing whitespace from this string expression. + * + * @return A new [Expr] representing the trimmed string. */ fun trim() = Companion.trim(this) @@ -3468,6 +3538,10 @@ abstract class Expr internal constructor() { fun unixMicrosToTimestamp() = Companion.unixMicrosToTimestamp(this) /** + * Creates an expression that converts this timestamp expression to the number of microseconds + * since the Unix epoch (1970-01-01 00:00:00 UTC). + * + * @return A new [Expr] representing the number of microseconds since epoch. */ fun timestampToUnixMicros() = Companion.timestampToUnixMicros(this) @@ -3476,6 +3550,10 @@ abstract class Expr internal constructor() { fun unixMillisToTimestamp() = Companion.unixMillisToTimestamp(this) /** + * Creates an expression that converts this timestamp expression to the number of milliseconds + * since the Unix epoch (1970-01-01 00:00:00 UTC). + * + * @return A new [Expr] representing the number of milliseconds since epoch. */ fun timestampToUnixMillis() = Companion.timestampToUnixMillis(this) @@ -3484,6 +3562,10 @@ abstract class Expr internal constructor() { fun unixSecondsToTimestamp() = Companion.unixSecondsToTimestamp(this) /** + * Creates an expression that converts this timestamp expression to the number of seconds since + * the Unix epoch (1970-01-01 00:00:00 UTC). + * + * @return A new [Expr] representing the number of seconds since epoch. */ fun timestampToUnixSeconds() = Companion.timestampToUnixSeconds(this) From 8a58ed2b3aa038685032c9d6094d8b6fe27dfcbc Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Wed, 7 May 2025 17:39:15 -0400 Subject: [PATCH 63/77] More expression work --- firebase-firestore/api.txt | 48 +++---- .../firebase/firestore/PipelineTest.java | 6 +- .../firebase/firestore/pipeline/aggregates.kt | 105 +++++++++++++-- .../firestore/pipeline/expressions.kt | 126 +++++++++++++++--- 4 files changed, 223 insertions(+), 62 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 5da5bd2fad6..7ad2c871db7 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -691,35 +691,35 @@ package com.google.firebase.firestore.pipeline { public final class AggregateFunction { method public com.google.firebase.firestore.pipeline.AggregateWithAlias alias(String alias); - method public static com.google.firebase.firestore.pipeline.AggregateFunction avg(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateFunction avg(com.google.firebase.firestore.pipeline.Expr expression); method public static com.google.firebase.firestore.pipeline.AggregateFunction avg(String fieldName); - method public static com.google.firebase.firestore.pipeline.AggregateFunction count(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateFunction count(com.google.firebase.firestore.pipeline.Expr expression); method public static com.google.firebase.firestore.pipeline.AggregateFunction count(String fieldName); method public static com.google.firebase.firestore.pipeline.AggregateFunction countAll(); method public static com.google.firebase.firestore.pipeline.AggregateFunction countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); method public static com.google.firebase.firestore.pipeline.AggregateFunction generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); - method public static com.google.firebase.firestore.pipeline.AggregateFunction max(com.google.firebase.firestore.pipeline.Expr expr); - method public static com.google.firebase.firestore.pipeline.AggregateFunction max(String fieldName); - method public static com.google.firebase.firestore.pipeline.AggregateFunction min(com.google.firebase.firestore.pipeline.Expr expr); - method public static com.google.firebase.firestore.pipeline.AggregateFunction min(String fieldName); - method public static com.google.firebase.firestore.pipeline.AggregateFunction sum(com.google.firebase.firestore.pipeline.Expr expr); + method public static com.google.firebase.firestore.pipeline.AggregateFunction maximum(com.google.firebase.firestore.pipeline.Expr expression); + method public static com.google.firebase.firestore.pipeline.AggregateFunction maximum(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateFunction minimum(com.google.firebase.firestore.pipeline.Expr expression); + method public static com.google.firebase.firestore.pipeline.AggregateFunction minimum(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateFunction sum(com.google.firebase.firestore.pipeline.Expr expression); method public static com.google.firebase.firestore.pipeline.AggregateFunction sum(String fieldName); field public static final com.google.firebase.firestore.pipeline.AggregateFunction.Companion Companion; } public static final class AggregateFunction.Companion { - method public com.google.firebase.firestore.pipeline.AggregateFunction avg(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateFunction avg(com.google.firebase.firestore.pipeline.Expr expression); method public com.google.firebase.firestore.pipeline.AggregateFunction avg(String fieldName); - method public com.google.firebase.firestore.pipeline.AggregateFunction count(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateFunction count(com.google.firebase.firestore.pipeline.Expr expression); method public com.google.firebase.firestore.pipeline.AggregateFunction count(String fieldName); method public com.google.firebase.firestore.pipeline.AggregateFunction countAll(); method public com.google.firebase.firestore.pipeline.AggregateFunction countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); method public com.google.firebase.firestore.pipeline.AggregateFunction generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); - method public com.google.firebase.firestore.pipeline.AggregateFunction max(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.AggregateFunction max(String fieldName); - method public com.google.firebase.firestore.pipeline.AggregateFunction min(com.google.firebase.firestore.pipeline.Expr expr); - method public com.google.firebase.firestore.pipeline.AggregateFunction min(String fieldName); - method public com.google.firebase.firestore.pipeline.AggregateFunction sum(com.google.firebase.firestore.pipeline.Expr expr); + method public com.google.firebase.firestore.pipeline.AggregateFunction maximum(com.google.firebase.firestore.pipeline.Expr expression); + method public com.google.firebase.firestore.pipeline.AggregateFunction maximum(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateFunction minimum(com.google.firebase.firestore.pipeline.Expr expression); + method public com.google.firebase.firestore.pipeline.AggregateFunction minimum(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateFunction sum(com.google.firebase.firestore.pipeline.Expr expression); method public com.google.firebase.firestore.pipeline.AggregateFunction sum(String fieldName); } @@ -738,8 +738,8 @@ package com.google.firebase.firestore.pipeline { } public class BooleanExpr extends com.google.firebase.firestore.pipeline.FunctionExpr { - method public final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.Expr then, com.google.firebase.firestore.pipeline.Expr otherwise); - method public final com.google.firebase.firestore.pipeline.Expr cond(Object then, Object otherwise); + method public final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.Expr thenExpr, com.google.firebase.firestore.pipeline.Expr elseExpr); + method public final com.google.firebase.firestore.pipeline.Expr cond(Object thenValue, Object elseValue); method public final com.google.firebase.firestore.pipeline.AggregateFunction countIf(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public final com.google.firebase.firestore.pipeline.BooleanExpr not(); @@ -1062,8 +1062,8 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Expr mapRemove(String key); method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, com.google.firebase.firestore.pipeline.Expr key); method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(String mapField, String key); - method public final com.google.firebase.firestore.pipeline.AggregateFunction max(); - method public final com.google.firebase.firestore.pipeline.AggregateFunction min(); + method public final com.google.firebase.firestore.pipeline.AggregateFunction maximum(); + method public final com.google.firebase.firestore.pipeline.AggregateFunction minimum(); method public final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr divisor); method public static final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr dividend, com.google.firebase.firestore.pipeline.Expr divisor); method public static final com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr dividend, Number divisor); @@ -1194,18 +1194,18 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Expr trim(com.google.firebase.firestore.pipeline.Expr stringExpression); method public static final com.google.firebase.firestore.pipeline.Expr trim(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(); - method public static final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(); method public static final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(String fieldName); method public final com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(); - method public static final com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public static final com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(String fieldName); method public static final com.google.firebase.firestore.pipeline.Expr vector(com.google.firebase.firestore.VectorValue vector); method public static final com.google.firebase.firestore.pipeline.Expr vector(double[] vector); method public final com.google.firebase.firestore.pipeline.Expr vectorLength(); - method public static final com.google.firebase.firestore.pipeline.Expr vectorLength(com.google.firebase.firestore.pipeline.Expr vector); + method public static final com.google.firebase.firestore.pipeline.Expr vectorLength(com.google.firebase.firestore.pipeline.Expr vectorExpression); method public static final com.google.firebase.firestore.pipeline.Expr vectorLength(String fieldName); method public static final com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); field public static final com.google.firebase.firestore.pipeline.Expr.Companion Companion; @@ -1456,15 +1456,15 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr toUpper(String fieldName); method public com.google.firebase.firestore.pipeline.Expr trim(com.google.firebase.firestore.pipeline.Expr stringExpression); method public com.google.firebase.firestore.pipeline.Expr trim(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Expr unixMicrosToTimestamp(String fieldName); method public com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Expr unixMillisToTimestamp(String fieldName); - method public com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr input); + method public com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.Expr unixSecondsToTimestamp(String fieldName); method public com.google.firebase.firestore.pipeline.Expr vector(com.google.firebase.firestore.VectorValue vector); method public com.google.firebase.firestore.pipeline.Expr vector(double[] vector); - method public com.google.firebase.firestore.pipeline.Expr vectorLength(com.google.firebase.firestore.pipeline.Expr vector); + method public com.google.firebase.firestore.pipeline.Expr vectorLength(com.google.firebase.firestore.pipeline.Expr vectorExpression); method public com.google.firebase.firestore.pipeline.Expr vectorLength(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr xor(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); } diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 12a4a5aa1d7..344f66fddfd 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -244,7 +244,7 @@ public void aggregateResultsMany() { .aggregate( AggregateFunction.countAll().alias("count"), AggregateFunction.avg("rating").alias("avgRating"), - field("rating").max().alias("maxRating")) + field("rating").maximum().alias("maxRating")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) @@ -304,8 +304,8 @@ public void minAndMaxAccumulations() { .collection(randomCol) .aggregate( AggregateFunction.countAll().alias("count"), - field("rating").max().alias("maxRating"), - field("published").min().alias("minPublished")) + field("rating").maximum().alias("maxRating"), + field("published").minimum().alias("minPublished")) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt index 60bdbdab8eb..0ce88ce385b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt @@ -35,29 +35,108 @@ private constructor( @JvmStatic fun generic(name: String, vararg expr: Expr) = AggregateFunction(name, expr) + /** + * Creates an aggregation that counts the total number of stage inputs. + * + * @return A new [AggregateFunction] representing the countAll aggregation. + */ @JvmStatic fun countAll() = AggregateFunction("count") + /** + * Creates an aggregation that counts the number of stage inputs where the input field exists. + * + * @param fieldName The name of the field to count. + * @return A new [AggregateFunction] representing the 'count' aggregation. + */ @JvmStatic fun count(fieldName: String) = AggregateFunction("count", fieldName) - @JvmStatic fun count(expr: Expr) = AggregateFunction("count", expr) - + /** + * Creates an aggregation that counts the number of stage inputs with valid evaluations of the + * provided [expression]. + * + * @param expression The expression to count. + * @return A new [AggregateFunction] representing the 'count' aggregation. + */ + @JvmStatic fun count(expression: Expr) = AggregateFunction("count", expression) + + /** + * Creates an aggregation that counts the number of stage inputs where the provided boolean + * expression evaluates to true. + * + * @param condition The boolean expression to evaluate on each input. + * @return A new [AggregateFunction] representing the count aggregation. + */ @JvmStatic fun countIf(condition: BooleanExpr) = AggregateFunction("countIf", condition) + /** + * Creates an aggregation that calculates the sum of a field's values across multiple stage + * inputs. + * + * @param fieldName The name of the field containing numeric values to sum up. + * @return A new [AggregateFunction] representing the average aggregation. + */ @JvmStatic fun sum(fieldName: String) = AggregateFunction("sum", fieldName) - @JvmStatic fun sum(expr: Expr) = AggregateFunction("sum", expr) - + /** + * Creates an aggregation that calculates the sum of values from an expression across multiple + * stage inputs. + * + * @param expression The expression to sum up. + * @return A new [AggregateFunction] representing the sum aggregation. + */ + @JvmStatic fun sum(expression: Expr) = AggregateFunction("sum", expression) + + /** + * Creates an aggregation that calculates the average (mean) of a field's values across multiple + * stage inputs. + * + * @param fieldName The name of the field containing numeric values to average. + * @return A new [AggregateFunction] representing the average aggregation. + */ @JvmStatic fun avg(fieldName: String) = AggregateFunction("avg", fieldName) - @JvmStatic fun avg(expr: Expr) = AggregateFunction("avg", expr) - - @JvmStatic fun min(fieldName: String) = AggregateFunction("min", fieldName) - - @JvmStatic fun min(expr: Expr) = AggregateFunction("min", expr) - - @JvmStatic fun max(fieldName: String) = AggregateFunction("max", fieldName) - - @JvmStatic fun max(expr: Expr) = AggregateFunction("max", expr) + /** + * Creates an aggregation that calculates the average (mean) of values from an expression across + * multiple stage inputs. + * + * @param expression The expression representing the values to average. + * @return A new [AggregateFunction] representing the average aggregation. + */ + @JvmStatic fun avg(expression: Expr) = AggregateFunction("avg", expression) + + /** + * Creates an aggregation that finds the minimum value of a field across multiple stage inputs. + * + * @param fieldName The name of the field to find the minimum value of. + * @return A new [AggregateFunction] representing the minimum aggregation. + */ + @JvmStatic fun minimum(fieldName: String) = AggregateFunction("min", fieldName) + + /** + * Creates an aggregation that finds the minimum value of an expression across multiple stage + * inputs. + * + * @param expression The expression to find the minimum value of. + * @return A new [AggregateFunction] representing the minimum aggregation. + */ + @JvmStatic fun minimum(expression: Expr) = AggregateFunction("min", expression) + + /** + * Creates an aggregation that finds the maximum value of a field across multiple stage inputs. + * + * @param fieldName The name of the field to find the maximum value of. + * @return A new [AggregateFunction] representing the maximum aggregation. + */ + @JvmStatic fun maximum(fieldName: String) = AggregateFunction("max", fieldName) + + /** + * Creates an aggregation that finds the maximum value of an expression across multiple stage + * inputs. + * + * @param expression The expression to find the maximum value of. + * @return A new [AggregateFunction] representing the maximum aggregation. + */ + @JvmStatic fun maximum(expression: Expr) = AggregateFunction("max", expression) } /** diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 4a5d2a4eb34..ba56d2bcb07 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -329,7 +329,7 @@ abstract class Expr internal constructor() { * Creates an expression that negates a boolean expression. * * @param condition The boolean expression to negate. - * @return A new [Expr] representing the not operation. + * @return A new [BooleanExpr] representing the not operation. */ @JvmStatic fun not(condition: BooleanExpr): BooleanExpr = BooleanExpr("not", condition) @@ -2033,17 +2033,40 @@ abstract class Expr internal constructor() { fun euclideanDistance(vectorFieldName: String, vector: VectorValue): Expr = FunctionExpr("euclidean_distance", vectorFieldName, vector) - /** @return A new [Expr] representing the vectorLength operation. */ - @JvmStatic fun vectorLength(vector: Expr): Expr = FunctionExpr("vector_length", vector) + /** + * Creates an expression that calculates the length (dimension) of a Firestore Vector. + * + * @param vectorExpression The expression representing the Firestore Vector. + * @return A new [Expr] representing the length (dimension) of the vector. + */ + @JvmStatic + fun vectorLength(vectorExpression: Expr): Expr = FunctionExpr("vector_length", vectorExpression) - /** @return A new [Expr] representing the vectorLength operation. */ + /** + * Creates an expression that calculates the length (dimension) of a Firestore Vector. + * + * @param fieldName The name of the field containing the Firestore Vector. + * @return A new [Expr] representing the length (dimension) of the vector. + */ @JvmStatic fun vectorLength(fieldName: String): Expr = FunctionExpr("vector_length", fieldName) - /** @return A new [Expr] representing the unixMicrosToTimestamp operation. */ + /** + * Creates an expression that interprets an expression as the number of microseconds since the + * Unix epoch (1970-01-01 00:00:00 UTC) and returns a timestamp. + * + * @param expr The expression representing the number of microseconds since epoch. + * @return A new [Expr] representing the timestamp. + */ @JvmStatic - fun unixMicrosToTimestamp(input: Expr): Expr = FunctionExpr("unix_micros_to_timestamp", input) + fun unixMicrosToTimestamp(expr: Expr): Expr = FunctionExpr("unix_micros_to_timestamp", expr) - /** @return A new [Expr] representing the unixMicrosToTimestamp operation. */ + /** + * Creates an expression that interprets a field's value as the number of microseconds since the + * Unix epoch (1970-01-01 00:00:00 UTC) and returns a timestamp. + * + * @param fieldName The name of the field containing the number of microseconds since epoch. + * @return A new [Expr] representing the timestamp. + */ @JvmStatic fun unixMicrosToTimestamp(fieldName: String): Expr = FunctionExpr("unix_micros_to_timestamp", fieldName) @@ -2069,10 +2092,23 @@ abstract class Expr internal constructor() { fun timestampToUnixMicros(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_micros", fieldName) + /** + * Creates an expression that interprets an expression as the number of milliseconds since the + * Unix epoch (1970-01-01 00:00:00 UTC) and returns a timestamp. + * + * @param expr The expression representing the number of milliseconds since epoch. + * @return A new [Expr] representing the timestamp. + */ @JvmStatic fun unixMillisToTimestamp(expr: Expr): Expr = FunctionExpr("unix_millis_to_timestamp", expr) - /** @return A new [Expr] representing the unixMillisToTimestamp operation. */ + /** + * Creates an expression that interprets a field's value as the number of milliseconds since the + * Unix epoch (1970-01-01 00:00:00 UTC) and returns a timestamp. + * + * @param fieldName The name of the field containing the number of milliseconds since epoch. + * @return A new [Expr] representing the timestamp. + */ @JvmStatic fun unixMillisToTimestamp(fieldName: String): Expr = FunctionExpr("unix_millis_to_timestamp", fieldName) @@ -2098,11 +2134,23 @@ abstract class Expr internal constructor() { fun timestampToUnixMillis(fieldName: String): Expr = FunctionExpr("timestamp_to_unix_millis", fieldName) - /** @return A new [Expr] representing the unixSecondsToTimestamp operation. */ + /** + * Creates an expression that interprets an expression as the number of seconds since the Unix + * epoch (1970-01-01 00:00:00 UTC) and returns a timestamp. + * + * @param expr The expression representing the number of seconds since epoch. + * @return A new [Expr] representing the timestamp. + */ @JvmStatic - fun unixSecondsToTimestamp(input: Expr): Expr = FunctionExpr("unix_seconds_to_timestamp", input) + fun unixSecondsToTimestamp(expr: Expr): Expr = FunctionExpr("unix_seconds_to_timestamp", expr) - /** @return A new [Expr] representing the unixSecondsToTimestamp operation. */ + /** + * Creates an expression that interprets a field's value as the number of seconds since the Unix + * epoch (1970-01-01 00:00:00 UTC) and returns a timestamp. + * + * @param fieldName The name of the field containing the number of seconds since epoch. + * @return A new [Expr] representing the timestamp. + */ @JvmStatic fun unixSecondsToTimestamp(fieldName: String): Expr = FunctionExpr("unix_seconds_to_timestamp", fieldName) @@ -3530,10 +3578,17 @@ abstract class Expr internal constructor() { fun euclideanDistance(vector: VectorValue): Expr = Companion.euclideanDistance(this, vector) /** + * Creates an expression that calculates the length (dimension) of a Firestore Vector. + * + * @return A new [Expr] representing the length (dimension) of the vector. */ fun vectorLength() = Companion.vectorLength(this) /** + * Creates an expression that interprets this expression as the number of microseconds since the + * Unix epoch (1970-01-01 00:00:00 UTC) and returns a timestamp. + * + * @return A new [Expr] representing the timestamp. */ fun unixMicrosToTimestamp() = Companion.unixMicrosToTimestamp(this) @@ -3546,6 +3601,10 @@ abstract class Expr internal constructor() { fun timestampToUnixMicros() = Companion.timestampToUnixMicros(this) /** + * Creates an expression that interprets this expression as the number of milliseconds since the + * Unix epoch (1970-01-01 00:00:00 UTC) and returns a timestamp. + * + * @return A new [Expr] representing the timestamp. */ fun unixMillisToTimestamp() = Companion.unixMillisToTimestamp(this) @@ -3558,6 +3617,10 @@ abstract class Expr internal constructor() { fun timestampToUnixMillis() = Companion.timestampToUnixMillis(this) /** + * Creates an expression that interprets this expression as the number of seconds since the Unix + * epoch (1970-01-01 00:00:00 UTC) and returns a timestamp. + * + * @return A new [Expr] representing the timestamp. */ fun unixSecondsToTimestamp() = Companion.unixSecondsToTimestamp(this) @@ -3717,7 +3780,7 @@ abstract class Expr internal constructor() { * Creates an aggregation that counts the number of stage inputs with valid evaluations of the * this expression. * - * @return A new [AggregateFunction] representing the 'count' aggregation. + * @return A new [AggregateFunction] representing the count aggregation. */ fun count(): AggregateFunction = AggregateFunction.count(this) @@ -3725,7 +3788,7 @@ abstract class Expr internal constructor() { * Creates an aggregation that calculates the sum of this numeric expression across multiple stage * inputs. * - * @return A new [AggregateFunction] representing the 'sum' aggregation. + * @return A new [AggregateFunction] representing the sum aggregation. */ fun sum(): AggregateFunction = AggregateFunction.sum(this) @@ -3733,7 +3796,7 @@ abstract class Expr internal constructor() { * Creates an aggregation that calculates the average (mean) of this numeric expression across * multiple stage inputs. * - * @return A new [AggregateFunction] representing the 'avg' aggregation. + * @return A new [AggregateFunction] representing the average aggregation. */ fun avg(): AggregateFunction = AggregateFunction.avg(this) @@ -3741,17 +3804,17 @@ abstract class Expr internal constructor() { * Creates an aggregation that finds the minimum value of this expression across multiple stage * inputs. * - * @return A new [AggregateFunction] representing the 'min' aggregation. + * @return A new [AggregateFunction] representing the minimum aggregation. */ - fun min(): AggregateFunction = AggregateFunction.min(this) + fun minimum(): AggregateFunction = AggregateFunction.minimum(this) /** * Creates an aggregation that finds the maximum value of this expression across multiple stage * inputs. * - * @return A new [AggregateFunction] representing the 'max' aggregation. + * @return A new [AggregateFunction] representing the maximum aggregation. */ - fun max(): AggregateFunction = AggregateFunction.max(this) + fun maximum(): AggregateFunction = AggregateFunction.maximum(this) /** * Create an [Ordering] that sorts documents in ascending order based on value of this expression @@ -4033,20 +4096,39 @@ open class BooleanExpr internal constructor(name: String, params: Array Date: Thu, 8 May 2025 11:26:28 -0400 Subject: [PATCH 64/77] Fix from API Review --- firebase-firestore/api.txt | 5 ++--- .../com/google/firebase/firestore/Pipeline.kt | 17 ----------------- .../firebase/firestore/pipeline/expressions.kt | 2 +- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 7ad2c871db7..9e981a511c1 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -433,7 +433,6 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline findNearest(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public com.google.firebase.firestore.Pipeline findNearest(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public com.google.firebase.firestore.Pipeline genericStage(com.google.firebase.firestore.pipeline.GenericStage stage); - method public com.google.firebase.firestore.Pipeline genericStage(String name, java.lang.Object... arguments); method public com.google.firebase.firestore.Pipeline limit(int limit); method public com.google.firebase.firestore.Pipeline offset(int offset); method public com.google.firebase.firestore.Pipeline removeFields(com.google.firebase.firestore.pipeline.Field field, com.google.firebase.firestore.pipeline.Field... additionalFields); @@ -991,7 +990,7 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Expr floor(); method public static final com.google.firebase.firestore.pipeline.Expr floor(com.google.firebase.firestore.pipeline.Expr numericExpr); method public static final com.google.firebase.firestore.pipeline.Expr floor(String numericField); - method public static final com.google.firebase.firestore.pipeline.FunctionExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public static final com.google.firebase.firestore.pipeline.Expr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); @@ -1324,7 +1323,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Field field(String name); method public com.google.firebase.firestore.pipeline.Expr floor(com.google.firebase.firestore.pipeline.Expr numericExpr); method public com.google.firebase.firestore.pipeline.Expr floor(String numericField); - method public com.google.firebase.firestore.pipeline.FunctionExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public com.google.firebase.firestore.pipeline.Expr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr gt(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 06e4142d81b..5184ac8c3c7 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -102,23 +102,6 @@ internal constructor( .addAllStages(stages.map { it.toProtoStage(userDataReader) }) .build() - /** - * Adds a stage to the pipeline by specifying the stage name as an argument. This does not offer - * any type safety on the stage params and requires the caller to know the order (and optionally - * names) of parameters accepted by the stage. - * - * This method provides a way to call stages that are supported by the Firestore backend but that - * are not implemented in the SDK version being used. - * - * For stages with named parameters, use the [GenericStage] class instead. - * - * @param name The unique name of the stage to add. - * @param arguments A list of ordered parameters to configure the stage's behavior. - * @return A new [Pipeline] object with this stage appended to the stage list. - */ - fun genericStage(name: String, vararg arguments: Any): Pipeline = - append(GenericStage.ofName(name).withArguments(arguments)) - /** * Adds a stage to the pipeline by specifying the stage name as an argument. This does not offer * any type safety on the stage params and requires the caller to know the order (and optionally diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index ba56d2bcb07..47f1a974ec5 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -290,7 +290,7 @@ abstract class Expr internal constructor() { return Field(fieldPath.internalPath) } - @JvmStatic fun generic(name: String, vararg expr: Expr) = FunctionExpr(name, expr) + @JvmStatic fun generic(name: String, vararg expr: Expr): Expr = FunctionExpr(name, expr) /** * Creates an expression that performs a logical 'AND' operation. From 8bbbfaafcd8483d9703ed327644836458a294453 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 15 May 2025 13:22:15 -0400 Subject: [PATCH 65/77] Fix --- .../com/google/firebase/firestore/PipelineTest.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 344f66fddfd..3531ffab2b1 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -279,13 +279,15 @@ public void groupAndAccumulateResultsGeneric() { firestore .pipeline() .collection(randomCol) - .genericStage("where", lt(field("published"), 1984)) + .genericStage(GenericStage.ofName("where").withArguments(lt(field("published"), 1984))) .genericStage( - "aggregate", - ImmutableMap.of("avgRating", AggregateFunction.avg("rating")), - ImmutableMap.of("genre", field("genre"))) + GenericStage.ofName("aggregate") + .withArguments( + ImmutableMap.of("avgRating", AggregateFunction.avg("rating")), + ImmutableMap.of("genre", field("genre")))) .genericStage(GenericStage.ofName("where").withArguments(gt("avgRating", 4.3))) - .genericStage("sort", field("avgRating").descending()) + .genericStage( + GenericStage.ofName("sort").withArguments(field("avgRating").descending())) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) From b4f04accde06db3d5e92f1d0941be451d5d7afab Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 22 May 2025 10:39:41 -0400 Subject: [PATCH 66/77] Fix add and multiply --- .../firestore/pipeline/expressions.kt | 82 ++++++++----------- 1 file changed, 33 insertions(+), 49 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 47f1a974ec5..4b4d783ee89 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -747,52 +747,48 @@ abstract class Expr internal constructor() { @JvmStatic fun sqrt(numericField: String): Expr = FunctionExpr("sqrt", numericField) /** - * Creates an expression that adds numeric expressions and constants. + * Creates an expression that adds numeric expressions. * * @param first Numeric expression to add. * @param second Numeric expression to add. - * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ @JvmStatic - fun add(first: Expr, second: Expr, vararg others: Any): Expr = - FunctionExpr("add", first, second, *others) + fun add(first: Expr, second: Expr): Expr = + FunctionExpr("add", first, second) /** - * Creates an expression that adds numeric expressions and constants. + * Creates an expression that adds numeric expressions with a constant. * * @param first Numeric expression to add. * @param second Constant to add. - * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ @JvmStatic - fun add(first: Expr, second: Number, vararg others: Any): Expr = - FunctionExpr("add", first, second, *others) + fun add(first: Expr, second: Number): Expr = + FunctionExpr("add", first, second) /** - * Creates an expression that adds a numeric field with numeric expressions and constants. + * Creates an expression that adds a numeric field with a numeric expression. * * @param numericFieldName Numeric field to add. * @param second Numeric expression to add to field value. - * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ @JvmStatic - fun add(numericFieldName: String, second: Expr, vararg others: Any): Expr = - FunctionExpr("add", numericFieldName, second, *others) + fun add(numericFieldName: String, second: Expr): Expr = + FunctionExpr("add", numericFieldName, second) /** - * Creates an expression that adds a numeric field with numeric expressions and constants. + * Creates an expression that adds a numeric field with constant. * * @param numericFieldName Numeric field to add. * @param second Constant to add. - * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ @JvmStatic - fun add(numericFieldName: String, second: Number, vararg others: Any): Expr = - FunctionExpr("add", numericFieldName, second, *others) + fun add(numericFieldName: String, second: Number): Expr = + FunctionExpr("add", numericFieldName, second) /** * Creates an expression that subtracts two expressions. @@ -839,52 +835,48 @@ abstract class Expr internal constructor() { FunctionExpr("subtract", numericFieldName, subtrahend) /** - * Creates an expression that multiplies numeric expressions and constants. + * Creates an expression that multiplies numeric expressions. * * @param first Numeric expression to multiply. * @param second Numeric expression to multiply. - * @param others Additional numeric expressions or constants to multiply. * @return A new [Expr] representing the multiplication operation. */ @JvmStatic - fun multiply(first: Expr, second: Expr, vararg others: Any): Expr = - FunctionExpr("multiply", first, second, *others) + fun multiply(first: Expr, second: Expr): Expr = + FunctionExpr("multiply", first, second) /** - * Creates an expression that multiplies numeric expressions and constants. + * Creates an expression that multiplies numeric expressions with a constant. * * @param first Numeric expression to multiply. * @param second Constant to multiply. - * @param others Additional numeric expressions or constants to multiply. * @return A new [Expr] representing the multiplication operation. */ @JvmStatic - fun multiply(first: Expr, second: Number, vararg others: Any): Expr = - FunctionExpr("multiply", first, second, *others) + fun multiply(first: Expr, second: Number): Expr = + FunctionExpr("multiply", first, second) /** - * Creates an expression that multiplies a numeric field with numeric expressions and constants. + * Creates an expression that multiplies a numeric field with a numeric expression. * * @param numericFieldName Numeric field to multiply. - * @param second Numeric expression to add to field multiply. - * @param others Additional numeric expressions or constants to multiply. + * @param second Numeric expression to multiply. * @return A new [Expr] representing the multiplication operation. */ @JvmStatic - fun multiply(numericFieldName: String, second: Expr, vararg others: Any): Expr = - FunctionExpr("multiply", numericFieldName, second, *others) + fun multiply(numericFieldName: String, second: Expr): Expr = + FunctionExpr("multiply", numericFieldName, second) /** - * Creates an expression that multiplies a numeric field with numeric expressions and constants. + * Creates an expression that multiplies a numeric field with a constant. * * @param numericFieldName Numeric field to multiply. * @param second Constant to multiply. - * @param others Additional numeric expressions or constants to multiply. * @return A new [Expr] representing the multiplication operation. */ @JvmStatic - fun multiply(numericFieldName: String, second: Number, vararg others: Any): Expr = - FunctionExpr("multiply", numericFieldName, second, *others) + fun multiply(numericFieldName: String, second: Number): Expr = + FunctionExpr("multiply", numericFieldName, second) /** * Creates an expression that divides two numeric expressions. @@ -2990,24 +2982,20 @@ abstract class Expr internal constructor() { fun documentId(): Expr = Companion.documentId(this) /** - * Creates an expression that adds this numeric expression to other numeric expressions and - * constants. + * Creates an expression that adds this numeric expression to another numeric expression. * * @param second Numeric expression to add. - * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ - fun add(second: Expr, vararg others: Any): Expr = Companion.add(this, second, *others) + fun add(second: Expr): Expr = Companion.add(this, second) /** - * Creates an expression that adds this numeric expression to other numeric expressions and - * constants. + * Creates an expression that adds this numeric expression to a constants. * * @param second Constant to add. - * @param others Additional numeric expressions or constants to add. * @return A new [Expr] representing the addition operation. */ - fun add(second: Number, vararg others: Any): Expr = Companion.add(this, second, *others) + fun add(second: Number): Expr = Companion.add(this, second) /** * Creates an expression that subtracts a constant from this numeric expression. @@ -3026,24 +3014,20 @@ abstract class Expr internal constructor() { fun subtract(subtrahend: Number): Expr = Companion.subtract(this, subtrahend) /** - * Creates an expression that multiplies this numeric expression to other numeric expressions and - * constants. + * Creates an expression that multiplies this numeric expression with another numeric expression. * * @param second Numeric expression to multiply. - * @param others Additional numeric expressions or constants to multiply. * @return A new [Expr] representing the multiplication operation. */ - fun multiply(second: Expr, vararg others: Any): Expr = Companion.multiply(this, second, *others) + fun multiply(second: Expr): Expr = Companion.multiply(this, second) /** - * Creates an expression that multiplies this numeric expression to other numeric expressions and - * constants. + * Creates an expression that multiplies this numeric expression with a constant. * * @param second Constant to multiply. - * @param others Additional numeric expressions or constants to multiply. * @return A new [Expr] representing the multiplication operation. */ - fun multiply(second: Number, vararg others: Any): Expr = Companion.multiply(this, second, *others) + fun multiply(second: Number): Expr = Companion.multiply(this, second) /** * Creates an expression that divides this numeric expression by another numeric expression. From 065235f867dcde12a12630020964b23925f6ff10 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 22 May 2025 14:47:16 -0400 Subject: [PATCH 67/77] Fix --- .../firebase/firestore/core/CompositeFilter.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java index ee471318f80..090ddf9c17b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/CompositeFilter.java @@ -170,13 +170,16 @@ public String getCanonicalId() { @Override BooleanExpr toPipelineExpr() { - BooleanExpr[] booleanExprs = - filters.stream().map(Filter::toPipelineExpr).toArray(BooleanExpr[]::new); + BooleanExpr first = filters.get(0).toPipelineExpr(); + BooleanExpr[] additional = new BooleanExpr[filters.size() - 1]; + for (int i = 1, filtersSize = filters.size(); i < filtersSize; i++) { + additional[i - 1] = filters.get(i).toPipelineExpr(); + } switch (operator) { case AND: - return new BooleanExpr("and", booleanExprs); + return BooleanExpr.and(first, additional); case OR: - return new BooleanExpr("or", booleanExprs); + return BooleanExpr.or(first, additional); } // Handle OPERATOR_UNSPECIFIED and UNRECOGNIZED cases as needed throw new IllegalArgumentException("Unsupported operator: " + operator); From 6369f3c276af6aaf94613cd9ebcaf7b8b6e47966 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 23 May 2025 09:20:42 -0400 Subject: [PATCH 68/77] rename generic stage --- .../firebase/firestore/PipelineTest.java | 14 ++--- .../com/google/firebase/firestore/Pipeline.kt | 14 ++--- .../google/firebase/firestore/core/Query.java | 4 +- .../firebase/firestore/pipeline/stage.kt | 54 +++++++++---------- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 3531ffab2b1..5c9e26f5acb 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -47,7 +47,7 @@ import com.google.firebase.firestore.pipeline.AggregateFunction; import com.google.firebase.firestore.pipeline.AggregateStage; import com.google.firebase.firestore.pipeline.Expr; -import com.google.firebase.firestore.pipeline.GenericStage; +import com.google.firebase.firestore.pipeline.Stage; import com.google.firebase.firestore.testutil.IntegrationTestUtil; import java.util.Collections; import java.util.LinkedHashMap; @@ -279,15 +279,15 @@ public void groupAndAccumulateResultsGeneric() { firestore .pipeline() .collection(randomCol) - .genericStage(GenericStage.ofName("where").withArguments(lt(field("published"), 1984))) - .genericStage( - GenericStage.ofName("aggregate") + .addStage(Stage.ofName("where").withArguments(lt(field("published"), 1984))) + .addStage( + Stage.ofName("aggregate") .withArguments( ImmutableMap.of("avgRating", AggregateFunction.avg("rating")), ImmutableMap.of("genre", field("genre")))) - .genericStage(GenericStage.ofName("where").withArguments(gt("avgRating", 4.3))) - .genericStage( - GenericStage.ofName("sort").withArguments(field("avgRating").descending())) + .addStage(Stage.ofName("where").withArguments(gt("avgRating", 4.3))) + .addStage( + Stage.ofName("sort").withArguments(field("avgRating").descending())) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index 5184ac8c3c7..fb7d8313737 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -36,7 +36,7 @@ import com.google.firebase.firestore.pipeline.ExprWithAlias import com.google.firebase.firestore.pipeline.Field import com.google.firebase.firestore.pipeline.FindNearestStage import com.google.firebase.firestore.pipeline.FunctionExpr -import com.google.firebase.firestore.pipeline.GenericStage +import com.google.firebase.firestore.pipeline.Stage import com.google.firebase.firestore.pipeline.LimitStage import com.google.firebase.firestore.pipeline.OffsetStage import com.google.firebase.firestore.pipeline.Ordering @@ -47,7 +47,7 @@ import com.google.firebase.firestore.pipeline.SampleStage import com.google.firebase.firestore.pipeline.SelectStage import com.google.firebase.firestore.pipeline.Selectable import com.google.firebase.firestore.pipeline.SortStage -import com.google.firebase.firestore.pipeline.Stage +import com.google.firebase.firestore.pipeline.BaseStage import com.google.firebase.firestore.pipeline.UnionStage import com.google.firebase.firestore.pipeline.UnnestStage import com.google.firebase.firestore.pipeline.WhereStage @@ -59,15 +59,15 @@ class Pipeline internal constructor( internal val firestore: FirebaseFirestore, internal val userDataReader: UserDataReader, - private val stages: FluentIterable> + private val stages: FluentIterable> ) { internal constructor( firestore: FirebaseFirestore, userDataReader: UserDataReader, - stage: Stage<*> + stage: BaseStage<*> ) : this(firestore, userDataReader, FluentIterable.of(stage)) - private fun append(stage: Stage<*>): Pipeline { + private fun append(stage: BaseStage<*>): Pipeline { return Pipeline(firestore, userDataReader, stages.append(stage)) } @@ -110,10 +110,10 @@ internal constructor( * This method provides a way to call stages that are supported by the Firestore backend but that * are not implemented in the SDK version being used. * - * @param stage An [GenericStage] object that specifies stage name and parameters. + * @param stage An [Stage] object that specifies stage name and parameters. * @return A new [Pipeline] object with this stage appended to the stage list. */ - fun genericStage(stage: GenericStage): Pipeline = append(stage) + fun addStage(stage: Stage): Pipeline = append(stage) /** * Adds new fields to outputs from previous stages. diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index 629135fe888..2aebd7e988c 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -37,7 +37,7 @@ import com.google.firebase.firestore.pipeline.FunctionExpr; import com.google.firebase.firestore.pipeline.InternalOptions; import com.google.firebase.firestore.pipeline.Ordering; -import com.google.firebase.firestore.pipeline.Stage; +import com.google.firebase.firestore.pipeline.BaseStage; import com.google.firestore.v1.Value; import java.util.ArrayList; import java.util.Collections; @@ -600,7 +600,7 @@ private static BooleanExpr whereConditionsFromCursor( } @NonNull - private Stage pipelineSource(FirebaseFirestore firestore) { + private BaseStage pipelineSource(FirebaseFirestore firestore) { if (isDocumentQuery()) { return new DocumentsSource(path.canonicalString()); } else if (isCollectionGroupQuery()) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index e3d02d19652..6b7e4546557 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -27,7 +27,7 @@ import com.google.firebase.firestore.util.Preconditions import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value -abstract class Stage> +abstract class BaseStage> internal constructor(protected val name: String, internal val options: InternalOptions) { internal fun toProtoStage(userDataReader: UserDataReader): Pipeline.Stage { val builder = Pipeline.Stage.newBuilder() @@ -96,32 +96,32 @@ internal constructor(protected val name: String, internal val options: InternalO * This class provides a way to call stages that are supported by the Firestore backend but that are * not implemented in the SDK version being used. */ -class GenericStage +class Stage private constructor( name: String, private val arguments: List, options: InternalOptions = InternalOptions.EMPTY -) : Stage(name, options) { +) : BaseStage(name, options) { companion object { /** * Specify name of stage * * @param name The unique name of the stage to add. - * @return [GenericStage] with specified parameters. + * @return [Stage] with specified parameters. */ - @JvmStatic fun ofName(name: String) = GenericStage(name, emptyList(), InternalOptions.EMPTY) + @JvmStatic fun ofName(name: String) = Stage(name, emptyList(), InternalOptions.EMPTY) } - override fun self(options: InternalOptions) = GenericStage(name, arguments, options) + override fun self(options: InternalOptions) = Stage(name, arguments, options) /** * Specify arguments to stage. * * @param arguments A list of ordered parameters to configure the stage's behavior. - * @return [GenericStage] with specified parameters. + * @return [Stage] with specified parameters. */ - fun withArguments(vararg arguments: Any): GenericStage = - GenericStage(name, arguments.map(GenericArg::from), options) + fun withArguments(vararg arguments: Any): Stage = + Stage(name, arguments.map(GenericArg::from), options) override fun args(userDataReader: UserDataReader): Sequence = arguments.asSequence().map { it.toProto(userDataReader) } @@ -167,7 +167,7 @@ internal sealed class GenericArg { internal class DatabaseSource @JvmOverloads internal constructor(options: InternalOptions = InternalOptions.EMPTY) : - Stage("database", options) { + BaseStage("database", options) { override fun self(options: InternalOptions) = DatabaseSource(options) override fun args(userDataReader: UserDataReader): Sequence = emptySequence() } @@ -178,7 +178,7 @@ internal constructor( // We validate [firestore.databaseId] when adding to pipeline. internal val firestore: FirebaseFirestore?, options: InternalOptions -) : Stage("collection", options) { +) : BaseStage("collection", options) { override fun self(options: InternalOptions): CollectionSource = CollectionSource(path, firestore, options) override fun args(userDataReader: UserDataReader): Sequence = @@ -216,7 +216,7 @@ internal constructor( class CollectionGroupSource private constructor(private val collectionId: String, options: InternalOptions) : - Stage("collection_group", options) { + BaseStage("collection_group", options) { override fun self(options: InternalOptions) = CollectionGroupSource(collectionId, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setReferenceValue("").build(), encodeValue(collectionId)) @@ -246,7 +246,7 @@ internal class DocumentsSource internal constructor( private val documents: Array, options: InternalOptions = InternalOptions.EMPTY -) : Stage("documents", options) { +) : BaseStage("documents", options) { internal constructor(document: String) : this(arrayOf(document)) override fun self(options: InternalOptions) = DocumentsSource(documents, options) override fun args(userDataReader: UserDataReader): Sequence = @@ -257,7 +257,7 @@ internal class AddFieldsStage internal constructor( private val fields: Array, options: InternalOptions = InternalOptions.EMPTY -) : Stage("add_fields", options) { +) : BaseStage("add_fields", options) { override fun self(options: InternalOptions) = AddFieldsStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) @@ -284,7 +284,7 @@ internal constructor( private val accumulators: Map, private val groups: Map, options: InternalOptions = InternalOptions.EMPTY -) : Stage("aggregate", options) { +) : BaseStage("aggregate", options) { private constructor(accumulators: Map) : this(accumulators, emptyMap()) companion object { @@ -349,7 +349,7 @@ internal class WhereStage internal constructor( private val condition: BooleanExpr, options: InternalOptions = InternalOptions.EMPTY -) : Stage("where", options) { +) : BaseStage("where", options) { override fun self(options: InternalOptions) = WhereStage(condition, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(condition.toProto(userDataReader)) @@ -365,7 +365,7 @@ internal constructor( private val vector: Expr, private val distanceMeasure: DistanceMeasure, options: InternalOptions = InternalOptions.EMPTY -) : Stage("find_nearest", options) { +) : BaseStage("find_nearest", options) { companion object { @@ -477,7 +477,7 @@ internal constructor( internal class LimitStage internal constructor(private val limit: Int, options: InternalOptions = InternalOptions.EMPTY) : - Stage("limit", options) { + BaseStage("limit", options) { override fun self(options: InternalOptions) = LimitStage(limit, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(limit)) @@ -485,7 +485,7 @@ internal constructor(private val limit: Int, options: InternalOptions = Internal internal class OffsetStage internal constructor(private val offset: Int, options: InternalOptions = InternalOptions.EMPTY) : - Stage("offset", options) { + BaseStage("offset", options) { override fun self(options: InternalOptions) = OffsetStage(offset, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(offset)) @@ -495,7 +495,7 @@ internal class SelectStage internal constructor( private val fields: Array, options: InternalOptions = InternalOptions.EMPTY -) : Stage("select", options) { +) : BaseStage("select", options) { override fun self(options: InternalOptions) = SelectStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) @@ -505,7 +505,7 @@ internal class SortStage internal constructor( private val orders: Array, options: InternalOptions = InternalOptions.EMPTY -) : Stage("sort", options) { +) : BaseStage("sort", options) { override fun self(options: InternalOptions) = SortStage(orders, options) override fun args(userDataReader: UserDataReader): Sequence = orders.asSequence().map { it.toProto(userDataReader) } @@ -515,7 +515,7 @@ internal class DistinctStage internal constructor( private val groups: Array, options: InternalOptions = InternalOptions.EMPTY -) : Stage("distinct", options) { +) : BaseStage("distinct", options) { override fun self(options: InternalOptions) = DistinctStage(groups, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(groups.associate { it.getAlias() to it.toProto(userDataReader) })) @@ -525,7 +525,7 @@ internal class RemoveFieldsStage internal constructor( private val fields: Array, options: InternalOptions = InternalOptions.EMPTY -) : Stage("remove_fields", options) { +) : BaseStage("remove_fields", options) { override fun self(options: InternalOptions) = RemoveFieldsStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = fields.asSequence().map(Field::toProto) @@ -536,7 +536,7 @@ internal constructor( private val mapValue: Expr, private val mode: Mode, options: InternalOptions = InternalOptions.EMPTY -) : Stage("replace", options) { +) : BaseStage("replace", options) { class Mode private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) companion object { @@ -563,7 +563,7 @@ private constructor( private val size: Number, private val mode: Mode, options: InternalOptions = InternalOptions.EMPTY -) : Stage("sample", options) { +) : BaseStage("sample", options) { override fun self(options: InternalOptions) = SampleStage(size, mode, options) class Mode private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) @@ -606,7 +606,7 @@ internal class UnionStage internal constructor( private val other: com.google.firebase.firestore.Pipeline, options: InternalOptions = InternalOptions.EMPTY -) : Stage("union", options) { +) : BaseStage("union", options) { override fun self(options: InternalOptions) = UnionStage(other, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setPipelineValue(other.toPipelineProto()).build()) @@ -620,7 +620,7 @@ class UnnestStage internal constructor( private val selectable: Selectable, options: InternalOptions = InternalOptions.EMPTY -) : Stage("unnest", options) { +) : BaseStage("unnest", options) { companion object { /** From d452eb30f42d340ea0c4be5cd000d74fc15456fb Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 23 May 2025 10:07:37 -0400 Subject: [PATCH 69/77] Make SDK version 23 compatible. --- .../google/firebase/firestore/core/Query.java | 35 +++++++++++++++---- .../firebase/firestore/util/BiFunction.java | 7 ++++ .../firebase/firestore/util/IntFunction.java | 7 ++++ 3 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/util/BiFunction.java create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/util/IntFunction.java diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index 2aebd7e988c..ac4d499854f 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -38,6 +38,9 @@ import com.google.firebase.firestore.pipeline.InternalOptions; import com.google.firebase.firestore.pipeline.Ordering; import com.google.firebase.firestore.pipeline.BaseStage; +import com.google.firebase.firestore.util.BiFunction; +import com.google.firebase.firestore.util.Function; +import com.google.firebase.firestore.util.IntFunction; import com.google.firestore.v1.Value; import java.util.ArrayList; import java.util.Collections; @@ -46,7 +49,6 @@ import java.util.List; import java.util.SortedSet; import java.util.TreeSet; -import java.util.function.BiFunction; /** * Encapsulates all the query attributes we support in the SDK. It can be run against the @@ -547,8 +549,7 @@ public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataR if (fields.size() == 1) { p = p.where(fields.get(0).exists()); } else { - BooleanExpr[] conditions = - fields.stream().skip(1).map(Expr.Companion::exists).toArray(BooleanExpr[]::new); + BooleanExpr[] conditions = skipFirstToArray(fields, BooleanExpr[]::new, Expr.Companion::exists); p = p.where(and(fields.get(0).exists(), conditions)); } @@ -564,23 +565,43 @@ public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataR if (hasLimit()) { // TODO: Handle situation where user enters limit larger than integer. if (limitType == LimitType.LIMIT_TO_FIRST) { - p = p.sort(orderings.get(0), orderings.stream().skip(1).toArray(Ordering[]::new)); + p = p.sort(orderings.get(0), skipFirstToArray(orderings, Ordering[]::new)); p = p.limit((int) limit); } else { p = p.sort( orderings.get(0).reverse(), - orderings.stream().skip(1).map(Ordering::reverse).toArray(Ordering[]::new)); + skipFirstToArray(orderings, Ordering[]::new, Ordering::reverse)); p = p.limit((int) limit); - p = p.sort(orderings.get(0), orderings.stream().skip(1).toArray(Ordering[]::new)); + p = p.sort(orderings.get(0), skipFirstToArray(orderings, Ordering[]::new)); } } else { - p = p.sort(orderings.get(0), orderings.stream().skip(1).toArray(Ordering[]::new)); + p = p.sort(orderings.get(0), skipFirstToArray(orderings, Ordering[]::new)); } return p; } + // Many Pipelines require first parameter to be separated out from rest. + private static T[] skipFirstToArray(List list, IntFunction generator) { + int size = list.size(); + T[] result = generator.apply(size - 1); + for (int i = 1; i < size; i++) { + result[i-1] = list.get(i); + } + return result; + } + + // Many Pipelines require first parameter to be separated out from rest. + private static R[] skipFirstToArray(List list, IntFunction generator, Function map) { + int size = list.size(); + R[] result = generator.apply(size - 1); + for (int i = 1; i < size; i++) { + result[i-1] = map.apply(list.get(i)); + } + return result; + } + private static BooleanExpr whereConditionsFromCursor( Bound bound, List fields, BiFunction cmp) { List boundPosition = bound.getPosition(); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/BiFunction.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/BiFunction.java new file mode 100644 index 00000000000..1afb87fbb1d --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/BiFunction.java @@ -0,0 +1,7 @@ +package com.google.firebase.firestore.util; + +/** A port of {@link java.util.function.BiFunction} */ +@FunctionalInterface +public interface BiFunction { + R apply(T t, U u); +} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/IntFunction.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/IntFunction.java new file mode 100644 index 00000000000..2407db54808 --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/IntFunction.java @@ -0,0 +1,7 @@ +package com.google.firebase.firestore.util; + +/** A port of {@link java.util.function.IntFunction} */ +@FunctionalInterface +public interface IntFunction { + R apply(int value); +} From 93a44a7fba95297851fc45b4febb80b1ab2d0611 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 23 May 2025 15:30:52 -0400 Subject: [PATCH 70/77] Fix query to pipeline logic. --- .../firebase/firestore/QueryToPipelineTest.java | 2 +- .../firestore/testutil/IntegrationTestUtil.java | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java index 4bf391df465..f4da3ce2856 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java @@ -356,7 +356,7 @@ public void testQueriesCanUseNotEqualFilters() { expectedDocsMap.remove("i"); expectedDocsMap.remove("j"); snapshot = - waitFor(db.pipeline().convertFrom(collection.whereEqualTo("zip", Double.NaN)).execute()); + waitFor(db.pipeline().convertFrom(collection.whereNotEqualTo("zip", Double.NaN)).execute()); assertEquals(Lists.newArrayList(expectedDocsMap.values()), pipelineSnapshotToValues(snapshot)); } diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java index bea8743e0ba..717e3f02ebc 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java @@ -567,9 +567,18 @@ public static void checkOnlineAndOfflineResultsMatch(Query query, String... expe * @param expectedDocs Ordered list of document keys that are expected to match the query */ public static void checkQueryAndPipelineResultsMatch(Query query, String... expectedDocs) { - QuerySnapshot docsFromQuery = waitFor(query.get(Source.SERVER)); - PipelineSnapshot docsFromPipeline = - waitFor(query.getFirestore().pipeline().convertFrom(query).execute()); + QuerySnapshot docsFromQuery; + try { + docsFromQuery = waitFor(query.get(Source.SERVER)); + } catch (Exception e) { + throw new RuntimeException("Classic Query FAILED", e); + } + PipelineSnapshot docsFromPipeline; + try { + docsFromPipeline = waitFor(query.getFirestore().pipeline().convertFrom(query).execute()); + } catch (Exception e) { + throw new RuntimeException("Pipeline FAILED", e); + } assertEquals(querySnapshotToIds(docsFromQuery), pipelineSnapshotToIds(docsFromPipeline)); List expected = asList(expectedDocs); From 96aac51e7ca60ee6c2abb4077f34650ca7693bcb Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 23 May 2025 15:32:51 -0400 Subject: [PATCH 71/77] Fix query to pipeline logic. --- firebase-firestore/api.txt | 94 ++++++++++--------- .../firebase/firestore/core/FieldFilter.java | 47 ++++++++-- .../google/firebase/firestore/model/Values.kt | 8 +- .../firestore/pipeline/expressions.kt | 19 ++++ 4 files changed, 114 insertions(+), 54 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index 9e981a511c1..cb86b4b0932 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -421,6 +421,7 @@ package com.google.firebase.firestore { public final class Pipeline { method public com.google.firebase.firestore.Pipeline addFields(com.google.firebase.firestore.pipeline.Selectable field, com.google.firebase.firestore.pipeline.Selectable... additionalFields); + method public com.google.firebase.firestore.Pipeline addStage(com.google.firebase.firestore.pipeline.Stage stage); method public com.google.firebase.firestore.Pipeline aggregate(com.google.firebase.firestore.pipeline.AggregateStage aggregateStage); method public com.google.firebase.firestore.Pipeline aggregate(com.google.firebase.firestore.pipeline.AggregateWithAlias accumulator, com.google.firebase.firestore.pipeline.AggregateWithAlias... additionalAccumulators); method public com.google.firebase.firestore.Pipeline distinct(com.google.firebase.firestore.pipeline.Selectable group, java.lang.Object... additionalGroups); @@ -432,7 +433,6 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline findNearest(com.google.firebase.firestore.pipeline.FindNearestStage stage); method public com.google.firebase.firestore.Pipeline findNearest(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public com.google.firebase.firestore.Pipeline findNearest(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); - method public com.google.firebase.firestore.Pipeline genericStage(com.google.firebase.firestore.pipeline.GenericStage stage); method public com.google.firebase.firestore.Pipeline limit(int limit); method public com.google.firebase.firestore.Pipeline offset(int offset); method public com.google.firebase.firestore.Pipeline removeFields(com.google.firebase.firestore.pipeline.Field field, com.google.firebase.firestore.pipeline.Field... additionalFields); @@ -722,7 +722,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.AggregateFunction sum(String fieldName); } - public final class AggregateStage extends com.google.firebase.firestore.pipeline.Stage { + public final class AggregateStage extends com.google.firebase.firestore.pipeline.BaseStage { method public static com.google.firebase.firestore.pipeline.AggregateStage withAccumulators(com.google.firebase.firestore.pipeline.AggregateWithAlias accumulator, com.google.firebase.firestore.pipeline.AggregateWithAlias... additionalAccumulators); method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(com.google.firebase.firestore.pipeline.Selectable group, java.lang.Object... additionalGroups); method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(String groupField, java.lang.Object... additionalGroups); @@ -736,6 +736,17 @@ package com.google.firebase.firestore.pipeline { public final class AggregateWithAlias { } + public abstract class BaseStage> { + method protected final String getName(); + method public final T with(String key, boolean value); + method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); + method public final T with(String key, double value); + method protected final T with(String key, error.NonExistentClass value); + method public final T with(String key, String value); + method public final T with(String key, long value); + property protected final String name; + } + public class BooleanExpr extends com.google.firebase.firestore.pipeline.FunctionExpr { method public final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.Expr thenExpr, com.google.firebase.firestore.pipeline.Expr elseExpr); method public final com.google.firebase.firestore.pipeline.Expr cond(Object thenValue, Object elseValue); @@ -749,7 +760,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); } - public final class CollectionGroupSource extends com.google.firebase.firestore.pipeline.Stage { + public final class CollectionGroupSource extends com.google.firebase.firestore.pipeline.BaseStage { method public static com.google.firebase.firestore.pipeline.CollectionGroupSource of(String collectionId); method public error.NonExistentClass withForceIndex(String value); field public static final com.google.firebase.firestore.pipeline.CollectionGroupSource.Companion Companion; @@ -759,7 +770,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.CollectionGroupSource of(String collectionId); } - public final class CollectionSource extends com.google.firebase.firestore.pipeline.Stage { + public final class CollectionSource extends com.google.firebase.firestore.pipeline.BaseStage { method public static com.google.firebase.firestore.pipeline.CollectionSource of(com.google.firebase.firestore.CollectionReference ref); method public static com.google.firebase.firestore.pipeline.CollectionSource of(String path); method public error.NonExistentClass withForceIndex(String value); @@ -825,12 +836,12 @@ package com.google.firebase.firestore.pipeline { } public abstract class Expr { - method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Number second, java.lang.Object... others); - method public final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public final com.google.firebase.firestore.pipeline.Expr add(Number second, java.lang.Object... others); - method public static final com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public static final com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, Number second, java.lang.Object... others); + method public final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr second); + method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second); + method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Number second); + method public final com.google.firebase.firestore.pipeline.Expr add(Number second); + method public static final com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second); + method public static final com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, Number second); method public com.google.firebase.firestore.pipeline.ExprWithAlias alias(String alias); method public static final com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); @@ -1003,6 +1014,7 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.BooleanExpr gte(Object value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); method public static final com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object value); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr ifError(com.google.firebase.firestore.pipeline.BooleanExpr tryExpr, com.google.firebase.firestore.pipeline.BooleanExpr catchExpr); method public final com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr catchExpr); method public static final com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr tryExpr, com.google.firebase.firestore.pipeline.Expr catchExpr); method public static final com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr tryExpr, Object catchValue); @@ -1069,12 +1081,12 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.Expr mod(Number divisor); method public static final com.google.firebase.firestore.pipeline.Expr mod(String dividendFieldName, com.google.firebase.firestore.pipeline.Expr divisor); method public static final com.google.firebase.firestore.pipeline.Expr mod(String dividendFieldName, Number divisor); - method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, Number second, java.lang.Object... others); - method public final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public final com.google.firebase.firestore.pipeline.Expr multiply(Number second, java.lang.Object... others); - method public static final com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public static final com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, Number second, java.lang.Object... others); + method public final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr second); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, Number second); + method public final com.google.firebase.firestore.pipeline.Expr multiply(Number second); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second); + method public static final com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, Number second); method public final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr other); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public static final com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); @@ -1211,10 +1223,10 @@ package com.google.firebase.firestore.pipeline { } public static final class Expr.Companion { - method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Number second, java.lang.Object... others); - method public com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, Number second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second); + method public com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, Number second); + method public com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second); + method public com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, Number second); method public com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, Object secondArray, java.lang.Object... otherArrays); @@ -1332,6 +1344,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr gte(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); method public com.google.firebase.firestore.pipeline.BooleanExpr gte(String fieldName, Object value); + method public com.google.firebase.firestore.pipeline.BooleanExpr ifError(com.google.firebase.firestore.pipeline.BooleanExpr tryExpr, com.google.firebase.firestore.pipeline.BooleanExpr catchExpr); method public com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr tryExpr, com.google.firebase.firestore.pipeline.Expr catchExpr); method public com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr tryExpr, Object catchValue); method public com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(com.google.firebase.firestore.pipeline.Expr value); @@ -1373,10 +1386,10 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr mod(com.google.firebase.firestore.pipeline.Expr dividend, Number divisor); method public com.google.firebase.firestore.pipeline.Expr mod(String dividendFieldName, com.google.firebase.firestore.pipeline.Expr divisor); method public com.google.firebase.firestore.pipeline.Expr mod(String dividendFieldName, Number divisor); - method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, Number second, java.lang.Object... others); - method public com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second, java.lang.Object... others); - method public com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, Number second, java.lang.Object... others); + method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second); + method public com.google.firebase.firestore.pipeline.Expr multiply(com.google.firebase.firestore.pipeline.Expr first, Number second); + method public com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second); + method public com.google.firebase.firestore.pipeline.Expr multiply(String numericFieldName, Number second); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, com.google.firebase.firestore.pipeline.Expr right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(com.google.firebase.firestore.pipeline.Expr left, Object right); method public com.google.firebase.firestore.pipeline.BooleanExpr neq(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); @@ -1479,7 +1492,7 @@ package com.google.firebase.firestore.pipeline { public static final class Field.Companion { } - public final class FindNearestStage extends com.google.firebase.firestore.pipeline.Stage { + public final class FindNearestStage extends com.google.firebase.firestore.pipeline.BaseStage { method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public static com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); @@ -1518,16 +1531,6 @@ package com.google.firebase.firestore.pipeline { public static final class GenericOptions.Companion { } - public final class GenericStage extends com.google.firebase.firestore.pipeline.Stage { - method public static com.google.firebase.firestore.pipeline.GenericStage ofName(String name); - method public com.google.firebase.firestore.pipeline.GenericStage withArguments(java.lang.Object... arguments); - field public static final com.google.firebase.firestore.pipeline.GenericStage.Companion Companion; - } - - public static final class GenericStage.Companion { - method public com.google.firebase.firestore.pipeline.GenericStage ofName(String name); - } - public final class InternalOptions { field public static final com.google.firebase.firestore.pipeline.InternalOptions.Companion Companion; field public static final com.google.firebase.firestore.pipeline.InternalOptions EMPTY; @@ -1573,7 +1576,7 @@ package com.google.firebase.firestore.pipeline { public static final class PipelineOptions.IndexMode.Companion { } - public final class SampleStage extends com.google.firebase.firestore.pipeline.Stage { + public final class SampleStage extends com.google.firebase.firestore.pipeline.BaseStage { method public static com.google.firebase.firestore.pipeline.SampleStage withDocLimit(int documents); method public static com.google.firebase.firestore.pipeline.SampleStage withPercentage(double percentage); field public static final com.google.firebase.firestore.pipeline.SampleStage.Companion Companion; @@ -1599,18 +1602,17 @@ package com.google.firebase.firestore.pipeline { ctor public Selectable(); } - public abstract class Stage> { - method protected final String getName(); - method public final T with(String key, boolean value); - method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); - method public final T with(String key, double value); - method protected final T with(String key, error.NonExistentClass value); - method public final T with(String key, String value); - method public final T with(String key, long value); - property protected final String name; + public final class Stage extends com.google.firebase.firestore.pipeline.BaseStage { + method public static com.google.firebase.firestore.pipeline.Stage ofName(String name); + method public com.google.firebase.firestore.pipeline.Stage withArguments(java.lang.Object... arguments); + field public static final com.google.firebase.firestore.pipeline.Stage.Companion Companion; + } + + public static final class Stage.Companion { + method public com.google.firebase.firestore.pipeline.Stage ofName(String name); } - public final class UnnestStage extends com.google.firebase.firestore.pipeline.Stage { + public final class UnnestStage extends com.google.firebase.firestore.pipeline.BaseStage { method public static com.google.firebase.firestore.pipeline.UnnestStage withField(com.google.firebase.firestore.pipeline.Selectable arrayWithAlias); method public static com.google.firebase.firestore.pipeline.UnnestStage withField(String arrayField, String alias); method public com.google.firebase.firestore.pipeline.UnnestStage withIndexField(String indexField); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java index 20dd9ad585a..f8ceb77baa8 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java @@ -14,17 +14,23 @@ package com.google.firebase.firestore.core; +import static com.google.firebase.firestore.model.Values.isNanValue; import static com.google.firebase.firestore.pipeline.Expr.and; +import static com.google.firebase.firestore.pipeline.Expr.ifError; import static com.google.firebase.firestore.util.Assert.hardAssert; -import static java.lang.Double.isNaN; + +import androidx.annotation.NonNull; import com.google.firebase.firestore.model.Document; import com.google.firebase.firestore.model.FieldPath; import com.google.firebase.firestore.model.Values; import com.google.firebase.firestore.pipeline.BooleanExpr; +import com.google.firebase.firestore.pipeline.Expr; import com.google.firebase.firestore.pipeline.Field; import com.google.firebase.firestore.util.Assert; import com.google.firestore.v1.Value; + +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -188,16 +194,18 @@ BooleanExpr toPipelineExpr() { case EQUAL: if (value.hasNullValue()) { return and(exists, x.isNull()); - } else if (value.hasDoubleValue() && isNaN(value.getDoubleValue())) { - return and(exists, x.isNan()); + } else if (isNanValue(value)) { + // The isNotNan will error on non-numeric values. + return and(exists, ifError(x.isNan(), Expr.constant(false))); } else { return and(exists, x.eq(value)); } case NOT_EQUAL: if (value.hasNullValue()) { return and(exists, x.isNotNull()); - } else if (value.hasDoubleValue() && isNaN(value.getDoubleValue())) { - return and(exists, x.isNotNan()); + } else if (isNanValue(value)) { + // The isNotNan will error on non-numeric values. + return and(exists, ifError(x.isNotNan(), Expr.constant(true))); } else { return and(exists, x.neq(value)); } @@ -211,14 +219,39 @@ BooleanExpr toPipelineExpr() { return and(exists, x.arrayContainsAny(value.getArrayValue().getValuesList())); case IN: return and(exists, x.eqAny(value.getArrayValue().getValuesList())); - case NOT_IN: - return and(exists, x.notEqAny(value.getArrayValue().getValuesList())); + case NOT_IN: { + List list = value.getArrayValue().getValuesList(); + if (hasNaN(list)) { + return and(exists, x.notEqAny(filterNaN(list)), ifError(x.isNotNan(), Expr.constant(true))); + } else { + return and(exists, x.notEqAny(list)); + } + } default: // Handle OPERATOR_UNSPECIFIED and UNRECOGNIZED cases as needed throw new IllegalArgumentException("Unsupported operator: " + operator); } } + private static boolean hasNaN(List list) { + for (Value v : list) { + if (isNanValue(v)) { + return true; + } + } + return false; + } + + @NonNull + private static List filterNaN(List list) { + List listWithoutNan = new ArrayList<>(list.size() - 1); + for (Value v : list) { + if (isNanValue(v)) continue; + listWithoutNan.add(v); + } + return listWithoutNan; + } + @Override public String toString() { return getCanonicalId(); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt index 3bcd2ed3c38..568a64899ec 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt @@ -599,8 +599,14 @@ internal object Values { .build() } + @JvmField + val TRUE: Value = Value.newBuilder().setBooleanValue(true).build() + + @JvmField + val FALSE: Value = Value.newBuilder().setBooleanValue(false).build() + @JvmStatic - fun encodeValue(value: Boolean): Value = Value.newBuilder().setBooleanValue(value).build() + fun encodeValue(value: Boolean): Value = if (value) TRUE else FALSE @JvmStatic fun encodeValue(geoPoint: GeoPoint): Value = diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 4b4d783ee89..5eb5e6c3698 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -2838,6 +2838,20 @@ abstract class Expr internal constructor() { @JvmStatic fun ifError(tryExpr: Expr, catchExpr: Expr): Expr = FunctionExpr("if_error", tryExpr, catchExpr) + /** + * Creates an expression that returns the [catchExpr] argument if there is an error, else return + * the result of the [tryExpr] argument evaluation. + * + * This overload will return [BooleanExpr] when both parameters are also [BooleanExpr]. + * + * @param tryExpr The try boolean expression. + * @param catchExpr The catch boolean expression that will be evaluated and returned if the [tryExpr] + * produces an error. + * @return A new [BooleanExpr] representing the ifError operation. + */ + @JvmStatic + fun ifError(tryExpr: BooleanExpr, catchExpr: BooleanExpr): BooleanExpr = BooleanExpr("if_error", tryExpr, catchExpr) + /** * Creates an expression that returns the [catchValue] argument if there is an error, else * return the result of the [tryExpr] argument evaluation. @@ -4055,6 +4069,11 @@ internal constructor( open class BooleanExpr internal constructor(name: String, params: Array) : FunctionExpr(name, params, InternalOptions.EMPTY) { internal constructor(name: String, param: Expr) : this(name, arrayOf(param)) + internal constructor( + name: String, + param1: Expr, + param2: Any + ) : this(name, arrayOf(param1, toExprOrConstant(param2))) internal constructor( name: String, param: Expr, From 385d3cff0fab32b5abf5662c817161e006352049 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 23 May 2025 15:37:02 -0400 Subject: [PATCH 72/77] Fix query to pipeline logic. --- .../java/com/google/firebase/firestore/core/FieldFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java index f8ceb77baa8..b702746f066 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java @@ -195,7 +195,7 @@ BooleanExpr toPipelineExpr() { if (value.hasNullValue()) { return and(exists, x.isNull()); } else if (isNanValue(value)) { - // The isNotNan will error on non-numeric values. + // The isNan will error on non-numeric values. return and(exists, ifError(x.isNan(), Expr.constant(false))); } else { return and(exists, x.eq(value)); From 9f9f95ae44fc3baf698e744ddf8c002390a416c0 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Fri, 23 May 2025 16:15:12 -0400 Subject: [PATCH 73/77] small refactor --- .../firestore/QueryToPipelineTest.java | 48 +++++++------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java index f4da3ce2856..942d6291668 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java @@ -613,53 +613,41 @@ public void testQueriesCanUseArrayContainsAnyFilters() { FirebaseFirestore db = collection.firestore; // Search for "array" to contain [42, 43]. - PipelineSnapshot snapshot = - waitFor( - db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", asList(42L, 43L))) - .execute()); + Pipeline pipeline = db.pipeline() + .convertFrom(collection.whereArrayContainsAny("array", asList(42L, 43L))); + PipelineSnapshot snapshot = waitFor(pipeline.execute()); assertEquals(asList(docA, docB, docD, docE), pipelineSnapshotToValues(snapshot)); // With objects. - snapshot = - waitFor( - db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", asList(map("a", 42L)))) - .execute()); + pipeline = db.pipeline() + .convertFrom(collection.whereArrayContainsAny("array", asList(map("a", 42L)))); + snapshot = waitFor(pipeline.execute()); assertEquals(asList(docF), pipelineSnapshotToValues(snapshot)); // With null. - snapshot = - waitFor( - db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", nullList())) - .execute()); + pipeline = db.pipeline() + .convertFrom(collection.whereArrayContainsAny("array", nullList())); + snapshot = waitFor(pipeline.execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With null and a value. List inputList = nullList(); inputList.add(43L); - snapshot = - waitFor( - db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", inputList)) - .execute()); + pipeline = db.pipeline() + .convertFrom(collection.whereArrayContainsAny("array", inputList)); + snapshot = waitFor(pipeline.execute()); assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); // With NaN. - snapshot = - waitFor( - db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN))) - .execute()); + pipeline = db.pipeline() + .convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN))); + snapshot = waitFor(pipeline.execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With NaN and a value. - snapshot = - waitFor( - db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN, 43L))) - .execute()); + pipeline = db.pipeline() + .convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN, 43L))); + snapshot = waitFor(pipeline.execute()); assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); } From 45280be8a9c7c0f4b1269c8e8f46c5330843dca4 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 5 Jun 2025 10:14:38 -0400 Subject: [PATCH 74/77] Fixes, addition, whitespace. --- firebase-firestore/api.txt | 66 ++++--- .../firebase/firestore/PipelineTest.java | 13 +- .../firestore/QueryToPipelineTest.java | 23 ++- .../testutil/IntegrationTestUtil.java | 2 +- .../com/google/firebase/firestore/Pipeline.kt | 20 +- .../firebase/firestore/core/FieldFilter.java | 18 +- .../google/firebase/firestore/core/Query.java | 14 +- .../google/firebase/firestore/model/Values.kt | 9 +- .../firestore/pipeline/expressions.kt | 185 ++++++++++++------ .../firebase/firestore/pipeline/stage.kt | 54 ++--- 10 files changed, 236 insertions(+), 168 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index cb86b4b0932..dd6a20ddcc8 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -421,7 +421,6 @@ package com.google.firebase.firestore { public final class Pipeline { method public com.google.firebase.firestore.Pipeline addFields(com.google.firebase.firestore.pipeline.Selectable field, com.google.firebase.firestore.pipeline.Selectable... additionalFields); - method public com.google.firebase.firestore.Pipeline addStage(com.google.firebase.firestore.pipeline.Stage stage); method public com.google.firebase.firestore.Pipeline aggregate(com.google.firebase.firestore.pipeline.AggregateStage aggregateStage); method public com.google.firebase.firestore.Pipeline aggregate(com.google.firebase.firestore.pipeline.AggregateWithAlias accumulator, com.google.firebase.firestore.pipeline.AggregateWithAlias... additionalAccumulators); method public com.google.firebase.firestore.Pipeline distinct(com.google.firebase.firestore.pipeline.Selectable group, java.lang.Object... additionalGroups); @@ -435,6 +434,7 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline findNearest(String vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public com.google.firebase.firestore.Pipeline limit(int limit); method public com.google.firebase.firestore.Pipeline offset(int offset); + method public com.google.firebase.firestore.Pipeline rawStage(com.google.firebase.firestore.pipeline.RawStage rawStage); method public com.google.firebase.firestore.Pipeline removeFields(com.google.firebase.firestore.pipeline.Field field, com.google.firebase.firestore.pipeline.Field... additionalFields); method public com.google.firebase.firestore.Pipeline removeFields(String field, java.lang.String... additionalFields); method public com.google.firebase.firestore.Pipeline replace(com.google.firebase.firestore.pipeline.Expr mapValue); @@ -722,7 +722,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.AggregateFunction sum(String fieldName); } - public final class AggregateStage extends com.google.firebase.firestore.pipeline.BaseStage { + public final class AggregateStage extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.AggregateStage withAccumulators(com.google.firebase.firestore.pipeline.AggregateWithAlias accumulator, com.google.firebase.firestore.pipeline.AggregateWithAlias... additionalAccumulators); method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(com.google.firebase.firestore.pipeline.Selectable group, java.lang.Object... additionalGroups); method public com.google.firebase.firestore.pipeline.AggregateStage withGroups(String groupField, java.lang.Object... additionalGroups); @@ -736,22 +736,12 @@ package com.google.firebase.firestore.pipeline { public final class AggregateWithAlias { } - public abstract class BaseStage> { - method protected final String getName(); - method public final T with(String key, boolean value); - method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); - method public final T with(String key, double value); - method protected final T with(String key, error.NonExistentClass value); - method public final T with(String key, String value); - method public final T with(String key, long value); - property protected final String name; - } - public class BooleanExpr extends com.google.firebase.firestore.pipeline.FunctionExpr { method public final com.google.firebase.firestore.pipeline.Expr cond(com.google.firebase.firestore.pipeline.Expr thenExpr, com.google.firebase.firestore.pipeline.Expr elseExpr); method public final com.google.firebase.firestore.pipeline.Expr cond(Object thenValue, Object elseValue); method public final com.google.firebase.firestore.pipeline.AggregateFunction countIf(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); + method public final com.google.firebase.firestore.pipeline.BooleanExpr ifError(com.google.firebase.firestore.pipeline.BooleanExpr catchExpr); method public final com.google.firebase.firestore.pipeline.BooleanExpr not(); field public static final com.google.firebase.firestore.pipeline.BooleanExpr.Companion Companion; } @@ -760,7 +750,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); } - public final class CollectionGroupSource extends com.google.firebase.firestore.pipeline.BaseStage { + public final class CollectionGroupSource extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.CollectionGroupSource of(String collectionId); method public error.NonExistentClass withForceIndex(String value); field public static final com.google.firebase.firestore.pipeline.CollectionGroupSource.Companion Companion; @@ -770,7 +760,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.CollectionGroupSource of(String collectionId); } - public final class CollectionSource extends com.google.firebase.firestore.pipeline.BaseStage { + public final class CollectionSource extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.CollectionSource of(com.google.firebase.firestore.CollectionReference ref); method public static com.google.firebase.firestore.pipeline.CollectionSource of(String path); method public error.NonExistentClass withForceIndex(String value); @@ -844,6 +834,8 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, Number second); method public com.google.firebase.firestore.pipeline.ExprWithAlias alias(String alias); method public static final com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + method public static final com.google.firebase.firestore.pipeline.Expr array(java.lang.Object?... elements); + method public static final com.google.firebase.firestore.pipeline.Expr array(java.util.List elements); method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); method public static final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, Object secondArray, java.lang.Object... otherArrays); method public final com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); @@ -915,6 +907,7 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr bitsOther); method public static final com.google.firebase.firestore.pipeline.Expr bitXor(String bitsFieldName, byte[] bitsOther); method public static final com.google.firebase.firestore.pipeline.Expr bitXor(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public static final com.google.firebase.firestore.pipeline.Expr blob(byte[] bytes); method public final com.google.firebase.firestore.pipeline.Expr byteLength(); method public static final com.google.firebase.firestore.pipeline.Expr byteLength(com.google.firebase.firestore.pipeline.Expr value); method public static final com.google.firebase.firestore.pipeline.Expr byteLength(String fieldName); @@ -1022,6 +1015,8 @@ package com.google.firebase.firestore.pipeline { method public final com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(com.google.firebase.firestore.pipeline.Expr value); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(String fieldName); + method public final com.google.firebase.firestore.pipeline.BooleanExpr isError(); + method public static final com.google.firebase.firestore.pipeline.BooleanExpr isError(com.google.firebase.firestore.pipeline.Expr expr); method public final com.google.firebase.firestore.pipeline.BooleanExpr isNan(); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); method public static final com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); @@ -1061,8 +1056,10 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object value); method public static final com.google.firebase.firestore.pipeline.Expr map(java.util.Map elements); + method public static final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr mapExpression, com.google.firebase.firestore.pipeline.Expr keyExpression); method public static final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr mapExpression, String key); method public final com.google.firebase.firestore.pipeline.Expr mapGet(String key); + method public static final com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr keyExpression); method public static final com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, String key); method public static final com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); method public final com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr mapExpr, com.google.firebase.firestore.pipeline.Expr... otherMaps); @@ -1228,6 +1225,8 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, com.google.firebase.firestore.pipeline.Expr second); method public com.google.firebase.firestore.pipeline.Expr add(String numericFieldName, Number second); method public com.google.firebase.firestore.pipeline.BooleanExpr and(com.google.firebase.firestore.pipeline.BooleanExpr condition, com.google.firebase.firestore.pipeline.BooleanExpr... conditions); + method public com.google.firebase.firestore.pipeline.Expr array(java.lang.Object?... elements); + method public com.google.firebase.firestore.pipeline.Expr array(java.util.List elements); method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); method public com.google.firebase.firestore.pipeline.Expr arrayConcat(com.google.firebase.firestore.pipeline.Expr firstArray, Object secondArray, java.lang.Object... otherArrays); method public com.google.firebase.firestore.pipeline.Expr arrayConcat(String firstArrayField, com.google.firebase.firestore.pipeline.Expr secondArray, java.lang.Object... otherArrays); @@ -1274,6 +1273,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr bitXor(com.google.firebase.firestore.pipeline.Expr bits, com.google.firebase.firestore.pipeline.Expr bitsOther); method public com.google.firebase.firestore.pipeline.Expr bitXor(String bitsFieldName, byte[] bitsOther); method public com.google.firebase.firestore.pipeline.Expr bitXor(String bitsFieldName, com.google.firebase.firestore.pipeline.Expr bitsOther); + method public com.google.firebase.firestore.pipeline.Expr blob(byte[] bytes); method public com.google.firebase.firestore.pipeline.Expr byteLength(com.google.firebase.firestore.pipeline.Expr value); method public com.google.firebase.firestore.pipeline.Expr byteLength(String fieldName); method public com.google.firebase.firestore.pipeline.Expr ceil(com.google.firebase.firestore.pipeline.Expr numericExpr); @@ -1349,6 +1349,7 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.Expr ifError(com.google.firebase.firestore.pipeline.Expr tryExpr, Object catchValue); method public com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(com.google.firebase.firestore.pipeline.Expr value); method public com.google.firebase.firestore.pipeline.BooleanExpr isAbsent(String fieldName); + method public com.google.firebase.firestore.pipeline.BooleanExpr isError(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(com.google.firebase.firestore.pipeline.Expr expr); method public com.google.firebase.firestore.pipeline.BooleanExpr isNan(String fieldName); method public com.google.firebase.firestore.pipeline.BooleanExpr isNotNan(com.google.firebase.firestore.pipeline.Expr expr); @@ -1374,7 +1375,9 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); method public com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object value); method public com.google.firebase.firestore.pipeline.Expr map(java.util.Map elements); + method public com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr mapExpression, com.google.firebase.firestore.pipeline.Expr keyExpression); method public com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr mapExpression, String key); + method public com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, com.google.firebase.firestore.pipeline.Expr keyExpression); method public com.google.firebase.firestore.pipeline.Expr mapGet(String fieldName, String key); method public com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); method public com.google.firebase.firestore.pipeline.Expr mapMerge(String firstMapFieldName, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); @@ -1492,7 +1495,7 @@ package com.google.firebase.firestore.pipeline { public static final class Field.Companion { } - public final class FindNearestStage extends com.google.firebase.firestore.pipeline.BaseStage { + public final class FindNearestStage extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public static com.google.firebase.firestore.pipeline.FindNearestStage of(com.google.firebase.firestore.pipeline.Field vectorField, double[] vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); method public static com.google.firebase.firestore.pipeline.FindNearestStage of(String vectorField, com.google.firebase.firestore.VectorValue vectorValue, com.google.firebase.firestore.pipeline.FindNearestStage.DistanceMeasure distanceMeasure); @@ -1576,7 +1579,17 @@ package com.google.firebase.firestore.pipeline { public static final class PipelineOptions.IndexMode.Companion { } - public final class SampleStage extends com.google.firebase.firestore.pipeline.BaseStage { + public final class RawStage extends com.google.firebase.firestore.pipeline.Stage { + method public static com.google.firebase.firestore.pipeline.RawStage ofName(String name); + method public com.google.firebase.firestore.pipeline.RawStage withArguments(java.lang.Object... arguments); + field public static final com.google.firebase.firestore.pipeline.RawStage.Companion Companion; + } + + public static final class RawStage.Companion { + method public com.google.firebase.firestore.pipeline.RawStage ofName(String name); + } + + public final class SampleStage extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.SampleStage withDocLimit(int documents); method public static com.google.firebase.firestore.pipeline.SampleStage withPercentage(double percentage); field public static final com.google.firebase.firestore.pipeline.SampleStage.Companion Companion; @@ -1602,17 +1615,18 @@ package com.google.firebase.firestore.pipeline { ctor public Selectable(); } - public final class Stage extends com.google.firebase.firestore.pipeline.BaseStage { - method public static com.google.firebase.firestore.pipeline.Stage ofName(String name); - method public com.google.firebase.firestore.pipeline.Stage withArguments(java.lang.Object... arguments); - field public static final com.google.firebase.firestore.pipeline.Stage.Companion Companion; - } - - public static final class Stage.Companion { - method public com.google.firebase.firestore.pipeline.Stage ofName(String name); + public abstract class Stage> { + method protected final String getName(); + method public final T with(String key, boolean value); + method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); + method public final T with(String key, double value); + method protected final T with(String key, error.NonExistentClass value); + method public final T with(String key, String value); + method public final T with(String key, long value); + property protected final String name; } - public final class UnnestStage extends com.google.firebase.firestore.pipeline.BaseStage { + public final class UnnestStage extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.UnnestStage withField(com.google.firebase.firestore.pipeline.Selectable arrayWithAlias); method public static com.google.firebase.firestore.pipeline.UnnestStage withField(String arrayField, String alias); method public com.google.firebase.firestore.pipeline.UnnestStage withIndexField(String indexField); diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java index 5c9e26f5acb..da140a27c49 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java @@ -47,7 +47,7 @@ import com.google.firebase.firestore.pipeline.AggregateFunction; import com.google.firebase.firestore.pipeline.AggregateStage; import com.google.firebase.firestore.pipeline.Expr; -import com.google.firebase.firestore.pipeline.Stage; +import com.google.firebase.firestore.pipeline.RawStage; import com.google.firebase.firestore.testutil.IntegrationTestUtil; import java.util.Collections; import java.util.LinkedHashMap; @@ -279,15 +279,14 @@ public void groupAndAccumulateResultsGeneric() { firestore .pipeline() .collection(randomCol) - .addStage(Stage.ofName("where").withArguments(lt(field("published"), 1984))) - .addStage( - Stage.ofName("aggregate") + .rawStage(RawStage.ofName("where").withArguments(lt(field("published"), 1984))) + .rawStage( + RawStage.ofName("aggregate") .withArguments( ImmutableMap.of("avgRating", AggregateFunction.avg("rating")), ImmutableMap.of("genre", field("genre")))) - .addStage(Stage.ofName("where").withArguments(gt("avgRating", 4.3))) - .addStage( - Stage.ofName("sort").withArguments(field("avgRating").descending())) + .rawStage(RawStage.ofName("where").withArguments(gt("avgRating", 4.3))) + .rawStage(RawStage.ofName("sort").withArguments(field("avgRating").descending())) .execute(); assertThat(waitFor(execute).getResults()) .comparingElementsUsing(DATA_CORRESPONDENCE) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java index 942d6291668..edec58cff66 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryToPipelineTest.java @@ -613,40 +613,39 @@ public void testQueriesCanUseArrayContainsAnyFilters() { FirebaseFirestore db = collection.firestore; // Search for "array" to contain [42, 43]. - Pipeline pipeline = db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", asList(42L, 43L))); + Pipeline pipeline = + db.pipeline().convertFrom(collection.whereArrayContainsAny("array", asList(42L, 43L))); PipelineSnapshot snapshot = waitFor(pipeline.execute()); assertEquals(asList(docA, docB, docD, docE), pipelineSnapshotToValues(snapshot)); // With objects. - pipeline = db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", asList(map("a", 42L)))); + pipeline = + db.pipeline().convertFrom(collection.whereArrayContainsAny("array", asList(map("a", 42L)))); snapshot = waitFor(pipeline.execute()); assertEquals(asList(docF), pipelineSnapshotToValues(snapshot)); // With null. - pipeline = db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", nullList())); + pipeline = db.pipeline().convertFrom(collection.whereArrayContainsAny("array", nullList())); snapshot = waitFor(pipeline.execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With null and a value. List inputList = nullList(); inputList.add(43L); - pipeline = db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", inputList)); + pipeline = db.pipeline().convertFrom(collection.whereArrayContainsAny("array", inputList)); snapshot = waitFor(pipeline.execute()); assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); // With NaN. - pipeline = db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN))); + pipeline = + db.pipeline().convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN))); snapshot = waitFor(pipeline.execute()); assertEquals(new ArrayList<>(), pipelineSnapshotToValues(snapshot)); // With NaN and a value. - pipeline = db.pipeline() - .convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN, 43L))); + pipeline = + db.pipeline() + .convertFrom(collection.whereArrayContainsAny("array", asList(Double.NaN, 43L))); snapshot = waitFor(pipeline.execute()); assertEquals(asList(docE), pipelineSnapshotToValues(snapshot)); } diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java index 717e3f02ebc..fbc517bb774 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java @@ -575,7 +575,7 @@ public static void checkQueryAndPipelineResultsMatch(Query query, String... expe } PipelineSnapshot docsFromPipeline; try { - docsFromPipeline = waitFor(query.getFirestore().pipeline().convertFrom(query).execute()); + docsFromPipeline = waitFor(query.getFirestore().pipeline().convertFrom(query).execute()); } catch (Exception e) { throw new RuntimeException("Pipeline FAILED", e); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index fb7d8313737..c1b09bcf94e 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -36,18 +36,18 @@ import com.google.firebase.firestore.pipeline.ExprWithAlias import com.google.firebase.firestore.pipeline.Field import com.google.firebase.firestore.pipeline.FindNearestStage import com.google.firebase.firestore.pipeline.FunctionExpr -import com.google.firebase.firestore.pipeline.Stage import com.google.firebase.firestore.pipeline.LimitStage import com.google.firebase.firestore.pipeline.OffsetStage import com.google.firebase.firestore.pipeline.Ordering import com.google.firebase.firestore.pipeline.PipelineOptions +import com.google.firebase.firestore.pipeline.RawStage import com.google.firebase.firestore.pipeline.RemoveFieldsStage import com.google.firebase.firestore.pipeline.ReplaceStage import com.google.firebase.firestore.pipeline.SampleStage import com.google.firebase.firestore.pipeline.SelectStage import com.google.firebase.firestore.pipeline.Selectable import com.google.firebase.firestore.pipeline.SortStage -import com.google.firebase.firestore.pipeline.BaseStage +import com.google.firebase.firestore.pipeline.Stage import com.google.firebase.firestore.pipeline.UnionStage import com.google.firebase.firestore.pipeline.UnnestStage import com.google.firebase.firestore.pipeline.WhereStage @@ -59,15 +59,15 @@ class Pipeline internal constructor( internal val firestore: FirebaseFirestore, internal val userDataReader: UserDataReader, - private val stages: FluentIterable> + private val stages: FluentIterable> ) { internal constructor( firestore: FirebaseFirestore, userDataReader: UserDataReader, - stage: BaseStage<*> + stage: Stage<*> ) : this(firestore, userDataReader, FluentIterable.of(stage)) - private fun append(stage: BaseStage<*>): Pipeline { + private fun append(stage: Stage<*>): Pipeline { return Pipeline(firestore, userDataReader, stages.append(stage)) } @@ -103,17 +103,17 @@ internal constructor( .build() /** - * Adds a stage to the pipeline by specifying the stage name as an argument. This does not offer - * any type safety on the stage params and requires the caller to know the order (and optionally - * names) of parameters accepted by the stage. + * Adds a raw stage to the pipeline by specifying the stage name as an argument. This does not + * offer any type safety on the stage params and requires the caller to know the order (and + * optionally names) of parameters accepted by the stage. * * This method provides a way to call stages that are supported by the Firestore backend but that * are not implemented in the SDK version being used. * - * @param stage An [Stage] object that specifies stage name and parameters. + * @param rawStage An [RawStage] object that specifies stage name and parameters. * @return A new [Pipeline] object with this stage appended to the stage list. */ - fun addStage(stage: Stage): Pipeline = append(stage) + fun rawStage(rawStage: RawStage): Pipeline = append(rawStage) /** * Adds new fields to outputs from previous stages. diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java index b702746f066..3b7c2ef4c06 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/FieldFilter.java @@ -20,7 +20,6 @@ import static com.google.firebase.firestore.util.Assert.hardAssert; import androidx.annotation.NonNull; - import com.google.firebase.firestore.model.Document; import com.google.firebase.firestore.model.FieldPath; import com.google.firebase.firestore.model.Values; @@ -29,7 +28,6 @@ import com.google.firebase.firestore.pipeline.Field; import com.google.firebase.firestore.util.Assert; import com.google.firestore.v1.Value; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -219,14 +217,16 @@ BooleanExpr toPipelineExpr() { return and(exists, x.arrayContainsAny(value.getArrayValue().getValuesList())); case IN: return and(exists, x.eqAny(value.getArrayValue().getValuesList())); - case NOT_IN: { - List list = value.getArrayValue().getValuesList(); - if (hasNaN(list)) { - return and(exists, x.notEqAny(filterNaN(list)), ifError(x.isNotNan(), Expr.constant(true))); - } else { - return and(exists, x.notEqAny(list)); + case NOT_IN: + { + List list = value.getArrayValue().getValuesList(); + if (hasNaN(list)) { + return and( + exists, x.notEqAny(filterNaN(list)), ifError(x.isNotNan(), Expr.constant(true))); + } else { + return and(exists, x.notEqAny(list)); + } } - } default: // Handle OPERATOR_UNSPECIFIED and UNRECOGNIZED cases as needed throw new IllegalArgumentException("Unsupported operator: " + operator); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java index ac4d499854f..f4ecf8fcbc7 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/Query.java @@ -37,7 +37,7 @@ import com.google.firebase.firestore.pipeline.FunctionExpr; import com.google.firebase.firestore.pipeline.InternalOptions; import com.google.firebase.firestore.pipeline.Ordering; -import com.google.firebase.firestore.pipeline.BaseStage; +import com.google.firebase.firestore.pipeline.Stage; import com.google.firebase.firestore.util.BiFunction; import com.google.firebase.firestore.util.Function; import com.google.firebase.firestore.util.IntFunction; @@ -549,7 +549,8 @@ public Pipeline toPipeline(FirebaseFirestore firestore, UserDataReader userDataR if (fields.size() == 1) { p = p.where(fields.get(0).exists()); } else { - BooleanExpr[] conditions = skipFirstToArray(fields, BooleanExpr[]::new, Expr.Companion::exists); + BooleanExpr[] conditions = + skipFirstToArray(fields, BooleanExpr[]::new, Expr.Companion::exists); p = p.where(and(fields.get(0).exists(), conditions)); } @@ -587,17 +588,18 @@ private static T[] skipFirstToArray(List list, IntFunction generator int size = list.size(); T[] result = generator.apply(size - 1); for (int i = 1; i < size; i++) { - result[i-1] = list.get(i); + result[i - 1] = list.get(i); } return result; } // Many Pipelines require first parameter to be separated out from rest. - private static R[] skipFirstToArray(List list, IntFunction generator, Function map) { + private static R[] skipFirstToArray( + List list, IntFunction generator, Function map) { int size = list.size(); R[] result = generator.apply(size - 1); for (int i = 1; i < size; i++) { - result[i-1] = map.apply(list.get(i)); + result[i - 1] = map.apply(list.get(i)); } return result; } @@ -621,7 +623,7 @@ private static BooleanExpr whereConditionsFromCursor( } @NonNull - private BaseStage pipelineSource(FirebaseFirestore firestore) { + private Stage pipelineSource(FirebaseFirestore firestore) { if (isDocumentQuery()) { return new DocumentsSource(path.canonicalString()); } else if (isCollectionGroupQuery()) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt index 568a64899ec..cd93238b8d6 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt @@ -599,14 +599,11 @@ internal object Values { .build() } - @JvmField - val TRUE: Value = Value.newBuilder().setBooleanValue(true).build() + @JvmField val TRUE: Value = Value.newBuilder().setBooleanValue(true).build() - @JvmField - val FALSE: Value = Value.newBuilder().setBooleanValue(false).build() + @JvmField val FALSE: Value = Value.newBuilder().setBooleanValue(false).build() - @JvmStatic - fun encodeValue(value: Boolean): Value = if (value) TRUE else FALSE + @JvmStatic fun encodeValue(value: Boolean): Value = if (value) TRUE else FALSE @JvmStatic fun encodeValue(geoPoint: GeoPoint): Value = diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 5eb5e6c3698..3388b4b8b4d 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -31,7 +31,6 @@ import com.google.firebase.firestore.util.CustomClassMapper import com.google.firestore.v1.MapValue import com.google.firestore.v1.Value import java.util.Date -import kotlin.reflect.KFunction1 /** * Represents an expression that can be evaluated to a value within the execution of a [Pipeline]. @@ -48,8 +47,11 @@ import kotlin.reflect.KFunction1 */ abstract class Expr internal constructor() { - private class ValueConstant(val value: Value) : Expr() { + private class Constant(val value: Value) : Expr() { override fun toProto(userDataReader: UserDataReader): Value = value + override fun toString(): String { + return "Constant(value=$value)" + } } companion object { @@ -61,7 +63,7 @@ abstract class Expr internal constructor() { toExpr(value, ::pojoToExprOrConstant) ?: throw IllegalArgumentException("Unknown type: $value") - private fun toExpr(value: Any?, toExpr: KFunction1): Expr? { + private inline fun toExpr(value: Any?, toExpr: (Any?) -> Expr): Expr? { if (value == null) return NULL return when (value) { is Expr -> value @@ -75,7 +77,7 @@ abstract class Expr internal constructor() { is DocumentReference -> constant(value) is ByteArray -> constant(value) is VectorValue -> constant(value) - is Value -> ValueConstant(value) + is Value -> Constant(value) is Map<*, *> -> map( value @@ -86,18 +88,18 @@ abstract class Expr internal constructor() { } .toTypedArray() ) - is List<*> -> ListOfExprs(value.map(toExpr).toTypedArray()) + is List<*> -> array(value) else -> null } } - internal fun toArrayOfExprOrConstant(others: Iterable): Array = + private fun toArrayOfExprOrConstant(others: Iterable): Array = others.map(::toExprOrConstant).toTypedArray() internal fun toArrayOfExprOrConstant(others: Array): Array = others.map(::toExprOrConstant).toTypedArray() - private val NULL: Expr = ValueConstant(Values.NULL_VALUE) + private val NULL: Expr = Constant(Values.NULL_VALUE) /** * Create a constant for a [String] value. @@ -107,7 +109,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun constant(value: String): Expr { - return ValueConstant(encodeValue(value)) + return Constant(encodeValue(value)) } /** @@ -118,7 +120,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun constant(value: Number): Expr { - return ValueConstant(encodeValue(value)) + return Constant(encodeValue(value)) } /** @@ -129,7 +131,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun constant(value: Date): Expr { - return ValueConstant(encodeValue(value)) + return Constant(encodeValue(value)) } /** @@ -140,7 +142,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun constant(value: Timestamp): Expr { - return ValueConstant(encodeValue(value)) + return Constant(encodeValue(value)) } /** @@ -174,8 +176,8 @@ abstract class Expr internal constructor() { * @return A new [Expr] constant instance. */ @JvmStatic - fun constant(value: GeoPoint): Expr { - return ValueConstant(encodeValue(value)) + fun constant(value: GeoPoint): Expr { // Ensure this overload exists or is correctly placed + return Constant(encodeValue(value)) } /** @@ -186,7 +188,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun constant(value: ByteArray): Expr { - return ValueConstant(encodeValue(value)) + return Constant(encodeValue(value)) } /** @@ -197,7 +199,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun constant(value: Blob): Expr { - return ValueConstant(encodeValue(value)) + return Constant(encodeValue(value)) } /** @@ -224,7 +226,18 @@ abstract class Expr internal constructor() { */ @JvmStatic fun constant(value: VectorValue): Expr { - return ValueConstant(encodeValue(value)) + return Constant(encodeValue(value)) + } + + /** + * Create a [Blob] constant from a [ByteArray]. + * + * @param bytes The [ByteArray] to convert to a Blob. + * @return A new [Expr] constant instance representing the Blob. + */ + @JvmStatic + fun blob(bytes: ByteArray): Expr { + return constant(Blob.fromBytes(bytes)) } /** @@ -245,7 +258,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun vector(vector: DoubleArray): Expr { - return ValueConstant(Values.encodeVectorValue(vector)) + return Constant(Values.encodeVectorValue(vector)) } /** @@ -256,7 +269,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun vector(vector: VectorValue): Expr { - return ValueConstant(encodeValue(vector)) + return Constant(encodeValue(vector)) } /** @@ -296,7 +309,7 @@ abstract class Expr internal constructor() { * Creates an expression that performs a logical 'AND' operation. * * @param condition The first [BooleanExpr]. - * @param conditions Addition [BooleanExpr]s. + * @param conditions Additional [BooleanExpr]s. * @return A new [BooleanExpr] representing the logical 'AND' operation. */ @JvmStatic @@ -307,7 +320,7 @@ abstract class Expr internal constructor() { * Creates an expression that performs a logical 'OR' operation. * * @param condition The first [BooleanExpr]. - * @param conditions Addition [BooleanExpr]s. + * @param conditions Additional [BooleanExpr]s. * @return A new [BooleanExpr] representing the logical 'OR' operation. */ @JvmStatic @@ -318,7 +331,7 @@ abstract class Expr internal constructor() { * Creates an expression that performs a logical 'XOR' operation. * * @param condition The first [BooleanExpr]. - * @param conditions Addition [BooleanExpr]s. + * @param conditions Additional [BooleanExpr]s. * @return A new [BooleanExpr] representing the logical 'XOR' operation. */ @JvmStatic @@ -753,9 +766,7 @@ abstract class Expr internal constructor() { * @param second Numeric expression to add. * @return A new [Expr] representing the addition operation. */ - @JvmStatic - fun add(first: Expr, second: Expr): Expr = - FunctionExpr("add", first, second) + @JvmStatic fun add(first: Expr, second: Expr): Expr = FunctionExpr("add", first, second) /** * Creates an expression that adds numeric expressions with a constant. @@ -764,9 +775,7 @@ abstract class Expr internal constructor() { * @param second Constant to add. * @return A new [Expr] representing the addition operation. */ - @JvmStatic - fun add(first: Expr, second: Number): Expr = - FunctionExpr("add", first, second) + @JvmStatic fun add(first: Expr, second: Number): Expr = FunctionExpr("add", first, second) /** * Creates an expression that adds a numeric field with a numeric expression. @@ -842,8 +851,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the multiplication operation. */ @JvmStatic - fun multiply(first: Expr, second: Expr): Expr = - FunctionExpr("multiply", first, second) + fun multiply(first: Expr, second: Expr): Expr = FunctionExpr("multiply", first, second) /** * Creates an expression that multiplies numeric expressions with a constant. @@ -853,8 +861,7 @@ abstract class Expr internal constructor() { * @return A new [Expr] representing the multiplication operation. */ @JvmStatic - fun multiply(first: Expr, second: Number): Expr = - FunctionExpr("multiply", first, second) + fun multiply(first: Expr, second: Number): Expr = FunctionExpr("multiply", first, second) /** * Creates an expression that multiplies a numeric field with a numeric expression. @@ -974,8 +981,7 @@ abstract class Expr internal constructor() { * @return A new [BooleanExpr] representing the 'IN' comparison. */ @JvmStatic - fun eqAny(expression: Expr, values: List): BooleanExpr = - eqAny(expression, ListOfExprs(toArrayOfExprOrConstant(values))) + fun eqAny(expression: Expr, values: List): BooleanExpr = eqAny(expression, array(values)) /** * Creates an expression that checks if an [expression], when evaluated, is equal to any of the @@ -999,8 +1005,7 @@ abstract class Expr internal constructor() { * @return A new [BooleanExpr] representing the 'IN' comparison. */ @JvmStatic - fun eqAny(fieldName: String, values: List): BooleanExpr = - eqAny(fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + fun eqAny(fieldName: String, values: List): BooleanExpr = eqAny(fieldName, array(values)) /** * Creates an expression that checks if a field's value is equal to any of the elements of @@ -1025,7 +1030,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun notEqAny(expression: Expr, values: List): BooleanExpr = - notEqAny(expression, ListOfExprs(toArrayOfExprOrConstant(values))) + notEqAny(expression, array(values)) /** * Creates an expression that checks if an [expression], when evaluated, is not equal to all the @@ -1050,7 +1055,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun notEqAny(fieldName: String, values: List): BooleanExpr = - notEqAny(fieldName, ListOfExprs(toArrayOfExprOrConstant(values))) + notEqAny(fieldName, array(values)) /** * Creates an expression that checks if a field's value is not equal to all of the elements of @@ -1761,6 +1766,28 @@ abstract class Expr internal constructor() { @JvmStatic fun mapGet(fieldName: String, key: String): Expr = FunctionExpr("map_get", fieldName, key) + /** + * Accesses a value from a map (object) field using the provided [keyExpression]. + * + * @param mapExpression The expression representing the map. + * @param keyExpression The key to access in the map. + * @return A new [Expr] representing the value associated with the given key in the map. + */ + @JvmStatic + fun mapGet(mapExpression: Expr, keyExpression: Expr): Expr = + FunctionExpr("map_get", mapExpression, keyExpression) + + /** + * Accesses a value from a map (object) field using the provided [keyExpression]. + * + * @param fieldName The field name of the map field. + * @param keyExpression The key to access in the map. + * @return A new [Expr] representing the value associated with the given key in the map. + */ + @JvmStatic + fun mapGet(fieldName: String, keyExpression: Expr): Expr = + FunctionExpr("map_get", fieldName, keyExpression) + /** * Creates an expression that merges multiple maps into a single map. If multiple maps have the * same key, the later value is used. @@ -2511,6 +2538,25 @@ abstract class Expr internal constructor() { @JvmStatic fun lte(fieldName: String, value: Any): BooleanExpr = BooleanExpr("lte", fieldName, value) + /** + * Creates an expression that creates a Firestore array value from an input array. + * + * @param elements The input array to evaluate in the expression. + * @return A new [Expr] representing the array function. + */ + @JvmStatic + fun array(vararg elements: Any?): Expr = + FunctionExpr("array", elements.map(::toExprOrConstant).toTypedArray()) + + /** + * Creates an expression that creates a Firestore array value from an input array. + * + * @param elements The input array to evaluate in the expression. + * @return A new [Expr] representing the array function. + */ + @JvmStatic + fun array(elements: List): Expr = + FunctionExpr("array", elements.map(::toExprOrConstant).toTypedArray()) /** * Creates an expression that concatenates an array with other arrays. * @@ -2628,8 +2674,7 @@ abstract class Expr internal constructor() { * @return A new [BooleanExpr] representing the arrayContainsAll operation. */ @JvmStatic - fun arrayContainsAll(array: Expr, values: List) = - arrayContainsAll(array, ListOfExprs(toArrayOfExprOrConstant(values))) + fun arrayContainsAll(array: Expr, values: List) = arrayContainsAll(array, array(values)) /** * Creates an expression that checks if [array] contains all elements of [arrayExpression]. @@ -2651,11 +2696,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun arrayContainsAll(arrayFieldName: String, values: List) = - BooleanExpr( - "array_contains_all", - arrayFieldName, - ListOfExprs(toArrayOfExprOrConstant(values)) - ) + BooleanExpr("array_contains_all", arrayFieldName, array(values)) /** * Creates an expression that checks if array field contains all elements of [arrayExpression]. @@ -2677,7 +2718,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun arrayContainsAny(array: Expr, values: List) = - BooleanExpr("array_contains_any", array, ListOfExprs(toArrayOfExprOrConstant(values))) + BooleanExpr("array_contains_any", array, array(values)) /** * Creates an expression that checks if [array] contains any elements of [arrayExpression]. @@ -2699,11 +2740,7 @@ abstract class Expr internal constructor() { */ @JvmStatic fun arrayContainsAny(arrayFieldName: String, values: List) = - BooleanExpr( - "array_contains_any", - arrayFieldName, - ListOfExprs(toArrayOfExprOrConstant(values)) - ) + BooleanExpr("array_contains_any", arrayFieldName, array(values)) /** * Creates an expression that checks if array field contains any elements of [arrayExpression]. @@ -2845,12 +2882,21 @@ abstract class Expr internal constructor() { * This overload will return [BooleanExpr] when both parameters are also [BooleanExpr]. * * @param tryExpr The try boolean expression. - * @param catchExpr The catch boolean expression that will be evaluated and returned if the [tryExpr] - * produces an error. + * @param catchExpr The catch boolean expression that will be evaluated and returned if the + * [tryExpr] produces an error. * @return A new [BooleanExpr] representing the ifError operation. */ @JvmStatic - fun ifError(tryExpr: BooleanExpr, catchExpr: BooleanExpr): BooleanExpr = BooleanExpr("if_error", tryExpr, catchExpr) + fun ifError(tryExpr: BooleanExpr, catchExpr: BooleanExpr): BooleanExpr = + BooleanExpr("if_error", tryExpr, catchExpr) + + /** + * Creates an expression that checks if a given expression produces an error. + * + * @param expr The expression to check. + * @return A new [BooleanExpr] representing the `isError` check. + */ + @JvmStatic fun isError(expr: Expr): BooleanExpr = BooleanExpr("is_error", expr) /** * Creates an expression that returns the [catchValue] argument if there is an error, else @@ -3953,6 +3999,13 @@ abstract class Expr internal constructor() { */ fun ifError(catchValue: Any): Expr = Companion.ifError(this, catchValue) + /** + * Creates an expression that checks if this expression produces an error. + * + * @return A new [BooleanExpr] representing the `isError` check. + */ + fun isError(): BooleanExpr = Companion.isError(this) + internal abstract fun toProto(userDataReader: UserDataReader): Value } @@ -4010,11 +4063,6 @@ class Field internal constructor(private val fieldPath: ModelFieldPath) : Select Value.newBuilder().setFieldReferenceValue(fieldPath.canonicalString()).build() } -internal class ListOfExprs(private val expressions: Array) : Expr() { - override fun toProto(userDataReader: UserDataReader): Value = - encodeValue(expressions.map { it.toProto(userDataReader) }) -} - /** * This class defines the base class for Firestore [Pipeline] functions, which can be evaluated * within pipeline execution. @@ -4132,6 +4180,18 @@ open class BooleanExpr internal constructor(name: String, params: Array> +abstract class Stage> internal constructor(protected val name: String, internal val options: InternalOptions) { internal fun toProtoStage(userDataReader: UserDataReader): Pipeline.Stage { val builder = Pipeline.Stage.newBuilder() @@ -96,32 +96,32 @@ internal constructor(protected val name: String, internal val options: InternalO * This class provides a way to call stages that are supported by the Firestore backend but that are * not implemented in the SDK version being used. */ -class Stage +class RawStage private constructor( name: String, private val arguments: List, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage(name, options) { +) : Stage(name, options) { companion object { /** * Specify name of stage * * @param name The unique name of the stage to add. - * @return [Stage] with specified parameters. + * @return [RawStage] with specified parameters. */ - @JvmStatic fun ofName(name: String) = Stage(name, emptyList(), InternalOptions.EMPTY) + @JvmStatic fun ofName(name: String) = RawStage(name, emptyList(), InternalOptions.EMPTY) } - override fun self(options: InternalOptions) = Stage(name, arguments, options) + override fun self(options: InternalOptions) = RawStage(name, arguments, options) /** * Specify arguments to stage. * * @param arguments A list of ordered parameters to configure the stage's behavior. - * @return [Stage] with specified parameters. + * @return [RawStage] with specified parameters. */ - fun withArguments(vararg arguments: Any): Stage = - Stage(name, arguments.map(GenericArg::from), options) + fun withArguments(vararg arguments: Any): RawStage = + RawStage(name, arguments.map(GenericArg::from), options) override fun args(userDataReader: UserDataReader): Sequence = arguments.asSequence().map { it.toProto(userDataReader) } @@ -167,7 +167,7 @@ internal sealed class GenericArg { internal class DatabaseSource @JvmOverloads internal constructor(options: InternalOptions = InternalOptions.EMPTY) : - BaseStage("database", options) { + Stage("database", options) { override fun self(options: InternalOptions) = DatabaseSource(options) override fun args(userDataReader: UserDataReader): Sequence = emptySequence() } @@ -178,7 +178,7 @@ internal constructor( // We validate [firestore.databaseId] when adding to pipeline. internal val firestore: FirebaseFirestore?, options: InternalOptions -) : BaseStage("collection", options) { +) : Stage("collection", options) { override fun self(options: InternalOptions): CollectionSource = CollectionSource(path, firestore, options) override fun args(userDataReader: UserDataReader): Sequence = @@ -216,7 +216,7 @@ internal constructor( class CollectionGroupSource private constructor(private val collectionId: String, options: InternalOptions) : - BaseStage("collection_group", options) { + Stage("collection_group", options) { override fun self(options: InternalOptions) = CollectionGroupSource(collectionId, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setReferenceValue("").build(), encodeValue(collectionId)) @@ -246,7 +246,7 @@ internal class DocumentsSource internal constructor( private val documents: Array, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("documents", options) { +) : Stage("documents", options) { internal constructor(document: String) : this(arrayOf(document)) override fun self(options: InternalOptions) = DocumentsSource(documents, options) override fun args(userDataReader: UserDataReader): Sequence = @@ -257,7 +257,7 @@ internal class AddFieldsStage internal constructor( private val fields: Array, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("add_fields", options) { +) : Stage("add_fields", options) { override fun self(options: InternalOptions) = AddFieldsStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) @@ -284,7 +284,7 @@ internal constructor( private val accumulators: Map, private val groups: Map, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("aggregate", options) { +) : Stage("aggregate", options) { private constructor(accumulators: Map) : this(accumulators, emptyMap()) companion object { @@ -349,7 +349,7 @@ internal class WhereStage internal constructor( private val condition: BooleanExpr, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("where", options) { +) : Stage("where", options) { override fun self(options: InternalOptions) = WhereStage(condition, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(condition.toProto(userDataReader)) @@ -365,7 +365,7 @@ internal constructor( private val vector: Expr, private val distanceMeasure: DistanceMeasure, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("find_nearest", options) { +) : Stage("find_nearest", options) { companion object { @@ -477,7 +477,7 @@ internal constructor( internal class LimitStage internal constructor(private val limit: Int, options: InternalOptions = InternalOptions.EMPTY) : - BaseStage("limit", options) { + Stage("limit", options) { override fun self(options: InternalOptions) = LimitStage(limit, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(limit)) @@ -485,7 +485,7 @@ internal constructor(private val limit: Int, options: InternalOptions = Internal internal class OffsetStage internal constructor(private val offset: Int, options: InternalOptions = InternalOptions.EMPTY) : - BaseStage("offset", options) { + Stage("offset", options) { override fun self(options: InternalOptions) = OffsetStage(offset, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(offset)) @@ -495,7 +495,7 @@ internal class SelectStage internal constructor( private val fields: Array, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("select", options) { +) : Stage("select", options) { override fun self(options: InternalOptions) = SelectStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) @@ -505,7 +505,7 @@ internal class SortStage internal constructor( private val orders: Array, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("sort", options) { +) : Stage("sort", options) { override fun self(options: InternalOptions) = SortStage(orders, options) override fun args(userDataReader: UserDataReader): Sequence = orders.asSequence().map { it.toProto(userDataReader) } @@ -515,7 +515,7 @@ internal class DistinctStage internal constructor( private val groups: Array, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("distinct", options) { +) : Stage("distinct", options) { override fun self(options: InternalOptions) = DistinctStage(groups, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(groups.associate { it.getAlias() to it.toProto(userDataReader) })) @@ -525,7 +525,7 @@ internal class RemoveFieldsStage internal constructor( private val fields: Array, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("remove_fields", options) { +) : Stage("remove_fields", options) { override fun self(options: InternalOptions) = RemoveFieldsStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = fields.asSequence().map(Field::toProto) @@ -536,7 +536,7 @@ internal constructor( private val mapValue: Expr, private val mode: Mode, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("replace", options) { +) : Stage("replace", options) { class Mode private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) companion object { @@ -563,7 +563,7 @@ private constructor( private val size: Number, private val mode: Mode, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("sample", options) { +) : Stage("sample", options) { override fun self(options: InternalOptions) = SampleStage(size, mode, options) class Mode private constructor(internal val proto: Value) { private constructor(protoString: String) : this(encodeValue(protoString)) @@ -606,7 +606,7 @@ internal class UnionStage internal constructor( private val other: com.google.firebase.firestore.Pipeline, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("union", options) { +) : Stage("union", options) { override fun self(options: InternalOptions) = UnionStage(other, options) override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(Value.newBuilder().setPipelineValue(other.toPipelineProto()).build()) @@ -620,7 +620,7 @@ class UnnestStage internal constructor( private val selectable: Selectable, options: InternalOptions = InternalOptions.EMPTY -) : BaseStage("unnest", options) { +) : Stage("unnest", options) { companion object { /** From 5eb6a0128ee475c3f1d576ecba7d59b55ab6d210 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Thu, 5 Jun 2025 15:03:52 -0400 Subject: [PATCH 75/77] Fixes / Refactor of Values --- .../core/number/NumberComparisonHelper.java | 7 +- .../google/firebase/firestore/GeoPoint.java | 7 +- .../google/firebase/firestore/core/View.java | 4 +- .../firestore/local/DocumentReference.java | 6 +- .../firestore/local/MemoryMutationQueue.java | 5 +- .../firestore/local/SQLiteMutationQueue.java | 3 +- .../firebase/firestore/model/BasePath.java | 2 +- .../google/firebase/firestore/model/Values.kt | 56 +++++++++------- .../google/firebase/firestore/util/Util.java | 65 +------------------ 9 files changed, 48 insertions(+), 107 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/cloud/datastore/core/number/NumberComparisonHelper.java b/firebase-firestore/src/main/java/com/google/cloud/datastore/core/number/NumberComparisonHelper.java index 6af2ea76995..270ff8462f3 100644 --- a/firebase-firestore/src/main/java/com/google/cloud/datastore/core/number/NumberComparisonHelper.java +++ b/firebase-firestore/src/main/java/com/google/cloud/datastore/core/number/NumberComparisonHelper.java @@ -50,7 +50,7 @@ public static int firestoreCompareDoubleWithLong(double doubleValue, long longVa } long doubleAsLong = (long) doubleValue; - int cmp = compareLongs(doubleAsLong, longValue); + int cmp = Long.compare(doubleAsLong, longValue); if (cmp != 0) { return cmp; } @@ -60,11 +60,6 @@ public static int firestoreCompareDoubleWithLong(double doubleValue, long longVa return firestoreCompareDoubles(doubleValue, longAsDouble); } - /** Compares longs. */ - public static int compareLongs(long leftLong, long rightLong) { - return Long.compare(leftLong, rightLong); - } - /** * Compares doubles with Firestore query semantics: NaN precedes all other numbers and equals * itself, all zeroes are equal. diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/GeoPoint.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/GeoPoint.java index a989189a1bd..0c257bbabf8 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/GeoPoint.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/GeoPoint.java @@ -14,9 +14,10 @@ package com.google.firebase.firestore; +import static com.google.cloud.datastore.core.number.NumberComparisonHelper.firestoreCompareDoubles; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.google.firebase.firestore.util.Util; /** Immutable class representing a {@code GeoPoint} in Cloud Firestore */ public class GeoPoint implements Comparable { @@ -52,9 +53,9 @@ public double getLongitude() { @Override public int compareTo(@NonNull GeoPoint other) { - int comparison = Util.compareDoubles(latitude, other.latitude); + int comparison = firestoreCompareDoubles(latitude, other.latitude); if (comparison == 0) { - return Util.compareDoubles(longitude, other.longitude); + return firestoreCompareDoubles(longitude, other.longitude); } else { return comparison; } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/View.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/View.java index a3a508df207..849f0b10f9e 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/View.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/View.java @@ -17,7 +17,6 @@ import static com.google.firebase.firestore.core.Query.LimitType.LIMIT_TO_FIRST; import static com.google.firebase.firestore.core.Query.LimitType.LIMIT_TO_LAST; import static com.google.firebase.firestore.util.Assert.hardAssert; -import static com.google.firebase.firestore.util.Util.compareIntegers; import androidx.annotation.Nullable; import com.google.firebase.database.collection.ImmutableSortedMap; @@ -301,7 +300,8 @@ public ViewChange applyChanges( Collections.sort( viewChanges, (DocumentViewChange o1, DocumentViewChange o2) -> { - int typeComp = compareIntegers(View.changeTypeOrder(o1), View.changeTypeOrder(o2)); + int i1 = View.changeTypeOrder(o1); + int typeComp = Integer.compare(i1, View.changeTypeOrder(o2)); if (typeComp != 0) { return typeComp; } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/DocumentReference.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/DocumentReference.java index 512b419906d..74dcfe63da0 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/DocumentReference.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/DocumentReference.java @@ -14,8 +14,6 @@ package com.google.firebase.firestore.local; -import static com.google.firebase.firestore.util.Util.compareIntegers; - import com.google.firebase.firestore.model.DocumentKey; import java.util.Comparator; @@ -60,12 +58,12 @@ int getId() { return keyComp; } - return compareIntegers(o1.targetOrBatchId, o2.targetOrBatchId); + return Integer.compare(o1.targetOrBatchId, o2.targetOrBatchId); }; static final Comparator BY_TARGET = (o1, o2) -> { - int targetComp = compareIntegers(o1.targetOrBatchId, o2.targetOrBatchId); + int targetComp = Integer.compare(o1.targetOrBatchId, o2.targetOrBatchId); if (targetComp != 0) { return targetComp; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/MemoryMutationQueue.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/MemoryMutationQueue.java index 7a238dd20c1..23b5c1e730d 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/MemoryMutationQueue.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/MemoryMutationQueue.java @@ -28,7 +28,6 @@ import com.google.firebase.firestore.model.mutation.Mutation; import com.google.firebase.firestore.model.mutation.MutationBatch; import com.google.firebase.firestore.remote.WriteStream; -import com.google.firebase.firestore.util.Util; import com.google.protobuf.ByteString; import java.util.ArrayList; import java.util.Collections; @@ -216,7 +215,7 @@ public List getAllMutationBatchesAffectingDocumentKey(DocumentKey public List getAllMutationBatchesAffectingDocumentKeys( Iterable documentKeys) { ImmutableSortedSet uniqueBatchIDs = - new ImmutableSortedSet(emptyList(), Util.comparator()); + new ImmutableSortedSet(emptyList(), Comparable::compareTo); for (DocumentKey key : documentKeys) { DocumentReference start = new DocumentReference(key, 0); @@ -255,7 +254,7 @@ public List getAllMutationBatchesAffectingQuery(Query query) { // Find unique batchIDs referenced by all documents potentially matching the query. ImmutableSortedSet uniqueBatchIDs = - new ImmutableSortedSet(emptyList(), Util.comparator()); + new ImmutableSortedSet(emptyList(), Comparable::compareTo); Iterator iterator = batchesByDocumentKey.iteratorFrom(start); while (iterator.hasNext()) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLiteMutationQueue.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLiteMutationQueue.java index dd70a58d02b..1c5c96f794a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLiteMutationQueue.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLiteMutationQueue.java @@ -30,7 +30,6 @@ import com.google.firebase.firestore.model.mutation.MutationBatch; import com.google.firebase.firestore.remote.WriteStream; import com.google.firebase.firestore.util.Consumer; -import com.google.firebase.firestore.util.Util; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.MessageLite; @@ -324,7 +323,7 @@ public List getAllMutationBatchesAffectingDocumentKeys( Collections.sort( result, (MutationBatch lhs, MutationBatch rhs) -> - Util.compareIntegers(lhs.getBatchId(), rhs.getBatchId())); + Integer.compare(lhs.getBatchId(), rhs.getBatchId())); } return result; } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/BasePath.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/BasePath.java index 6d800de05d4..d002c8aead4 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/BasePath.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/BasePath.java @@ -107,7 +107,7 @@ public int compareTo(@NonNull B o) { } i++; } - return Util.compareIntegers(myLength, theirLength); + return Integer.compare(myLength, theirLength); } private static int compareSegments(String lhs, String rhs) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt index cd93238b8d6..9d2b3424623 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/Values.kt @@ -13,6 +13,8 @@ // limitations under the License. package com.google.firebase.firestore.model +import com.google.cloud.datastore.core.number.NumberComparisonHelper.firestoreCompareDoubleWithLong +import com.google.cloud.datastore.core.number.NumberComparisonHelper.firestoreCompareDoubles import com.google.firebase.firestore.Blob import com.google.firebase.firestore.DocumentReference import com.google.firebase.firestore.GeoPoint @@ -28,7 +30,6 @@ import com.google.protobuf.ByteString import com.google.protobuf.NullValue import com.google.protobuf.Timestamp import com.google.type.LatLng -import java.lang.Double.doubleToLongBits import java.util.Date import java.util.TreeMap import kotlin.math.min @@ -135,17 +136,25 @@ internal object Values { } } - private fun numberEquals(left: Value, right: Value): Boolean { - if (left.valueTypeCase != right.valueTypeCase) { - return false - } - return when (left.valueTypeCase) { - ValueTypeCase.INTEGER_VALUE -> left.integerValue == right.integerValue + private fun numberEquals(left: Value, right: Value): Boolean = + when (left.valueTypeCase) { + ValueTypeCase.INTEGER_VALUE -> + when (right.valueTypeCase) { + ValueTypeCase.INTEGER_VALUE -> left.integerValue == right.integerValue + ValueTypeCase.DOUBLE_VALUE -> + firestoreCompareDoubleWithLong(right.doubleValue, left.integerValue) == 0 + else -> false + } ValueTypeCase.DOUBLE_VALUE -> - doubleToLongBits(left.doubleValue) == doubleToLongBits(right.doubleValue) + when (right.valueTypeCase) { + ValueTypeCase.INTEGER_VALUE -> + firestoreCompareDoubleWithLong(left.doubleValue, right.integerValue) == 0 + ValueTypeCase.DOUBLE_VALUE -> + firestoreCompareDoubles(left.doubleValue, right.doubleValue) == 0 + else -> false + } else -> false } - } private fun arrayEquals(left: Value, right: Value): Boolean { val leftArray = left.arrayValue @@ -199,13 +208,13 @@ internal object Values { val rightType = typeOrder(right) if (leftType != rightType) { - return Util.compareIntegers(leftType, rightType) + return leftType.compareTo(rightType) } return when (leftType) { TYPE_ORDER_NULL, TYPE_ORDER_MAX_VALUE -> 0 - TYPE_ORDER_BOOLEAN -> Util.compareBooleans(left.booleanValue, right.booleanValue) + TYPE_ORDER_BOOLEAN -> left.booleanValue.compareTo(right.booleanValue) TYPE_ORDER_NUMBER -> compareNumbers(left, right) TYPE_ORDER_TIMESTAMP -> compareTimestamps(left.timestampValue, right.timestampValue) TYPE_ORDER_SERVER_TIMESTAMP -> @@ -269,15 +278,15 @@ internal object Values { private fun compareNumbers(left: Value, right: Value): Int { if (left.hasDoubleValue()) { if (right.hasDoubleValue()) { - return Util.compareDoubles(left.doubleValue, right.doubleValue) + return firestoreCompareDoubles(left.doubleValue, right.doubleValue) } else if (right.hasIntegerValue()) { - return Util.compareMixed(left.doubleValue, right.integerValue) + return firestoreCompareDoubleWithLong(left.doubleValue, right.integerValue) } } else if (left.hasIntegerValue()) { if (right.hasIntegerValue()) { - return Util.compareLongs(left.integerValue, right.integerValue) + return java.lang.Long.compare(left.integerValue, right.integerValue) } else if (right.hasDoubleValue()) { - return -1 * Util.compareMixed(right.doubleValue, left.integerValue) + return -1 * firestoreCompareDoubleWithLong(right.doubleValue, left.integerValue) } } @@ -285,11 +294,11 @@ internal object Values { } private fun compareTimestamps(left: Timestamp, right: Timestamp): Int { - val cmp = Util.compareLongs(left.seconds, right.seconds) + val cmp = left.seconds.compareTo(right.seconds) if (cmp != 0) { return cmp } - return Util.compareIntegers(left.nanos, right.nanos) + return left.nanos.compareTo(right.nanos) } private fun compareReferences(leftPath: String, rightPath: String): Int { @@ -303,13 +312,13 @@ internal object Values { return cmp } } - return Util.compareIntegers(leftSegments.size, rightSegments.size) + return leftSegments.size.compareTo(rightSegments.size) } private fun compareGeoPoints(left: LatLng, right: LatLng): Int { - val comparison = Util.compareDoubles(left.latitude, right.latitude) + val comparison = firestoreCompareDoubles(left.latitude, right.latitude) if (comparison == 0) { - return Util.compareDoubles(left.longitude, right.longitude) + return firestoreCompareDoubles(left.longitude, right.longitude) } return comparison } @@ -322,7 +331,7 @@ internal object Values { return cmp } } - return Util.compareIntegers(left.valuesCount, right.valuesCount) + return left.valuesCount.compareTo(right.valuesCount) } private fun compareMaps(left: MapValue, right: MapValue): Int { @@ -342,7 +351,7 @@ internal object Values { } // Only equal if both iterators are exhausted. - return Util.compareBooleans(iterator1.hasNext(), iterator2.hasNext()) + return iterator1.hasNext().compareTo(iterator2.hasNext()) } private fun compareVectors(left: MapValue, right: MapValue): Int { @@ -353,8 +362,7 @@ internal object Values { val leftArrayValue = leftMap[VECTOR_MAP_VECTORS_KEY]!!.arrayValue val rightArrayValue = rightMap[VECTOR_MAP_VECTORS_KEY]!!.arrayValue - val lengthCompare = - Util.compareIntegers(leftArrayValue.valuesCount, rightArrayValue.valuesCount) + val lengthCompare = leftArrayValue.valuesCount.compareTo(rightArrayValue.valuesCount) if (lengthCompare != 0) { return lengthCompare } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/Util.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/Util.java index 543da11e7d3..c4aa523836e 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/Util.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/Util.java @@ -19,7 +19,6 @@ import android.os.Looper; import androidx.annotation.Nullable; import com.google.android.gms.tasks.Continuation; -import com.google.cloud.datastore.core.number.NumberComparisonHelper; import com.google.firebase.firestore.FieldPath; import com.google.firebase.firestore.FirebaseFirestoreException; import com.google.firebase.firestore.FirebaseFirestoreException.Code; @@ -57,34 +56,6 @@ public static String autoId() { return builder.toString(); } - /** - * Utility function to compare booleans. Note that we can't use Boolean.compare because it's only - * available after Android 19. - */ - public static int compareBooleans(boolean b1, boolean b2) { - if (b1 == b2) { - return 0; - } else if (b1) { - return 1; - } else { - return -1; - } - } - - /** - * Utility function to compare integers. Note that we can't use Integer.compare because it's only - * available after Android 19. - */ - public static int compareIntegers(int i1, int i2) { - if (i1 < i2) { - return -1; - } else if (i1 > i2) { - return 1; - } else { - return 0; - } - } - /** Compare strings in UTF-8 encoded byte order */ public static int compareUtf8Strings(String left, String right) { ByteString leftBytes = ByteString.copyFromUtf8(left); @@ -92,28 +63,6 @@ public static int compareUtf8Strings(String left, String right) { return compareByteStrings(leftBytes, rightBytes); } - /** - * Utility function to compare longs. Note that we can't use Long.compare because it's only - * available after Android 19. - */ - public static int compareLongs(long i1, long i2) { - return NumberComparisonHelper.compareLongs(i1, i2); - } - - /** Utility function to compare doubles (using Firestore semantics for NaN). */ - public static int compareDoubles(double i1, double i2) { - return NumberComparisonHelper.firestoreCompareDoubles(i1, i2); - } - - /** Compares a double and a long (using Firestore semantics for NaN). */ - public static int compareMixed(double doubleValue, long longValue) { - return NumberComparisonHelper.firestoreCompareDoubleWithLong(doubleValue, longValue); - } - - public static > Comparator comparator() { - return Comparable::compareTo; - } - public static FirebaseFirestoreException exceptionFromStatus(Status error) { StatusException statusException = error.asException(); return new FirebaseFirestoreException( @@ -136,15 +85,6 @@ private static Exception convertStatusException(Exception e) { } } - /** Turns a Throwable into an exception, converting it from a StatusException if necessary. */ - public static Exception convertThrowableToException(Throwable t) { - if (t instanceof Exception) { - return Util.convertStatusException((Exception) t); - } else { - return new Exception(t); - } - } - private static final Continuation VOID_ERROR_TRANSFORMER = task -> { if (task.isSuccessful()) { @@ -237,7 +177,7 @@ public static int compareByteArrays(byte[] left, byte[] right) { } // Byte values are equal, continue with comparison } - return Util.compareIntegers(left.length, right.length); + return Integer.compare(left.length, right.length); } public static int compareByteStrings(ByteString left, ByteString right) { @@ -253,7 +193,8 @@ public static int compareByteStrings(ByteString left, ByteString right) { } // Byte values are equal, continue with comparison } - return Util.compareIntegers(left.size(), right.size()); + int i1 = left.size(); + return Integer.compare(i1, right.size()); } public static StringBuilder repeatSequence( From 78ab98c0ee0526cd7d7d2eab5af4a2479345c968 Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 28 Jul 2025 14:16:54 -0400 Subject: [PATCH 76/77] Response to PR review (and back porting from evaluation) --- firebase-firestore/api.txt | 103 +++++------------- .../com/google/firebase/firestore/Pipeline.kt | 41 +++---- .../firebase/firestore/model/FieldPath.java | 5 + .../firebase/firestore/pipeline/aggregates.kt | 2 +- .../firestore/pipeline/expressions.kt | 99 +++++++++-------- .../firebase/firestore/pipeline/options.kt | 76 ++----------- .../firebase/firestore/pipeline/stage.kt | 68 +++++++----- 7 files changed, 147 insertions(+), 247 deletions(-) diff --git a/firebase-firestore/api.txt b/firebase-firestore/api.txt index dd6a20ddcc8..253b4410ba3 100644 --- a/firebase-firestore/api.txt +++ b/firebase-firestore/api.txt @@ -440,7 +440,7 @@ package com.google.firebase.firestore { method public com.google.firebase.firestore.Pipeline replace(com.google.firebase.firestore.pipeline.Expr mapValue); method public com.google.firebase.firestore.Pipeline replace(String field); method public com.google.firebase.firestore.Pipeline sample(com.google.firebase.firestore.pipeline.SampleStage sample); - method public com.google.firebase.firestore.Pipeline sample(int documents); + method public com.google.firebase.firestore.Pipeline sample(int count); method public com.google.firebase.firestore.Pipeline select(com.google.firebase.firestore.pipeline.Selectable selection, java.lang.Object... additionalSelections); method public com.google.firebase.firestore.Pipeline select(String fieldName, java.lang.Object... additionalSelections); method public com.google.firebase.firestore.Pipeline sort(com.google.firebase.firestore.pipeline.Ordering order, com.google.firebase.firestore.pipeline.Ordering... additionalOrders); @@ -680,8 +680,8 @@ package com.google.firebase.firestore.pipeline { public abstract class AbstractOptions> { method public final T with(String key, boolean value); method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); - method public final T with(String key, com.google.firebase.firestore.pipeline.GenericOptions value); method protected final T with(String key, com.google.firebase.firestore.pipeline.InternalOptions value); + method public final T with(String key, com.google.firebase.firestore.pipeline.RawOptions value); method public final T with(String key, double value); method protected final T with(String key, error.NonExistentClass value); method public final T with(String key, String value); @@ -696,11 +696,11 @@ package com.google.firebase.firestore.pipeline { method public static com.google.firebase.firestore.pipeline.AggregateFunction count(String fieldName); method public static com.google.firebase.firestore.pipeline.AggregateFunction countAll(); method public static com.google.firebase.firestore.pipeline.AggregateFunction countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); - method public static com.google.firebase.firestore.pipeline.AggregateFunction generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public static com.google.firebase.firestore.pipeline.AggregateFunction maximum(com.google.firebase.firestore.pipeline.Expr expression); method public static com.google.firebase.firestore.pipeline.AggregateFunction maximum(String fieldName); method public static com.google.firebase.firestore.pipeline.AggregateFunction minimum(com.google.firebase.firestore.pipeline.Expr expression); method public static com.google.firebase.firestore.pipeline.AggregateFunction minimum(String fieldName); + method public static com.google.firebase.firestore.pipeline.AggregateFunction raw(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public static com.google.firebase.firestore.pipeline.AggregateFunction sum(com.google.firebase.firestore.pipeline.Expr expression); method public static com.google.firebase.firestore.pipeline.AggregateFunction sum(String fieldName); field public static final com.google.firebase.firestore.pipeline.AggregateFunction.Companion Companion; @@ -713,11 +713,11 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.AggregateFunction count(String fieldName); method public com.google.firebase.firestore.pipeline.AggregateFunction countAll(); method public com.google.firebase.firestore.pipeline.AggregateFunction countIf(com.google.firebase.firestore.pipeline.BooleanExpr condition); - method public com.google.firebase.firestore.pipeline.AggregateFunction generic(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public com.google.firebase.firestore.pipeline.AggregateFunction maximum(com.google.firebase.firestore.pipeline.Expr expression); method public com.google.firebase.firestore.pipeline.AggregateFunction maximum(String fieldName); method public com.google.firebase.firestore.pipeline.AggregateFunction minimum(com.google.firebase.firestore.pipeline.Expr expression); method public com.google.firebase.firestore.pipeline.AggregateFunction minimum(String fieldName); + method public com.google.firebase.firestore.pipeline.AggregateFunction raw(String name, com.google.firebase.firestore.pipeline.Expr... expr); method public com.google.firebase.firestore.pipeline.AggregateFunction sum(com.google.firebase.firestore.pipeline.Expr expression); method public com.google.firebase.firestore.pipeline.AggregateFunction sum(String fieldName); } @@ -772,59 +772,6 @@ package com.google.firebase.firestore.pipeline { method public com.google.firebase.firestore.pipeline.CollectionSource of(String path); } - public final class ExplainOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { - method public error.NonExistentClass withIndexRecommendation(boolean value); - method public error.NonExistentClass withMode(com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode value); - method public error.NonExistentClass withOutputFormat(com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat value); - method public error.NonExistentClass withProfiles(com.google.firebase.firestore.pipeline.ExplainOptions.Profiles value); - method public error.NonExistentClass withRedact(boolean value); - method public error.NonExistentClass withVerbosity(com.google.firebase.firestore.pipeline.ExplainOptions.Verbosity value); - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions DEFAULT; - } - - public static final class ExplainOptions.Companion { - } - - public static final class ExplainOptions.ExplainMode { - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode ANALYZE; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode EXECUTE; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.ExplainMode EXPLAIN; - } - - public static final class ExplainOptions.ExplainMode.Companion { - } - - public static final class ExplainOptions.OutputFormat { - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat JSON; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat STRUCT; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.OutputFormat TEXT; - } - - public static final class ExplainOptions.OutputFormat.Companion { - } - - public static final class ExplainOptions.Profiles { - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Profiles BYTES_THROUGHPUT; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Profiles.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Profiles LATENCY; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Profiles RECORDS_COUNT; - } - - public static final class ExplainOptions.Profiles.Companion { - } - - public static final class ExplainOptions.Verbosity { - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Verbosity.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Verbosity EXECUTION_TREE; - field public static final com.google.firebase.firestore.pipeline.ExplainOptions.Verbosity SUMMARY_ONLY; - } - - public static final class ExplainOptions.Verbosity.Companion { - } - public abstract class Expr { method public final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr second); method public static final com.google.firebase.firestore.pipeline.Expr add(com.google.firebase.firestore.pipeline.Expr first, com.google.firebase.firestore.pipeline.Expr second); @@ -1056,6 +1003,7 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, com.google.firebase.firestore.pipeline.Expr expression); method public static final com.google.firebase.firestore.pipeline.BooleanExpr lte(String fieldName, Object value); method public static final com.google.firebase.firestore.pipeline.Expr map(java.util.Map elements); + method public final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr keyExpression); method public static final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr mapExpression, com.google.firebase.firestore.pipeline.Expr keyExpression); method public static final com.google.firebase.firestore.pipeline.Expr mapGet(com.google.firebase.firestore.pipeline.Expr mapExpression, String key); method public final com.google.firebase.firestore.pipeline.Expr mapGet(String key); @@ -1064,7 +1012,7 @@ package com.google.firebase.firestore.pipeline { method public static final com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr firstMap, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); method public final com.google.firebase.firestore.pipeline.Expr mapMerge(com.google.firebase.firestore.pipeline.Expr mapExpr, com.google.firebase.firestore.pipeline.Expr... otherMaps); method public static final com.google.firebase.firestore.pipeline.Expr mapMerge(String firstMapFieldName, com.google.firebase.firestore.pipeline.Expr secondMap, com.google.firebase.firestore.pipeline.Expr... otherMaps); - method public final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr key); + method public final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr keyExpression); method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr mapExpr, com.google.firebase.firestore.pipeline.Expr key); method public static final com.google.firebase.firestore.pipeline.Expr mapRemove(com.google.firebase.firestore.pipeline.Expr mapExpr, String key); method public final com.google.firebase.firestore.pipeline.Expr mapRemove(String key); @@ -1485,6 +1433,10 @@ package com.google.firebase.firestore.pipeline { } public final class ExprWithAlias extends com.google.firebase.firestore.pipeline.Selectable { + method public String getAlias(); + method public com.google.firebase.firestore.pipeline.Expr getExpr(); + property public String alias; + property public com.google.firebase.firestore.pipeline.Expr expr; } public final class Field extends com.google.firebase.firestore.pipeline.Selectable { @@ -1526,14 +1478,6 @@ package com.google.firebase.firestore.pipeline { public class FunctionExpr extends com.google.firebase.firestore.pipeline.Expr { } - public final class GenericOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { - field public static final com.google.firebase.firestore.pipeline.GenericOptions.Companion Companion; - field public static final com.google.firebase.firestore.pipeline.GenericOptions DEFAULT; - } - - public static final class GenericOptions.Companion { - } - public final class InternalOptions { field public static final com.google.firebase.firestore.pipeline.InternalOptions.Companion Companion; field public static final com.google.firebase.firestore.pipeline.InternalOptions EMPTY; @@ -1562,7 +1506,6 @@ package com.google.firebase.firestore.pipeline { } public final class PipelineOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { - method public com.google.firebase.firestore.pipeline.PipelineOptions withExplainOptions(com.google.firebase.firestore.pipeline.ExplainOptions options); method public com.google.firebase.firestore.pipeline.PipelineOptions withIndexMode(com.google.firebase.firestore.pipeline.PipelineOptions.IndexMode indexMode); field public static final com.google.firebase.firestore.pipeline.PipelineOptions.Companion Companion; field public static final com.google.firebase.firestore.pipeline.PipelineOptions DEFAULT; @@ -1579,6 +1522,14 @@ package com.google.firebase.firestore.pipeline { public static final class PipelineOptions.IndexMode.Companion { } + public final class RawOptions extends com.google.firebase.firestore.pipeline.AbstractOptions { + field public static final com.google.firebase.firestore.pipeline.RawOptions.Companion Companion; + field public static final com.google.firebase.firestore.pipeline.RawOptions DEFAULT; + } + + public static final class RawOptions.Companion { + } + public final class RawStage extends com.google.firebase.firestore.pipeline.Stage { method public static com.google.firebase.firestore.pipeline.RawStage ofName(String name); method public com.google.firebase.firestore.pipeline.RawStage withArguments(java.lang.Object... arguments); @@ -1590,13 +1541,13 @@ package com.google.firebase.firestore.pipeline { } public final class SampleStage extends com.google.firebase.firestore.pipeline.Stage { - method public static com.google.firebase.firestore.pipeline.SampleStage withDocLimit(int documents); + method public static com.google.firebase.firestore.pipeline.SampleStage withCount(int count); method public static com.google.firebase.firestore.pipeline.SampleStage withPercentage(double percentage); field public static final com.google.firebase.firestore.pipeline.SampleStage.Companion Companion; } public static final class SampleStage.Companion { - method public com.google.firebase.firestore.pipeline.SampleStage withDocLimit(int documents); + method public com.google.firebase.firestore.pipeline.SampleStage withCount(int count); method public com.google.firebase.firestore.pipeline.SampleStage withPercentage(double percentage); } @@ -1615,14 +1566,14 @@ package com.google.firebase.firestore.pipeline { ctor public Selectable(); } - public abstract class Stage> { + public abstract sealed class Stage> { method protected final String getName(); - method public final T with(String key, boolean value); - method public final T with(String key, com.google.firebase.firestore.pipeline.Field value); - method public final T with(String key, double value); - method protected final T with(String key, error.NonExistentClass value); - method public final T with(String key, String value); - method public final T with(String key, long value); + method public final T withOption(String key, boolean value); + method public final T withOption(String key, com.google.firebase.firestore.pipeline.Field value); + method public final T withOption(String key, double value); + method protected final T withOption(String key, error.NonExistentClass value); + method public final T withOption(String key, String value); + method public final T withOption(String key, long value); property protected final String name; } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt index c1b09bcf94e..644542cd657 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/Pipeline.kt @@ -32,6 +32,7 @@ import com.google.firebase.firestore.pipeline.DatabaseSource import com.google.firebase.firestore.pipeline.DistinctStage import com.google.firebase.firestore.pipeline.DocumentsSource import com.google.firebase.firestore.pipeline.Expr +import com.google.firebase.firestore.pipeline.Expr.Companion.field import com.google.firebase.firestore.pipeline.ExprWithAlias import com.google.firebase.firestore.pipeline.Field import com.google.firebase.firestore.pipeline.FindNearestStage @@ -153,9 +154,7 @@ internal constructor( */ fun removeFields(field: String, vararg additionalFields: String): Pipeline = append( - RemoveFieldsStage( - arrayOf(Expr.field(field), *additionalFields.map(Expr::field).toTypedArray()) - ) + RemoveFieldsStage(arrayOf(field(field), *additionalFields.map(Expr::field).toTypedArray())) ) /** @@ -178,11 +177,7 @@ internal constructor( * @return A new [Pipeline] object with this stage appended to the stage list. */ fun select(selection: Selectable, vararg additionalSelections: Any): Pipeline = - append( - SelectStage( - arrayOf(selection, *additionalSelections.map(Selectable::toSelectable).toTypedArray()) - ) - ) + append(SelectStage.of(selection, *additionalSelections)) /** * Selects or creates a set of fields from the outputs of previous stages. @@ -204,14 +199,7 @@ internal constructor( * @return A new [Pipeline] object with this stage appended to the stage list. */ fun select(fieldName: String, vararg additionalSelections: Any): Pipeline = - append( - SelectStage( - arrayOf( - Expr.field(fieldName), - *additionalSelections.map(Selectable::toSelectable).toTypedArray() - ) - ) - ) + append(SelectStage.of(fieldName, *additionalSelections)) /** * Sorts the documents from previous stages based on one or more [Ordering] criteria. @@ -320,10 +308,7 @@ internal constructor( fun distinct(groupField: String, vararg additionalGroups: Any): Pipeline = append( DistinctStage( - arrayOf( - Expr.field(groupField), - *additionalGroups.map(Selectable::toSelectable).toTypedArray() - ) + arrayOf(field(groupField), *additionalGroups.map(Selectable::toSelectable).toTypedArray()) ) ) @@ -453,10 +438,10 @@ internal constructor( * @param field The [String] specifying the field name containing the nested map. * @return A new [Pipeline] object with this stage appended to the stage list. */ - fun replace(field: String): Pipeline = replace(Expr.field(field)) + fun replace(field: String): Pipeline = replace(field(field)) /** - * Fully overwrites all fields in a document with those coming from a nested map. + * Fully overwrites all fields in a document with those coming from a map. * * This stage allows you to emit a map value as a document. Each key of the map becomes a field on * the document that contains the corresponding value. @@ -470,15 +455,15 @@ internal constructor( /** * Performs a pseudo-random sampling of the input documents. * - * The [documents] parameter represents the target number of documents to produce and must be a + * The [count] parameter represents the target number of documents to produce and must be a * non-negative integer value. If the previous stage produces less than size documents, the entire * previous results are returned. If the previous stage produces more than size, this outputs a * sample of exactly size entries where any sample is equally likely. * - * @param documents The number of documents to emit. + * @param count The number of documents to emit. * @return A new [Pipeline] object with this stage appended to the stage list. */ - fun sample(documents: Int): Pipeline = append(SampleStage.withDocLimit(documents)) + fun sample(count: Int): Pipeline = append(SampleStage.withCount(count)) /** * Performs a pseudo-random sampling of the input documents. @@ -514,8 +499,7 @@ internal constructor( * @param alias The name of field to store emitted element of array. * @return A new [Pipeline] object with this stage appended to the stage list. */ - fun unnest(arrayField: String, alias: String): Pipeline = - unnest(Expr.field(arrayField).alias(alias)) + fun unnest(arrayField: String, alias: String): Pipeline = unnest(field(arrayField).alias(alias)) /** * Takes a specified array from the input documents and outputs a document for each element with @@ -644,7 +628,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto * Set the pipeline's source to the collection specified by CollectionSource. * * @param stage A [CollectionSource] that will be the source of this pipeline. - * @return Pipeline with documents from target collection. + * @return A new [Pipeline] object with documents from target collection. * @throws [IllegalArgumentException] Thrown if the [stage] provided targets a different project * or database than the pipeline. */ @@ -659,6 +643,7 @@ class PipelineSource internal constructor(private val firestore: FirebaseFiresto * Set the pipeline's source to the collection group with the given id. * * @param collectionId The id of a collection group that will be the source of this pipeline. + * @return A new [Pipeline] object with documents from target collection group. */ fun collectionGroup(collectionId: String): Pipeline = pipeline(CollectionGroupSource.of((collectionId))) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java index 051dfce922b..e4176a42e17 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/FieldPath.java @@ -22,7 +22,12 @@ /** A dot separated path for navigating sub-objects with in a document */ public final class FieldPath extends BasePath { + public static final String UPDATE_TIME_NAME = "__update_time__"; + public static final String CREATE_TIME_NAME = "__create_time__"; + public static final FieldPath KEY_PATH = fromSingleSegment(DocumentKey.KEY_FIELD_NAME); + public static final FieldPath UPDATE_TIME_PATH = fromSingleSegment(UPDATE_TIME_NAME); + public static final FieldPath CREATE_TIME_PATH = fromSingleSegment(CREATE_TIME_NAME); public static final FieldPath EMPTY_PATH = new FieldPath(Collections.emptyList()); private FieldPath(List segments) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt index 0ce88ce385b..d179d0eff4a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/aggregates.kt @@ -33,7 +33,7 @@ private constructor( companion object { - @JvmStatic fun generic(name: String, vararg expr: Expr) = AggregateFunction(name, expr) + @JvmStatic fun raw(name: String, vararg expr: Expr) = AggregateFunction(name, expr) /** * Creates an aggregation that counts the total number of stage inputs. diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt index 3388b4b8b4d..2cae16fc312 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt @@ -24,6 +24,9 @@ import com.google.firebase.firestore.UserDataReader import com.google.firebase.firestore.VectorValue import com.google.firebase.firestore.model.DocumentKey import com.google.firebase.firestore.model.FieldPath as ModelFieldPath +import com.google.firebase.firestore.model.FieldPath.CREATE_TIME_PATH +import com.google.firebase.firestore.model.FieldPath.KEY_PATH +import com.google.firebase.firestore.model.FieldPath.UPDATE_TIME_PATH import com.google.firebase.firestore.model.Values import com.google.firebase.firestore.model.Values.encodeValue import com.google.firebase.firestore.pipeline.Expr.Companion.field @@ -154,6 +157,10 @@ abstract class Expr internal constructor() { @JvmStatic fun constant(value: Boolean): BooleanExpr { val encodedValue = encodeValue(value) + // To return a BooleanExpr, we need to break the pattern that expects a BooleanExpr to be a + // "pipeline function". In stead of building on serialization logic built into BooleanExpr, + // we override methods. The constructor parameters are irrelevant, since the internal + // BooleanExpr logic is never invoked. return object : BooleanExpr("N/A", emptyArray()) { override fun toProto(userDataReader: UserDataReader): Value { return encodedValue @@ -224,10 +231,7 @@ abstract class Expr internal constructor() { * @param value The [VectorValue] value. * @return A new [Expr] constant instance. */ - @JvmStatic - fun constant(value: VectorValue): Expr { - return Constant(encodeValue(value)) - } + @JvmStatic fun constant(value: VectorValue): Expr = Constant(encodeValue(value)) /** * Create a [Blob] constant from a [ByteArray]. @@ -235,20 +239,14 @@ abstract class Expr internal constructor() { * @param bytes The [ByteArray] to convert to a Blob. * @return A new [Expr] constant instance representing the Blob. */ - @JvmStatic - fun blob(bytes: ByteArray): Expr { - return constant(Blob.fromBytes(bytes)) - } + @JvmStatic fun blob(bytes: ByteArray): Expr = constant(Blob.fromBytes(bytes)) /** * Constant for a null value. * * @return A [Expr] constant instance. */ - @JvmStatic - fun nullValue(): Expr { - return NULL - } + @JvmStatic fun nullValue(): Expr = NULL /** * Create a vector constant for a [DoubleArray] value. @@ -256,10 +254,7 @@ abstract class Expr internal constructor() { * @param vector The [VectorValue] value. * @return A [Expr] constant instance. */ - @JvmStatic - fun vector(vector: DoubleArray): Expr { - return Constant(Values.encodeVectorValue(vector)) - } + @JvmStatic fun vector(vector: DoubleArray): Expr = Constant(Values.encodeVectorValue(vector)) /** * Create a vector constant for a [VectorValue] value. @@ -267,10 +262,7 @@ abstract class Expr internal constructor() { * @param vector The [VectorValue] value. * @return A [Expr] constant instance. */ - @JvmStatic - fun vector(vector: VectorValue): Expr { - return Constant(encodeValue(vector)) - } + @JvmStatic fun vector(vector: VectorValue): Expr = Constant(encodeValue(vector)) /** * Creates a [Field] instance representing the field at the given path. @@ -283,10 +275,12 @@ abstract class Expr internal constructor() { */ @JvmStatic fun field(name: String): Field { - if (name == DocumentKey.KEY_FIELD_NAME) { - return Field(ModelFieldPath.KEY_PATH) + return when (name) { + DocumentKey.KEY_FIELD_NAME -> Field(KEY_PATH) + ModelFieldPath.CREATE_TIME_NAME -> Field(CREATE_TIME_PATH) + ModelFieldPath.UPDATE_TIME_NAME -> Field(UPDATE_TIME_PATH) + else -> Field(FieldPath.fromDotSeparatedPath(name).internalPath) } - return Field(FieldPath.fromDotSeparatedPath(name).internalPath) } /** @@ -298,10 +292,7 @@ abstract class Expr internal constructor() { * @param fieldPath The [FieldPath] to the field. * @return A new [Field] instance representing the specified path. */ - @JvmStatic - fun field(fieldPath: FieldPath): Field { - return Field(fieldPath.internalPath) - } + @JvmStatic fun field(fieldPath: FieldPath): Field = Field(fieldPath.internalPath) @JvmStatic fun generic(name: String, vararg expr: Expr): Expr = FunctionExpr(name, expr) @@ -1263,7 +1254,7 @@ abstract class Expr internal constructor() { FunctionExpr("replace_all", fieldName, find, replace) /** - * Creates an expression that calculates the character length of a string expression in UTF8. + * Creates an expression that calculates the character length of a string expression. * * @param expr The expression representing the string. * @return A new [Expr] representing the charLength operation. @@ -1271,7 +1262,7 @@ abstract class Expr internal constructor() { @JvmStatic fun charLength(expr: Expr): Expr = FunctionExpr("char_length", expr) /** - * Creates an expression that calculates the character length of a string field in UTF8. + * Creates an expression that calculates the character length of a string field. * * @param fieldName The name of the field containing the string. * @return A new [Expr] representing the charLength operation. @@ -1399,7 +1390,8 @@ abstract class Expr internal constructor() { BooleanExpr("regex_contains", fieldName, pattern) /** - * Creates an expression that checks if a string field matches a specified regular expression. + * Creates an expression that checks if a string expression matches a specified regular + * expression. * * @param stringExpression The expression representing the string to match against. * @param pattern The regular expression to use for the match. @@ -1410,7 +1402,8 @@ abstract class Expr internal constructor() { BooleanExpr("regex_match", stringExpression, pattern) /** - * Creates an expression that checks if a string field matches a specified regular expression. + * Creates an expression that checks if a string expression matches a specified regular + * expression. * * @param stringExpression The expression representing the string to match against. * @param pattern The regular expression to use for the match. @@ -1573,7 +1566,7 @@ abstract class Expr internal constructor() { BooleanExpr("starts_with", stringExpr, prefix) /** - * Creates an expression that checks if a string expression starts with a given [prefix]. + * Creates an expression that checks if a string field starts with a given [prefix]. * * @param fieldName The name of field that contains a string to check. * @param prefix The prefix string expression to check for. @@ -1584,7 +1577,7 @@ abstract class Expr internal constructor() { BooleanExpr("starts_with", fieldName, prefix) /** - * Creates an expression that checks if a string expression starts with a given [prefix]. + * Creates an expression that checks if a string field starts with a given [prefix]. * * @param fieldName The name of field that contains a string to check. * @param prefix The prefix string to check for. @@ -1617,7 +1610,7 @@ abstract class Expr internal constructor() { BooleanExpr("ends_with", stringExpr, suffix) /** - * Creates an expression that checks if a string expression ends with a given [suffix]. + * Creates an expression that checks if a string field ends with a given [suffix]. * * @param fieldName The name of field that contains a string to check. * @param suffix The suffix string expression to check for. @@ -1628,7 +1621,7 @@ abstract class Expr internal constructor() { BooleanExpr("ends_with", fieldName, suffix) /** - * Creates an expression that checks if a string expression ends with a given [suffix]. + * Creates an expression that checks if a string field ends with a given [suffix]. * * @param fieldName The name of field that contains a string to check. * @param suffix The suffix string to check for. @@ -2910,6 +2903,9 @@ abstract class Expr internal constructor() { fun ifError(tryExpr: Expr, catchValue: Any): Expr = FunctionExpr("if_error", tryExpr, catchValue) + // TODO: we should double check that we want to ship `documentId` expression and that it wasn't + // intended for internal use in the backend + /** * Creates an expression that returns the document ID from a path. * @@ -3034,6 +3030,9 @@ abstract class Expr internal constructor() { */ open fun alias(alias: String) = ExprWithAlias(alias, this) + // TODO: we should double check that we want to ship `documentId` expression and that it wasn't + // intended for internal use in the backend + /** * Creates an expression that returns the document ID from this path expression. * @@ -3514,6 +3513,14 @@ abstract class Expr internal constructor() { */ fun strConcat(vararg strings: Any): Expr = Companion.strConcat(this, *strings) + /** + * Accesses a map (object) value using the provided [keyExpression]. + * + * @param keyExpression The name of the key to remove from this map expression. + * @return A new [Expr] representing the value associated with the given key in the map. + */ + fun mapGet(keyExpression: Expr) = Companion.mapGet(this, keyExpression) + /** * Accesses a map (object) value using the provided [key]. * @@ -3536,10 +3543,10 @@ abstract class Expr internal constructor() { /** * Creates an expression that removes a key from this map expression. * - * @param key The name of the key to remove from this map expression. + * @param keyExpression The name of the key to remove from this map expression. * @return A new [Expr] that evaluates to a modified map. */ - fun mapRemove(key: Expr) = Companion.mapRemove(this, key) + fun mapRemove(keyExpression: Expr) = Companion.mapRemove(this, keyExpression) /** * Creates an expression that removes a key from this map expression. @@ -4011,8 +4018,8 @@ abstract class Expr internal constructor() { /** Expressions that have an alias are [Selectable] */ abstract class Selectable : Expr() { - internal abstract fun getAlias(): String - internal abstract fun getExpr(): Expr + internal abstract val alias: String + internal abstract val expr: Expr internal companion object { fun toSelectable(o: Any): Selectable { @@ -4027,10 +4034,8 @@ abstract class Selectable : Expr() { } /** Represents an expression that will be given the alias in the output document. */ -class ExprWithAlias internal constructor(private val alias: String, private val expr: Expr) : +class ExprWithAlias internal constructor(override val alias: String, override val expr: Expr) : Selectable() { - override fun getAlias() = alias - override fun getExpr() = expr override fun toProto(userDataReader: UserDataReader): Value = expr.toProto(userDataReader) } @@ -4050,12 +4055,16 @@ class Field internal constructor(private val fieldPath: ModelFieldPath) : Select * * @return An [Field] representing the document ID. */ - @JvmField val DOCUMENT_ID: Field = field(FieldPath.documentId()) + @JvmField val DOCUMENT_ID: Field = Field(KEY_PATH) + + @JvmField internal val UPDATE_TIME: Field = Field(UPDATE_TIME_PATH) + + @JvmField internal val CREATE_TIME: Field = Field(CREATE_TIME_PATH) } - override fun getAlias(): String = fieldPath.canonicalString() + override val alias: String = fieldPath.canonicalString() - override fun getExpr(): Expr = this + override val expr: Expr = this override fun toProto(userDataReader: UserDataReader) = toProto() diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt index 27d5375f3ab..9e748e12f14 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt @@ -120,21 +120,21 @@ internal constructor(internal val options: InternalOptions) { fun with(key: String, value: Field): T = with(key, value.toProto()) /** - * Specify [GenericOptions] object + * Specify [RawOptions] object * * @param key The option key - * @param value The [GenericOptions] object + * @param value The [RawOptions] object * @return A new options object. */ - fun with(key: String, value: GenericOptions): T = with(key, value.options) + fun with(key: String, value: RawOptions): T = with(key, value.options) } -class GenericOptions private constructor(options: InternalOptions) : - AbstractOptions(options) { - override fun self(options: InternalOptions) = GenericOptions(options) +class RawOptions private constructor(options: InternalOptions) : + AbstractOptions(options) { + override fun self(options: InternalOptions) = RawOptions(options) companion object { - @JvmField val DEFAULT: GenericOptions = GenericOptions(InternalOptions.EMPTY) + @JvmField val DEFAULT: RawOptions = RawOptions(InternalOptions.EMPTY) } } @@ -154,66 +154,4 @@ class PipelineOptions private constructor(options: InternalOptions) : } fun withIndexMode(indexMode: IndexMode): PipelineOptions = with("index_mode", indexMode.value) - - fun withExplainOptions(options: ExplainOptions): PipelineOptions = - with("explain_options", options.options) -} - -class ExplainOptions private constructor(options: InternalOptions) : - AbstractOptions(options) { - override fun self(options: InternalOptions) = ExplainOptions(options) - - companion object { - @JvmField val DEFAULT = ExplainOptions(InternalOptions.EMPTY) - } - - fun withMode(value: ExplainMode) = with("mode", value.value) - - fun withOutputFormat(value: OutputFormat) = with("output_format", value.value) - - fun withVerbosity(value: Verbosity) = with("verbosity", value.value) - - fun withIndexRecommendation(value: Boolean) = with("index_recommendation", value) - - fun withProfiles(value: Profiles) = with("profiles", value.value) - - fun withRedact(value: Boolean) = with("redact", value) - - class ExplainMode private constructor(internal val value: String) { - companion object { - @JvmField val EXECUTE = ExplainMode("execute") - - @JvmField val EXPLAIN = ExplainMode("explain") - - @JvmField val ANALYZE = ExplainMode("analyze") - } - } - - class OutputFormat private constructor(internal val value: String) { - companion object { - @JvmField val TEXT = OutputFormat("text") - - @JvmField val JSON = OutputFormat("json") - - @JvmField val STRUCT = OutputFormat("struct") - } - } - - class Verbosity private constructor(internal val value: String) { - companion object { - @JvmField val SUMMARY_ONLY = Verbosity("summary_only") - - @JvmField val EXECUTION_TREE = Verbosity("execution_tree") - } - } - - class Profiles private constructor(internal val value: String) { - companion object { - @JvmField val LATENCY = Profiles("latency") - - @JvmField val RECORDS_COUNT = Profiles("records_count") - - @JvmField val BYTES_THROUGHPUT = Profiles("bytes_throughput") - } - } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt index 4271c973c28..dc537fff052 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/stage.kt @@ -27,8 +27,10 @@ import com.google.firebase.firestore.util.Preconditions import com.google.firestore.v1.Pipeline import com.google.firestore.v1.Value -abstract class Stage> -internal constructor(protected val name: String, internal val options: InternalOptions) { +sealed class Stage>( + protected val name: String, + internal val options: InternalOptions +) { internal fun toProtoStage(userDataReader: UserDataReader): Pipeline.Stage { val builder = Pipeline.Stage.newBuilder() builder.setName(name) @@ -40,7 +42,7 @@ internal constructor(protected val name: String, internal val options: InternalO internal abstract fun self(options: InternalOptions): T - protected fun with(key: String, value: Value): T = self(options.with(key, value)) + protected fun withOption(key: String, value: Value): T = self(options.with(key, value)) /** * Specify named [String] parameter @@ -49,7 +51,7 @@ internal constructor(protected val name: String, internal val options: InternalO * @param value The [String] value of parameter * @return New stage with named parameter. */ - fun with(key: String, value: String): T = with(key, Values.encodeValue(value)) + fun withOption(key: String, value: String): T = withOption(key, Values.encodeValue(value)) /** * Specify named [Boolean] parameter @@ -58,7 +60,7 @@ internal constructor(protected val name: String, internal val options: InternalO * @param value The [Boolean] value of parameter * @return New stage with named parameter. */ - fun with(key: String, value: Boolean): T = with(key, Values.encodeValue(value)) + fun withOption(key: String, value: Boolean): T = withOption(key, Values.encodeValue(value)) /** * Specify named [Long] parameter @@ -67,7 +69,7 @@ internal constructor(protected val name: String, internal val options: InternalO * @param value The [Long] value of parameter * @return New stage with named parameter. */ - fun with(key: String, value: Long): T = with(key, Values.encodeValue(value)) + fun withOption(key: String, value: Long): T = withOption(key, Values.encodeValue(value)) /** * Specify named [Double] parameter @@ -76,7 +78,7 @@ internal constructor(protected val name: String, internal val options: InternalO * @param value The [Double] value of parameter * @return New stage with named parameter. */ - fun with(key: String, value: Double): T = with(key, Values.encodeValue(value)) + fun withOption(key: String, value: Double): T = withOption(key, Values.encodeValue(value)) /** * Specify named [Field] parameter @@ -85,7 +87,7 @@ internal constructor(protected val name: String, internal val options: InternalO * @param value The [Field] value of parameter * @return New stage with named parameter. */ - fun with(key: String, value: Field): T = with(key, value.toProto()) + fun withOption(key: String, value: Field): T = withOption(key, value.toProto()) } /** @@ -211,7 +213,7 @@ internal constructor( } } - fun withForceIndex(value: String) = with("force_index", value) + fun withForceIndex(value: String) = withOption("force_index", value) } class CollectionGroupSource @@ -238,7 +240,7 @@ private constructor(private val collectionId: String, options: InternalOptions) } } - fun withForceIndex(value: String) = with("force_index", value) + fun withForceIndex(value: String) = withOption("force_index", value) } internal class DocumentsSource @@ -260,7 +262,7 @@ internal constructor( ) : Stage("add_fields", options) { override fun self(options: InternalOptions) = AddFieldsStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = - sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) + sequenceOf(encodeValue(fields.associate { it.alias to it.toProto(userDataReader) })) } /** @@ -334,8 +336,8 @@ internal constructor( fun withGroups(group: Selectable, vararg additionalGroups: Any) = AggregateStage( accumulators, - mapOf(group.getAlias() to group.getExpr()) - .plus(additionalGroups.map(Selectable::toSelectable).associateBy(Selectable::getAlias)) + mapOf(group.alias to group.expr) + .plus(additionalGroups.map(Selectable::toSelectable).associateBy(Selectable::alias)) ) override fun args(userDataReader: UserDataReader): Sequence = @@ -454,7 +456,7 @@ internal constructor( * @param limit must be a positive integer. * @return [FindNearestStage] with specified [limit]. */ - fun withLimit(limit: Long): FindNearestStage = with("limit", limit) + fun withLimit(limit: Long): FindNearestStage = withOption("limit", limit) /** * Add a field containing the distance to the result. @@ -463,7 +465,7 @@ internal constructor( * @return [FindNearestStage] with specified [distanceField]. */ fun withDistanceField(distanceField: Field): FindNearestStage = - with("distance_field", distanceField) + withOption("distance_field", distanceField) /** * Add a field containing the distance to the result. @@ -492,13 +494,23 @@ internal constructor(private val offset: Int, options: InternalOptions = Interna } internal class SelectStage -internal constructor( - private val fields: Array, - options: InternalOptions = InternalOptions.EMPTY -) : Stage("select", options) { +private constructor(internal val fields: Array, options: InternalOptions) : + Stage("select", options) { + companion object { + @JvmStatic + fun of(selection: Selectable, vararg additionalSelections: Any): SelectStage = + SelectStage( + arrayOf(selection, *additionalSelections.map(Selectable::toSelectable).toTypedArray()), + InternalOptions.EMPTY + ) + + @JvmStatic + fun of(fieldName: String, vararg additionalSelections: Any): SelectStage = + of(field(fieldName), *additionalSelections) + } override fun self(options: InternalOptions) = SelectStage(fields, options) override fun args(userDataReader: UserDataReader): Sequence = - sequenceOf(encodeValue(fields.associate { it.getAlias() to it.toProto(userDataReader) })) + sequenceOf(encodeValue(fields.associate { it.alias to it.toProto(userDataReader) })) } internal class SortStage @@ -518,7 +530,7 @@ internal constructor( ) : Stage("distinct", options) { override fun self(options: InternalOptions) = DistinctStage(groups, options) override fun args(userDataReader: UserDataReader): Sequence = - sequenceOf(encodeValue(groups.associate { it.getAlias() to it.toProto(userDataReader) })) + sequenceOf(encodeValue(groups.associate { it.alias to it.toProto(userDataReader) })) } internal class RemoveFieldsStage @@ -588,15 +600,15 @@ private constructor( /** * Creates [SampleStage] with size limited to number of documents. * - * The [documents] parameter represents the target number of documents to produce and must be a + * The [count] parameter represents the target number of documents to produce and must be a * non-negative integer value. If the previous stage produces less than size documents, the * entire previous results are returned. If the previous stage produces more than size, this * outputs a sample of exactly size entries where any sample is equally likely. * - * @param documents The number of documents to emit. - * @return [SampleStage] with specified [documents]. + * @param count The number of documents to emit. + * @return [SampleStage] with specified [count]. */ - @JvmStatic fun withDocLimit(documents: Int) = SampleStage(documents, Mode.DOCUMENTS) + @JvmStatic fun withCount(count: Int) = SampleStage(count, Mode.DOCUMENTS) } override fun args(userDataReader: UserDataReader): Sequence = sequenceOf(encodeValue(size), mode.proto) @@ -652,11 +664,11 @@ internal constructor( */ @JvmStatic fun withField(arrayField: String, alias: String): UnnestStage = - UnnestStage(Expr.field(arrayField).alias(alias)) + UnnestStage(Expr.Companion.field(arrayField).alias(alias)) } override fun self(options: InternalOptions) = UnnestStage(selectable, options) override fun args(userDataReader: UserDataReader): Sequence = - sequenceOf(encodeValue(selectable.getAlias()), selectable.toProto(userDataReader)) + sequenceOf(encodeValue(selectable.alias), selectable.toProto(userDataReader)) /** * Adds index field to emitted documents @@ -667,5 +679,5 @@ internal constructor( * @param indexField The field name of index field. * @return [SampleStage] that includes specified index field. */ - fun withIndexField(indexField: String): UnnestStage = with("index_field", indexField) + fun withIndexField(indexField: String): UnnestStage = withOption("index_field", indexField) } From f579bf451579f27a82fc6ef2b8887e5b41a124ee Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Mon, 28 Jul 2025 14:21:38 -0400 Subject: [PATCH 77/77] Copyright --- .../google/firebase/firestore/util/BiFunction.java | 14 ++++++++++++++ .../firebase/firestore/util/IntFunction.java | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/BiFunction.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/BiFunction.java index 1afb87fbb1d..f4283a44408 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/BiFunction.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/BiFunction.java @@ -1,3 +1,17 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.google.firebase.firestore.util; /** A port of {@link java.util.function.BiFunction} */ diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/IntFunction.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/IntFunction.java index 2407db54808..05257e9a9f4 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/util/IntFunction.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/util/IntFunction.java @@ -1,3 +1,17 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.google.firebase.firestore.util; /** A port of {@link java.util.function.IntFunction} */