Skip to content

Commit 47a947e

Browse files
authored
feat(firestore): add support for isType pipeline expression (#7985)
Adds support for `isType` pipeline expression. Ported from: googleapis/java-firestore#2329
1 parent ebfa5e4 commit 47a947e

5 files changed

Lines changed: 148 additions & 1 deletion

File tree

firebase-firestore/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
[#7893](https://github.com/firebase/firebase-android-sdk/pull/7893)
1414
- [feature] Added support for `rand` and `trunc` Pipeline expressions.
1515
[#7886](https://github.com/firebase/firebase-android-sdk/pull/7886)
16+
- [feature] Added support for `isType` Pipeline expression.
17+
[#7985](https://github.com/firebase/firebase-android-sdk/pull/7985)
1618
- [feature] Add public preview support for full-text search and geo search.
1719
[#7949](https://github.com/firebase/firebase-android-sdk/pull/7949)
1820
- [feature] Added support for `ltrim`, `rtrim`, `stringIndexOf`, `stringRepeat`, `stringReplaceOne`, and `stringReplaceAll` Pipeline expressions.

firebase-firestore/api.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,9 @@ package com.google.firebase.firestore.pipeline {
10921092
method public static final com.google.firebase.firestore.pipeline.BooleanExpression isAbsent(String fieldName);
10931093
method public final com.google.firebase.firestore.pipeline.BooleanExpression isError();
10941094
method public static final com.google.firebase.firestore.pipeline.BooleanExpression isError(com.google.firebase.firestore.pipeline.Expression expr);
1095+
method public static final com.google.firebase.firestore.pipeline.BooleanExpression isType(com.google.firebase.firestore.pipeline.Expression expr, String type);
1096+
method public final com.google.firebase.firestore.pipeline.BooleanExpression isType(String type);
1097+
method public static final com.google.firebase.firestore.pipeline.BooleanExpression isType(String fieldName, String type);
10951098
method public final com.google.firebase.firestore.pipeline.Expression join(com.google.firebase.firestore.pipeline.Expression delimiterExpression);
10961099
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);
10971100
method public static final com.google.firebase.firestore.pipeline.Expression join(com.google.firebase.firestore.pipeline.Expression arrayExpression, String delimiter);
@@ -1627,6 +1630,8 @@ package com.google.firebase.firestore.pipeline {
16271630
method public com.google.firebase.firestore.pipeline.BooleanExpression isAbsent(com.google.firebase.firestore.pipeline.Expression value);
16281631
method public com.google.firebase.firestore.pipeline.BooleanExpression isAbsent(String fieldName);
16291632
method public com.google.firebase.firestore.pipeline.BooleanExpression isError(com.google.firebase.firestore.pipeline.Expression expr);
1633+
method public com.google.firebase.firestore.pipeline.BooleanExpression isType(com.google.firebase.firestore.pipeline.Expression expr, String type);
1634+
method public com.google.firebase.firestore.pipeline.BooleanExpression isType(String fieldName, String type);
16301635
method public com.google.firebase.firestore.pipeline.Expression join(com.google.firebase.firestore.pipeline.Expression arrayExpression, com.google.firebase.firestore.pipeline.Expression delimiterExpression);
16311636
method public com.google.firebase.firestore.pipeline.Expression join(com.google.firebase.firestore.pipeline.Expression arrayExpression, String delimiter);
16321637
method public com.google.firebase.firestore.pipeline.Expression join(String arrayFieldName, com.google.firebase.firestore.pipeline.Expression delimiterExpression);

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineTest.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3525,6 +3525,84 @@ public void testTypeFunction() {
35253525
assertThat(result.get("nestedFieldType")).isEqualTo("map");
35263526
}
35273527

3528+
@Test
3529+
public void testIsType() {
3530+
assumeFalse(
3531+
"Type expressions are not supported against the emulator.", isRunningAgainstEmulator());
3532+
3533+
Task<Pipeline.Snapshot> execute =
3534+
firestore
3535+
.pipeline()
3536+
.collection(randomCol)
3537+
.replaceWith(
3538+
map(
3539+
mapOfEntries(
3540+
entry("int", 1),
3541+
entry("float", 1.1),
3542+
entry("str", "a string"),
3543+
entry("bool", true),
3544+
entry("null", null),
3545+
entry("geoPoint", new GeoPoint(0.1, 0.2)),
3546+
entry("timestamp", new Timestamp(123456, 0)),
3547+
entry(
3548+
"bytes",
3549+
com.google.firebase.firestore.Blob.fromBytes(new byte[] {1, 2, 3})),
3550+
entry("docRef", randomCol.document("bar")),
3551+
entry("vector", FieldValue.vector(new double[] {1.0, 2.0, 3.0})),
3552+
entry(
3553+
"map",
3554+
map(mapOfEntries(entry("numberK", 1), entry("stringK", "a string")))),
3555+
entry("array", array(1, 2, true)))))
3556+
.select(
3557+
Expression.isType("int", "int64").alias("isInt64"),
3558+
Expression.isType("int", "number").alias("isInt64IsNumber"),
3559+
Expression.isType("int", "decimal128").alias("isInt64IsDecimal128"),
3560+
Expression.isType("float", "float64").alias("isFloat64"),
3561+
Expression.isType("float", "number").alias("isFloat64IsNumber"),
3562+
Expression.isType("float", "decimal128").alias("isFloat64IsDecimal128"),
3563+
Expression.isType("str", "string").alias("isStr"),
3564+
Expression.isType("str", "int64").alias("isStrNum"),
3565+
Expression.isType("int", "string").alias("isNumStr"),
3566+
Expression.isType("bool", "boolean").alias("isBool"),
3567+
Expression.isType("null", "null").alias("isNull"),
3568+
Expression.isType("geoPoint", "geo_point").alias("isGeoPoint"),
3569+
Expression.isType("timestamp", "timestamp").alias("isTimestamp"),
3570+
Expression.isType("bytes", "bytes").alias("isBytes"),
3571+
Expression.isType("docRef", "reference").alias("isDocRef"),
3572+
Expression.isType("vector", "vector").alias("isVector"),
3573+
Expression.isType("map", "map").alias("isMap"),
3574+
Expression.isType("array", "array").alias("isArray"),
3575+
Expression.isType(constant(1), "int64").alias("exprIsInt64"),
3576+
field("int").isType("int64").alias("staticIsInt64"))
3577+
.limit(1)
3578+
.execute();
3579+
3580+
assertThat(waitFor(execute).getResults())
3581+
.comparingElementsUsing(DATA_CORRESPONDENCE)
3582+
.containsExactly(
3583+
mapOfEntries(
3584+
entry("isInt64", true),
3585+
entry("isInt64IsNumber", true),
3586+
entry("isInt64IsDecimal128", false),
3587+
entry("isFloat64", true),
3588+
entry("isFloat64IsNumber", true),
3589+
entry("isFloat64IsDecimal128", false),
3590+
entry("isStr", true),
3591+
entry("isStrNum", false),
3592+
entry("isNumStr", false),
3593+
entry("isBool", true),
3594+
entry("isNull", true),
3595+
entry("isGeoPoint", true),
3596+
entry("isTimestamp", true),
3597+
entry("isBytes", true),
3598+
entry("isDocRef", true),
3599+
entry("isVector", true),
3600+
entry("isMap", true),
3601+
entry("isArray", true),
3602+
entry("exprIsInt64", true),
3603+
entry("staticIsInt64", true)));
3604+
}
3605+
35283606
@Test
35293607
public void testVectorLength() {
35303608
Task<Pipeline.Snapshot> execute =

firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/FunctionRegistry.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ internal object FunctionRegistry {
118118
"cosine_distance" to notImplemented,
119119
"dot_product" to notImplemented,
120120
"timestamp_trunc" to notImplemented,
121+
"type" to notImplemented,
122+
"is_type" to notImplemented,
121123
"substring" to notImplemented,
122124
"string_repeat" to notImplemented,
123125
"string_replace_all" to notImplemented,

firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/expressions.kt

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1940,6 +1940,48 @@ abstract class Expression internal constructor() {
19401940
@JvmStatic
19411941
fun type(fieldName: String): Expression = FunctionExpression("type", notImplemented, fieldName)
19421942

1943+
/**
1944+
* Creates an expression that checks if the result of an expression is of the given type.
1945+
*
1946+
* Supported values for `type` are: "null", "array", "boolean", "bytes", "timestamp",
1947+
* "geo_point", "number", "int32", "int64", "float64", "decimal128", "map", "reference",
1948+
* "string", "vector", "max_key", "min_key", "object_id", "regex", and "request_timestamp".
1949+
*
1950+
* ```kotlin
1951+
* // Check if the 'age' field is an integer
1952+
* isType(field("age"), "int64")
1953+
* ```
1954+
*
1955+
* @param expr The expression to check the type of.
1956+
* @param type The type to check for.
1957+
* @return A new [BooleanExpression] that evaluates to true if the expression's result is of the
1958+
* given type, false otherwise.
1959+
*/
1960+
@JvmStatic
1961+
fun isType(expr: Expression, type: String): BooleanExpression =
1962+
BooleanFunctionExpression("is_type", notImplemented, expr, constant(type))
1963+
1964+
/**
1965+
* Creates an expression that checks if the value of a field is of the given type.
1966+
*
1967+
* Supported values for `type` are: "null", "array", "boolean", "bytes", "timestamp",
1968+
* "geo_point", "number", "int32", "int64", "float64", "decimal128", "map", "reference",
1969+
* "string", "vector", "max_key", "min_key", "object_id", "regex", and "request_timestamp".
1970+
*
1971+
* ```kotlin
1972+
* // Check if the 'age' field is an integer
1973+
* isType("age", "int64")
1974+
* ```
1975+
*
1976+
* @param fieldName The name of the field to check the type of.
1977+
* @param type The type to check for.
1978+
* @return A new [BooleanExpression] that evaluates to true if the expression's result is of the
1979+
* given type, false otherwise.
1980+
*/
1981+
@JvmStatic
1982+
fun isType(fieldName: String, type: String): BooleanExpression =
1983+
BooleanFunctionExpression("is_type", notImplemented, fieldName, constant(type))
1984+
19431985
/**
19441986
* Creates an expression that calculates the length of a string, array, map, vector, or blob
19451987
* expression.
@@ -8329,7 +8371,25 @@ abstract class Expression internal constructor() {
83298371
*
83308372
* @return A new [Expression] representing the type operation.
83318373
*/
8332-
fun type(): Expression = type(this)
8374+
fun type(): Expression = Companion.type(this)
8375+
8376+
/**
8377+
* Creates an expression that checks if the result of this expression is of the given type.
8378+
*
8379+
* Supported values for `type` are: "null", "array", "boolean", "bytes", "timestamp", "geo_point",
8380+
* "number", "int32", "int64", "float64", "decimal128", "map", "reference", "string", "vector",
8381+
* "max_key", "min_key", "object_id", "regex", and "request_timestamp".
8382+
*
8383+
* ```kotlin
8384+
* // Check if the 'age' field is an integer
8385+
* field("age").isType("int64")
8386+
* ```
8387+
*
8388+
* @param type The type to check for.
8389+
* @return A new [BooleanExpression] that evaluates to true if the expression's result is of the
8390+
* given type, false otherwise.
8391+
*/
8392+
fun isType(type: String): BooleanExpression = Companion.isType(this, type)
83338393

83348394
/**
83358395
* Creates an expression that splits this string or blob expression by a delimiter.

0 commit comments

Comments
 (0)