Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions firebase-firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
[#7893](https://github.com/firebase/firebase-android-sdk/pull/7893)
- [feature] Added support for `rand` and `trunc` Pipeline expressions.
[#7886](https://github.com/firebase/firebase-android-sdk/pull/7886)
- [feature] Added support for `isType` Pipeline expression.
[#7985](https://github.com/firebase/firebase-android-sdk/pull/7985)

# 26.1.2

Expand Down
5 changes: 5 additions & 0 deletions firebase-firestore/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,9 @@ package com.google.firebase.firestore.pipeline {
method public static final com.google.firebase.firestore.pipeline.BooleanExpression isAbsent(String fieldName);
method public final com.google.firebase.firestore.pipeline.BooleanExpression isError();
method public static final com.google.firebase.firestore.pipeline.BooleanExpression isError(com.google.firebase.firestore.pipeline.Expression expr);
method public static final com.google.firebase.firestore.pipeline.BooleanExpression isType(com.google.firebase.firestore.pipeline.Expression expr, String type);
method public final com.google.firebase.firestore.pipeline.BooleanExpression isType(String type);
method public static final com.google.firebase.firestore.pipeline.BooleanExpression isType(String fieldName, String type);
method public final com.google.firebase.firestore.pipeline.Expression join(com.google.firebase.firestore.pipeline.Expression delimiterExpression);
method public static final com.google.firebase.firestore.pipeline.Expression join(com.google.firebase.firestore.pipeline.Expression arrayExpression, com.google.firebase.firestore.pipeline.Expression delimiterExpression);
method public static final com.google.firebase.firestore.pipeline.Expression join(com.google.firebase.firestore.pipeline.Expression arrayExpression, String delimiter);
Expand Down Expand Up @@ -1489,6 +1492,8 @@ package com.google.firebase.firestore.pipeline {
method public com.google.firebase.firestore.pipeline.BooleanExpression isAbsent(com.google.firebase.firestore.pipeline.Expression value);
method public com.google.firebase.firestore.pipeline.BooleanExpression isAbsent(String fieldName);
method public com.google.firebase.firestore.pipeline.BooleanExpression isError(com.google.firebase.firestore.pipeline.Expression expr);
method public com.google.firebase.firestore.pipeline.BooleanExpression isType(com.google.firebase.firestore.pipeline.Expression expr, String type);
method public com.google.firebase.firestore.pipeline.BooleanExpression isType(String fieldName, String type);
method public com.google.firebase.firestore.pipeline.Expression join(com.google.firebase.firestore.pipeline.Expression arrayExpression, com.google.firebase.firestore.pipeline.Expression delimiterExpression);
method public com.google.firebase.firestore.pipeline.Expression join(com.google.firebase.firestore.pipeline.Expression arrayExpression, String delimiter);
method public com.google.firebase.firestore.pipeline.Expression join(String arrayFieldName, com.google.firebase.firestore.pipeline.Expression delimiterExpression);
Expand Down
2 changes: 1 addition & 1 deletion firebase-firestore/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version=26.1.3
version=26.2.0
Comment thread
dlarocque marked this conversation as resolved.
latestReleasedVersion=26.1.2
Original file line number Diff line number Diff line change
Expand Up @@ -2970,6 +2970,84 @@ public void testTypeFunction() {
assertThat(result.get("nestedFieldType")).isEqualTo("map");
}

@Test
public void testIsType() {
assumeFalse(
"Type expressions are not supported against the emulator.", isRunningAgainstEmulator());

Task<Pipeline.Snapshot> execute =
firestore
.pipeline()
.collection(randomCol)
.replaceWith(
map(
mapOfEntries(
entry("int", 1),
entry("float", 1.1),
entry("str", "a string"),
entry("bool", true),
entry("null", null),
entry("geoPoint", new GeoPoint(0.1, 0.2)),
entry("timestamp", new Timestamp(123456, 0)),
entry(
"bytes",
com.google.firebase.firestore.Blob.fromBytes(new byte[] {1, 2, 3})),
entry("docRef", randomCol.document("bar")),
entry("vector", FieldValue.vector(new double[] {1.0, 2.0, 3.0})),
entry(
"map",
map(mapOfEntries(entry("numberK", 1), entry("stringK", "a string")))),
entry("array", array(1, 2, true)))))
.select(
Expression.isType("int", "int64").alias("isInt64"),
Expression.isType("int", "number").alias("isInt64IsNumber"),
Expression.isType("int", "decimal128").alias("isInt64IsDecimal128"),
Expression.isType("float", "float64").alias("isFloat64"),
Expression.isType("float", "number").alias("isFloat64IsNumber"),
Expression.isType("float", "decimal128").alias("isFloat64IsDecimal128"),
Expression.isType("str", "string").alias("isStr"),
Expression.isType("str", "int64").alias("isStrNum"),
Expression.isType("int", "string").alias("isNumStr"),
Expression.isType("bool", "boolean").alias("isBool"),
Expression.isType("null", "null").alias("isNull"),
Expression.isType("geoPoint", "geo_point").alias("isGeoPoint"),
Expression.isType("timestamp", "timestamp").alias("isTimestamp"),
Expression.isType("bytes", "bytes").alias("isBytes"),
Expression.isType("docRef", "reference").alias("isDocRef"),
Expression.isType("vector", "vector").alias("isVector"),
Expression.isType("map", "map").alias("isMap"),
Expression.isType("array", "array").alias("isArray"),
Expression.isType(constant(1), "int64").alias("exprIsInt64"),
field("int").isType("int64").alias("staticIsInt64"))
.limit(1)
.execute();

assertThat(waitFor(execute).getResults())
.comparingElementsUsing(DATA_CORRESPONDENCE)
.containsExactly(
mapOfEntries(
entry("isInt64", true),
entry("isInt64IsNumber", true),
entry("isInt64IsDecimal128", false),
entry("isFloat64", true),
entry("isFloat64IsNumber", true),
entry("isFloat64IsDecimal128", false),
entry("isStr", true),
entry("isStrNum", false),
entry("isNumStr", false),
entry("isBool", true),
entry("isNull", true),
entry("isGeoPoint", true),
entry("isTimestamp", true),
entry("isBytes", true),
entry("isDocRef", true),
entry("isVector", true),
entry("isMap", true),
entry("isArray", true),
entry("exprIsInt64", true),
entry("staticIsInt64", true)));
}

@Test
public void testVectorLength() {
Task<Pipeline.Snapshot> execute =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ internal object FunctionRegistry {
"split" to evaluateSplit,
"substring" to evaluateSubstring,
"ltrim" to evaluateLTrim,
"rtrim" to evaluateRTrim
"rtrim" to evaluateRTrim,
"type" to notImplemented,
"is_type" to notImplemented
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -1936,6 +1936,48 @@ abstract class Expression internal constructor() {
@JvmStatic
fun type(fieldName: String): Expression = FunctionExpression("type", notImplemented, fieldName)

/**
* Creates an expression that checks if the result of an expression is of the given type.
*
* Supported values for `type` are: "null", "array", "boolean", "bytes", "timestamp",
* "geo_point", "number", "int32", "int64", "float64", "decimal128", "map", "reference",
* "string", "vector", "max_key", "min_key", "object_id", "regex", and "request_timestamp".
Comment thread
dlarocque marked this conversation as resolved.
*
* ```kotlin
* // Check if the 'age' field is an integer
* isType(field("age"), "int64")
* ```
*
* @param expr The expression to check the type of.
* @param type The type to check for.
* @return A new [BooleanExpression] that evaluates to true if the expression's result is of the
* given type, false otherwise.
*/
@JvmStatic
fun isType(expr: Expression, type: String): BooleanExpression =
BooleanFunctionExpression("is_type", notImplemented, expr, constant(type))

/**
* Creates an expression that checks if the value of a field is of the given type.
*
* Supported values for `type` are: "null", "array", "boolean", "bytes", "timestamp",
* "geo_point", "number", "int32", "int64", "float64", "decimal128", "map", "reference",
* "string", "vector", "max_key", "min_key", "object_id", "regex", and "request_timestamp".
*
* ```kotlin
* // Check if the 'age' field is an integer
* isType("age", "int64")
* ```
*
* @param fieldName The name of the field to check the type of.
* @param type The type to check for.
* @return A new [BooleanExpression] that evaluates to true if the expression's result is of the
* given type, false otherwise.
*/
@JvmStatic
fun isType(fieldName: String, type: String): BooleanExpression =
BooleanFunctionExpression("is_type", notImplemented, fieldName, constant(type))

/**
* Creates an expression that calculates the length of a string, array, map, vector, or blob
* expression.
Expand Down Expand Up @@ -6639,7 +6681,25 @@ abstract class Expression internal constructor() {
*
* @return A new [Expression] representing the type operation.
*/
fun type(): Expression = type(this)
fun type(): Expression = Companion.type(this)

/**
* Creates an expression that checks if the result of this expression is of the given type.
*
* Supported values for `type` are: "null", "array", "boolean", "bytes", "timestamp", "geo_point",
* "number", "int32", "int64", "float64", "decimal128", "map", "reference", "string", "vector",
* "max_key", "min_key", "object_id", "regex", and "request_timestamp".
*
* ```kotlin
* // Check if the 'age' field is an integer
* field("age").isType("int64")
* ```
*
* @param type The type to check for.
* @return A new [BooleanExpression] that evaluates to true if the expression's result is of the
* given type, false otherwise.
*/
fun isType(type: String): BooleanExpression = Companion.isType(this, type)

/**
* Creates an expression that splits this string or blob expression by a delimiter.
Expand Down
Loading