Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -13,6 +13,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)
- [feature] Add public preview support for full-text search and geo search.
[#7949](https://github.com/firebase/firebase-android-sdk/pull/7949)
- [feature] Added support for `ltrim`, `rtrim`, `stringIndexOf`, `stringRepeat`, `stringReplaceOne`, and `stringReplaceAll` Pipeline expressions.
Expand Down
5 changes: 5 additions & 0 deletions firebase-firestore/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,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 @@ -1627,6 +1630,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
Original file line number Diff line number Diff line change
Expand Up @@ -3525,6 +3525,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 @@ -118,6 +118,8 @@ internal object FunctionRegistry {
"cosine_distance" to notImplemented,
"dot_product" to notImplemented,
"timestamp_trunc" to notImplemented,
"type" to notImplemented,
"is_type" to notImplemented,
"substring" to notImplemented,
"string_repeat" to notImplemented,
"string_replace_all" to notImplemented,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1940,6 +1940,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 @@ -8329,7 +8371,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