diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/AggregateFunction.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/AggregateFunction.java index d3a3bba36..1cab69389 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/AggregateFunction.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/AggregateFunction.java @@ -214,6 +214,111 @@ public static AggregateFunction maximum(Expression expression) { return new AggregateFunction("maximum", expression); } + /** + * Creates an aggregation that finds the first value of a field across multiple stage inputs. + * + * @param fieldName The name of the field to find the first value of. + * @return A new {@link AggregateFunction} representing the first aggregation. + */ + @BetaApi + public static AggregateFunction first(String fieldName) { + return new AggregateFunction("first", fieldName); + } + + /** + * Creates an aggregation that finds the first value of an expression across multiple stage + * inputs. + * + * @param expression The expression to find the first value of. + * @return A new {@link AggregateFunction} representing the first aggregation. + */ + @BetaApi + public static AggregateFunction first(Expression expression) { + return new AggregateFunction("first", expression); + } + + /** + * Creates an aggregation that finds the last value of a field across multiple stage inputs. + * + * @param fieldName The name of the field to find the last value of. + * @return A new {@link AggregateFunction} representing the last aggregation. + */ + @BetaApi + public static AggregateFunction last(String fieldName) { + return new AggregateFunction("last", fieldName); + } + + /** + * Creates an aggregation that finds the last value of an expression across multiple stage inputs. + * + * @param expression The expression to find the last value of. + * @return A new {@link AggregateFunction} representing the last aggregation. + */ + @BetaApi + public static AggregateFunction last(Expression expression) { + return new AggregateFunction("last", expression); + } + + /** + * Creates an aggregation that collects all values of a field across multiple stage inputs into an + * array. + * + *
If the expression resolves to an absent value, it is converted to `null`. The order of + * elements in the output array is not stable and shouldn't be relied upon. + * + * @param fieldName The name of the field to collect values from. + * @return A new {@link AggregateFunction} representing the array_agg aggregation. + */ + @BetaApi + public static AggregateFunction arrayAgg(String fieldName) { + return new AggregateFunction("array_agg", fieldName); + } + + /** + * Creates an aggregation that collects all values of an expression across multiple stage inputs + * into an array. + * + *
If the expression resolves to an absent value, it is converted to `null`. The order of + * elements in the output array is not stable and shouldn't be relied upon. + * + * @param expression The expression to collect values from. + * @return A new {@link AggregateFunction} representing the array_agg aggregation. + */ + @BetaApi + public static AggregateFunction arrayAgg(Expression expression) { + return new AggregateFunction("array_agg", expression); + } + + /** + * Creates an aggregation that collects all distinct values of a field across multiple stage + * inputs into an array. + * + *
If the expression resolves to an absent value, it is converted to `null`. The order of + * elements in the output array is not stable and shouldn't be relied upon. + * + * @param fieldName The name of the field to collect values from. + * @return A new {@link AggregateFunction} representing the array_agg_distinct aggregation. + */ + @BetaApi + public static AggregateFunction arrayAggDistinct(String fieldName) { + return new AggregateFunction("array_agg_distinct", fieldName); + } + + /** + * Creates an aggregation that collects all distinct values of an expression across multiple stage + * inputs into an array. + * + *
If the expression resolves to an absent value, it is converted to `null`. The order of + * elements in the output array is not stable and shouldn't be relied upon. + * + * @param expression The expression to collect values from. + * @return A new {@link AggregateFunction} representing the array_agg_distinct aggregation. + */ + @BetaApi + public static AggregateFunction arrayAggDistinct(Expression expression) { + return new AggregateFunction("array_agg_distinct", expression); + } + /** * Assigns an alias to this aggregate. * diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java index 14f2bd9ab..14c310743 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java @@ -3213,6 +3213,94 @@ public static Expression roundToPrecision(String numericField, Expression decima return roundToPrecision(field(numericField), decimalPlace); } + /** + * Creates an expression that returns a random double between 0.0 and 1.0 but not including 1.0. + * + * @return A new {@link Expression} representing a random double result from the rand operation. + */ + @BetaApi + public static Expression rand() { + return new FunctionExpression("rand", ImmutableList.of()); + } + + /** + * Creates an expression that truncates {@code numericExpr} to an integer. + * + * @param numericExpr An expression that returns number when evaluated. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression trunc(Expression numericExpr) { + return new FunctionExpression("trunc", ImmutableList.of(numericExpr)); + } + + /** + * Creates an expression that truncates {@code numericField} to an integer. + * + * @param numericField Name of field that returns number when evaluated. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression trunc(String numericField) { + return trunc(field(numericField)); + } + + /** + * Creates an expression that truncates {@code numericExpr} to {@code decimalPlace} decimal places + * if {@code decimalPlace} is positive, truncates digits to the left of the decimal point if + * {@code decimalPlace} is negative. + * + * @param numericExpr An expression that returns number when evaluated. + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression truncToPrecision(Expression numericExpr, int decimalPlace) { + return new FunctionExpression("trunc", ImmutableList.of(numericExpr, constant(decimalPlace))); + } + + /** + * Creates an expression that truncates {@code numericField} to {@code decimalPlace} decimal + * places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point + * if {@code decimalPlace} is negative. + * + * @param numericField Name of field that returns number when evaluated. + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression truncToPrecision(String numericField, int decimalPlace) { + return truncToPrecision(field(numericField), decimalPlace); + } + + /** + * Creates an expression that truncates {@code numericExpr} to {@code decimalPlace} decimal places + * if {@code decimalPlace} is positive, truncates digits to the left of the decimal point if + * {@code decimalPlace} is negative. + * + * @param numericExpr An expression that returns number when evaluated. + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression truncToPrecision(Expression numericExpr, Expression decimalPlace) { + return new FunctionExpression("trunc", ImmutableList.of(numericExpr, decimalPlace)); + } + + /** + * Creates an expression that truncates {@code numericField} to {@code decimalPlace} decimal + * places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point + * if {@code decimalPlace} is negative. + * + * @param numericField Name of field that returns number when evaluated. + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression truncToPrecision(String numericField, Expression decimalPlace) { + return truncToPrecision(field(numericField), decimalPlace); + } + /** * Creates an expression that returns the smallest integer that isn't less than {@code * numericExpr}. @@ -3686,6 +3774,42 @@ public final Expression roundToPrecision(Expression decimalPlace) { return roundToPrecision(this, decimalPlace); } + /** + * Creates an expression that truncates this numeric expression to an integer. + * + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public final Expression trunc() { + return trunc(this); + } + + /** + * Creates an expression that truncates this numeric expression to {@code decimalPlace} decimal + * places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point + * if {@code decimalPlace} is negative. + * + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public final Expression truncToPrecision(int decimalPlace) { + return truncToPrecision(this, decimalPlace); + } + + /** + * Creates an expression that truncates this numeric expression to {@code decimalPlace} decimal + * places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point + * if {@code decimalPlace} is negative. + * + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public final Expression truncToPrecision(Expression decimalPlace) { + return truncToPrecision(this, decimalPlace); + } + /** * Creates an expression that returns the smallest integer that isn't less than this numeric * expression. @@ -4303,6 +4427,56 @@ public final AggregateFunction countDistinct() { return AggregateFunction.countDistinct(this); } + /** + * Creates an aggregation that finds the first value of this expression across multiple stage + * inputs. + * + * @return A new {@link AggregateFunction} representing the first aggregation. + */ + @BetaApi + public final AggregateFunction first() { + return AggregateFunction.first(this); + } + + /** + * Creates an aggregation that finds the last value of this expression across multiple stage + * inputs. + * + * @return A new {@link AggregateFunction} representing the last aggregation. + */ + @BetaApi + public final AggregateFunction last() { + return AggregateFunction.last(this); + } + + /** + * Creates an aggregation that collects all values of this expression across multiple stage inputs + * into an array. + * + *
If the expression resolves to an absent value, it is converted to `null`. The order of + * elements in the output array is not stable and shouldn't be relied upon. + * + * @return A new {@link AggregateFunction} representing the array_agg aggregation. + */ + @BetaApi + public final AggregateFunction arrayAgg() { + return AggregateFunction.arrayAgg(this); + } + + /** + * Creates an aggregation that collects all distinct values of this expression across multiple + * stage inputs into an array. + * + *
If the expression resolves to an absent value, it is converted to `null`. The order of
+ * elements in the output array is not stable and shouldn't be relied upon.
+ *
+ * @return A new {@link AggregateFunction} representing the array_agg_distinct aggregation.
+ */
+ @BetaApi
+ public final AggregateFunction arrayAggDistinct() {
+ return AggregateFunction.arrayAggDistinct(this);
+ }
+
/**
* Create an {@link Ordering} that sorts documents in ascending order based on value of this
* expression
diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java
index 5f810332f..8dc00b03f 100644
--- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java
+++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java
@@ -19,10 +19,14 @@
import static com.google.cloud.firestore.FieldValue.vector;
import static com.google.cloud.firestore.it.ITQueryTest.map;
import static com.google.cloud.firestore.it.TestHelper.isRunningAgainstFirestoreEmulator;
+import static com.google.cloud.firestore.pipeline.expressions.AggregateFunction.arrayAgg;
+import static com.google.cloud.firestore.pipeline.expressions.AggregateFunction.arrayAggDistinct;
import static com.google.cloud.firestore.pipeline.expressions.AggregateFunction.count;
import static com.google.cloud.firestore.pipeline.expressions.AggregateFunction.countAll;
import static com.google.cloud.firestore.pipeline.expressions.AggregateFunction.countDistinct;
import static com.google.cloud.firestore.pipeline.expressions.AggregateFunction.countIf;
+import static com.google.cloud.firestore.pipeline.expressions.AggregateFunction.first;
+import static com.google.cloud.firestore.pipeline.expressions.AggregateFunction.last;
import static com.google.cloud.firestore.pipeline.expressions.AggregateFunction.sum;
import static com.google.cloud.firestore.pipeline.expressions.Expression.add;
import static com.google.cloud.firestore.pipeline.expressions.Expression.and;
@@ -56,6 +60,7 @@
import static com.google.cloud.firestore.pipeline.expressions.Expression.nullValue;
import static com.google.cloud.firestore.pipeline.expressions.Expression.or;
import static com.google.cloud.firestore.pipeline.expressions.Expression.pow;
+import static com.google.cloud.firestore.pipeline.expressions.Expression.rand;
import static com.google.cloud.firestore.pipeline.expressions.Expression.regexMatch;
import static com.google.cloud.firestore.pipeline.expressions.Expression.round;
import static com.google.cloud.firestore.pipeline.expressions.Expression.sqrt;
@@ -67,6 +72,8 @@
import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixMicros;
import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixMillis;
import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixSeconds;
+import static com.google.cloud.firestore.pipeline.expressions.Expression.trunc;
+import static com.google.cloud.firestore.pipeline.expressions.Expression.truncToPrecision;
import static com.google.cloud.firestore.pipeline.expressions.Expression.unixMicrosToTimestamp;
import static com.google.cloud.firestore.pipeline.expressions.Expression.unixMillisToTimestamp;
import static com.google.cloud.firestore.pipeline.expressions.Expression.unixSecondsToTimestamp;
@@ -579,6 +586,132 @@ public void testMinMax() throws Exception {
"min_published", 1813L)));
}
+ @Test
+ public void testFirstAndLastAccumulators() throws Exception {
+ List