Skip to content

Commit d7ac3fe

Browse files
Fixed a race condition in test and remove null / nan related operations (#7741)
## Description This PR introduces the following Beta API changes and related fixes: * **Removed API Methods:** Removes the `isNan`, `isNotNan`, `isNull`, and `isNotNull` pipeline string/number operations. * **Changed `alias` Return Type:** Updates the `alias` method to now return an `AliasedExpression` instead of `Selectable`. * **Changelog Update:** Updates `CHANGELOG.md` to reflect these recent Beta API changes. * **Test Fixes:** Fixes build failures in `QueryToPipelineTest.java` caused by the race condition. --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent d093ee4 commit d7ac3fe

File tree

11 files changed

+69
-455
lines changed

11 files changed

+69
-455
lines changed

firebase-firestore/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
- [feature] Added support for `regexFind` and `regexFindAll` Pipeline expressions.
44
[#7669](https://github.com/firebase/firebase-android-sdk/pull/7669)
5+
- [changed] Updated `Expression.alias()` to return `AliasedExpression`.
6+
- [removed] Removed `isNan`, `isNotNan`, `isNull`, and `isNotNull` factory methods from `Expression`.
7+
Use `equal(Double.NaN)`, `notEqual(Double.NaN)`, `equal(nullValue())`, and `notEqual(nullValue())`
8+
respectively.
59

610
# 26.1.0
711

firebase-firestore/api.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ package com.google.firebase.firestore.pipeline {
790790
method public final com.google.firebase.firestore.pipeline.Expression add(Number second);
791791
method public static final com.google.firebase.firestore.pipeline.Expression add(String numericFieldName, com.google.firebase.firestore.pipeline.Expression second);
792792
method public static final com.google.firebase.firestore.pipeline.Expression add(String numericFieldName, Number second);
793-
method public com.google.firebase.firestore.pipeline.Selectable alias(String alias);
793+
method public com.google.firebase.firestore.pipeline.AliasedExpression alias(String alias);
794794
method public static final com.google.firebase.firestore.pipeline.BooleanExpression and(com.google.firebase.firestore.pipeline.BooleanExpression condition, com.google.firebase.firestore.pipeline.BooleanExpression... conditions);
795795
method public static final com.google.firebase.firestore.pipeline.Expression array(java.lang.Object?... elements);
796796
method public static final com.google.firebase.firestore.pipeline.Expression array(java.util.List<? extends java.lang.Object?> elements);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ public void testCanQueryByDocumentIdUsingRefs() {
352352
public void testCanQueryWithAndWithoutDocumentKey() {
353353
CollectionReference collection = testCollection();
354354
FirebaseFirestore db = collection.firestore;
355-
collection.add(map());
355+
waitFor(collection.add(map()));
356356
Task<Pipeline.Snapshot> query1 =
357357
db.pipeline()
358358
.createFrom(collection.orderBy(FieldPath.documentId(), Direction.ASCENDING))

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/RealtimePipelineTest.kt

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,16 @@ import com.google.firebase.firestore.pipeline.Expression.Companion.exp
3636
import com.google.firebase.firestore.pipeline.Expression.Companion.field
3737
import com.google.firebase.firestore.pipeline.Expression.Companion.floor
3838
import com.google.firebase.firestore.pipeline.Expression.Companion.isAbsent
39-
import com.google.firebase.firestore.pipeline.Expression.Companion.isNan
40-
import com.google.firebase.firestore.pipeline.Expression.Companion.isNotNan
41-
import com.google.firebase.firestore.pipeline.Expression.Companion.isNotNull
42-
import com.google.firebase.firestore.pipeline.Expression.Companion.isNull
4339
import com.google.firebase.firestore.pipeline.Expression.Companion.like
4440
import com.google.firebase.firestore.pipeline.Expression.Companion.ln
4541
import com.google.firebase.firestore.pipeline.Expression.Companion.log
4642
import com.google.firebase.firestore.pipeline.Expression.Companion.log10
4743
import com.google.firebase.firestore.pipeline.Expression.Companion.mod
4844
import com.google.firebase.firestore.pipeline.Expression.Companion.multiply
4945
import com.google.firebase.firestore.pipeline.Expression.Companion.not
46+
import com.google.firebase.firestore.pipeline.Expression.Companion.notEqual
5047
import com.google.firebase.firestore.pipeline.Expression.Companion.notEqualAny
48+
import com.google.firebase.firestore.pipeline.Expression.Companion.nullValue
5149
import com.google.firebase.firestore.pipeline.Expression.Companion.or
5250
import com.google.firebase.firestore.pipeline.Expression.Companion.pow
5351
import com.google.firebase.firestore.pipeline.Expression.Companion.regexContains
@@ -573,7 +571,8 @@ class RealtimePipelineTest {
573571

574572
collRef.document("book1").update("title", FieldValue.serverTimestamp())
575573

576-
val pipeline = db.realtimePipeline().collection(collRef.path).where(field("title").isNull())
574+
val pipeline =
575+
db.realtimePipeline().collection(collRef.path).where(field("title").equal(nullValue()))
577576

578577
val channel = Channel<RealtimePipeline.Snapshot>(Channel.UNLIMITED)
579578
val job = launch { pipeline.snapshots().collect { snapshot -> channel.send(snapshot) } }
@@ -593,7 +592,11 @@ class RealtimePipelineTest {
593592
collRef.document("book1").update("title", FieldValue.serverTimestamp())
594593

595594
val pipeline =
596-
db.realtimePipeline().collection(collRef.path).where(field("title").isNotNull()).limit(1)
595+
db
596+
.realtimePipeline()
597+
.collection(collRef.path)
598+
.where(field("title").notEqual(nullValue()))
599+
.limit(1)
597600

598601
val channel1 = Channel<RealtimePipeline.Snapshot>(Channel.UNLIMITED)
599602
val job1 = launch {
@@ -942,7 +945,8 @@ class RealtimePipelineTest {
942945
collRef.document("book1").update("rating", Double.NaN).await()
943946

944947
// Test isNan
945-
val pipelineIsNan = db.realtimePipeline().collection(collRef.path).where(isNan("rating"))
948+
val pipelineIsNan =
949+
db.realtimePipeline().collection(collRef.path).where(field("rating").equal(Double.NaN))
946950

947951
val channelIsNan = Channel<RealtimePipeline.Snapshot>(Channel.UNLIMITED)
948952
val jobIsNan = launch {
@@ -956,7 +960,8 @@ class RealtimePipelineTest {
956960
jobIsNan.cancel()
957961

958962
// Test isNotNan
959-
val pipelineIsNotNan = db.realtimePipeline().collection(collRef.path).where(isNotNan("rating"))
963+
val pipelineIsNotNan =
964+
db.realtimePipeline().collection(collRef.path).where(field("rating").notEqual(Double.NaN))
960965

961966
val channelIsNotNan = Channel<RealtimePipeline.Snapshot>(Channel.UNLIMITED)
962967
val jobIsNotNan = launch {
@@ -973,7 +978,8 @@ class RealtimePipelineTest {
973978
collRef.document("book1").update("rating", null).await()
974979

975980
// Test isNull
976-
val pipelineIsNull = db.realtimePipeline().collection(collRef.path).where(isNull("rating"))
981+
val pipelineIsNull =
982+
db.realtimePipeline().collection(collRef.path).where(field("rating").equal(nullValue()))
977983

978984
val channelIsNull = Channel<RealtimePipeline.Snapshot>(Channel.UNLIMITED)
979985
val jobIsNull = launch {
@@ -988,7 +994,7 @@ class RealtimePipelineTest {
988994

989995
// Test isNotNull
990996
val pipelineIsNotNull =
991-
db.realtimePipeline().collection(collRef.path).where(isNotNull("rating"))
997+
db.realtimePipeline().collection(collRef.path).where(field("rating").notEqual(nullValue()))
992998

993999
val channelIsNotNull = Channel<RealtimePipeline.Snapshot>(Channel.UNLIMITED)
9941000
val jobIsNotNull = launch {

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

Lines changed: 3 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,126 +1755,6 @@ abstract class Expression internal constructor() {
17551755
fun isAbsent(fieldName: String): BooleanExpression =
17561756
BooleanFunctionExpression("is_absent", evaluateIsAbsent, fieldName)
17571757

1758-
/**
1759-
* Creates an expression that checks if an expression evaluates to 'NaN' (Not a Number).
1760-
*
1761-
* ```kotlin
1762-
* // Check if the result of a calculation is NaN
1763-
* isNan(divide("value", 0))
1764-
* ```
1765-
*
1766-
* @param expr The expression to check.
1767-
* @return A new [BooleanExpression] representing the isNan operation.
1768-
*/
1769-
@JvmStatic
1770-
internal fun isNan(expr: Expression): BooleanExpression =
1771-
BooleanFunctionExpression("is_nan", evaluateIsNaN, expr)
1772-
1773-
/**
1774-
* Creates an expression that checks if the field's value evaluates to 'NaN' (Not a Number).
1775-
*
1776-
* ```kotlin
1777-
* // Check if the value of a field is NaN
1778-
* isNan("value")
1779-
* ```
1780-
*
1781-
* @param fieldName The field to check.
1782-
* @return A new [BooleanExpression] representing the isNan operation.
1783-
*/
1784-
@JvmStatic
1785-
internal fun isNan(fieldName: String): BooleanExpression =
1786-
BooleanFunctionExpression("is_nan", evaluateIsNaN, fieldName)
1787-
1788-
/**
1789-
* Creates an expression that checks if the results of [expr] is NOT 'NaN' (Not a Number).
1790-
*
1791-
* ```kotlin
1792-
* // Check if the result of a calculation is NOT NaN
1793-
* isNotNan(divide("value", 0))
1794-
* ```
1795-
*
1796-
* @param expr The expression to check.
1797-
* @return A new [BooleanExpression] representing the isNotNan operation.
1798-
*/
1799-
@JvmStatic
1800-
internal fun isNotNan(expr: Expression): BooleanExpression =
1801-
BooleanFunctionExpression("is_not_nan", evaluateIsNotNaN, expr)
1802-
1803-
/**
1804-
* Creates an expression that checks if the field's value is NOT 'NaN' (Not a Number).
1805-
*
1806-
* ```kotlin
1807-
* // Check if the value of a field is NOT NaN
1808-
* isNotNan("value")
1809-
* ```
1810-
*
1811-
* @param fieldName The field to check.
1812-
* @return A new [BooleanExpression] representing the isNotNan operation.
1813-
*/
1814-
@JvmStatic
1815-
internal fun isNotNan(fieldName: String): BooleanExpression =
1816-
BooleanFunctionExpression("is_not_nan", evaluateIsNotNaN, fieldName)
1817-
1818-
/**
1819-
* Creates an expression that checks if the result of [expr] is null.
1820-
*
1821-
* ```kotlin
1822-
* // Check if the value of the 'name' field is null
1823-
* isNull("name")
1824-
* ```
1825-
*
1826-
* @param expr The expression to check.
1827-
* @return A new [BooleanExpression] representing the isNull operation.
1828-
*/
1829-
@JvmStatic
1830-
internal fun isNull(expr: Expression): BooleanExpression =
1831-
BooleanFunctionExpression("is_null", evaluateIsNull, expr)
1832-
1833-
/**
1834-
* Creates an expression that checks if the value of a field is null.
1835-
*
1836-
* ```kotlin
1837-
* // Check if the value of the 'name' field is null
1838-
* isNull("name")
1839-
* ```
1840-
*
1841-
* @param fieldName The field to check.
1842-
* @return A new [BooleanExpression] representing the isNull operation.
1843-
*/
1844-
@JvmStatic
1845-
internal fun isNull(fieldName: String): BooleanExpression =
1846-
BooleanFunctionExpression("is_null", evaluateIsNull, fieldName)
1847-
1848-
/**
1849-
* Creates an expression that checks if the result of [expr] is not null.
1850-
*
1851-
* ```kotlin
1852-
* // Check if the value of the 'name' field is not null
1853-
* isNotNull(field("name"))
1854-
* ```
1855-
*
1856-
* @param expr The expression to check.
1857-
* @return A new [BooleanExpression] representing the isNotNull operation.
1858-
*/
1859-
@JvmStatic
1860-
internal fun isNotNull(expr: Expression): BooleanExpression =
1861-
BooleanFunctionExpression("is_not_null", evaluateIsNotNull, expr)
1862-
1863-
/**
1864-
* Creates an expression that checks if the value of a field is not null.
1865-
*
1866-
* ```kotlin
1867-
* // Check if the value of the 'name' field is not null
1868-
* isNotNull("name")
1869-
* ```
1870-
*
1871-
* @param fieldName The field to check.
1872-
* @return A new [BooleanExpression] representing the isNotNull operation.
1873-
*/
1874-
@JvmStatic
1875-
internal fun isNotNull(fieldName: String): BooleanExpression =
1876-
BooleanFunctionExpression("is_not_null", evaluateIsNotNull, fieldName)
1877-
18781758
/**
18791759
* Creates an expression that returns a string indicating the type of the value this expression
18801760
* evaluates to.
@@ -5554,10 +5434,10 @@ abstract class Expression internal constructor() {
55545434
* to calculated values.
55555435
*
55565436
* @param alias The alias to assign to this expression.
5557-
* @return A new [Selectable] (typically an [AliasedExpression]) that wraps this expression and
5558-
* associates it with the provided alias.
5437+
* @return A [AliasedExpression] that wraps this expression and associates it with the provided
5438+
* alias.
55595439
*/
5560-
open fun alias(alias: String): Selectable = AliasedExpression(alias, this)
5440+
open fun alias(alias: String): AliasedExpression = AliasedExpression(alias, this)
55615441

55625442
/**
55635443
* Creates an expression that returns the document ID from this path expression.
@@ -5951,55 +5831,6 @@ abstract class Expression internal constructor() {
59515831
*/
59525832
fun isAbsent(): BooleanExpression = Companion.isAbsent(this)
59535833

5954-
/**
5955-
* Creates an expression that checks if this expression evaluates to 'NaN' (Not a Number).
5956-
*
5957-
* ```kotlin
5958-
* // Check if the result of a calculation is NaN
5959-
* divide("value", 0).isNan()
5960-
* ```
5961-
*
5962-
* @return A new [BooleanExpression] representing the isNan operation.
5963-
*/
5964-
internal fun isNan(): BooleanExpression = Companion.isNan(this)
5965-
5966-
/**
5967-
* Creates an expression that checks if the results of this expression is NOT 'NaN' (Not a
5968-
* Number).
5969-
*
5970-
* ```kotlin
5971-
* // Check if the result of a calculation is NOT NaN
5972-
* divide("value", 0).isNotNan()
5973-
* ```
5974-
*
5975-
* @return A new [BooleanExpression] representing the isNotNan operation.
5976-
*/
5977-
internal fun isNotNan(): BooleanExpression = Companion.isNotNan(this)
5978-
5979-
/**
5980-
* Creates an expression that checks if the result of this expression is null.
5981-
*
5982-
* ```kotlin
5983-
* // Check if the value of the 'name' field is null
5984-
* field("name").isNull()
5985-
* ```
5986-
*
5987-
* @return A new [BooleanExpression] representing the isNull operation.
5988-
*/
5989-
internal fun isNull(): BooleanExpression = Companion.isNull(this)
5990-
5991-
/**
5992-
* Creates an expression that checks if the result of this expression is not null.
5993-
*
5994-
* ```kotlin
5995-
* // Check if the value of the 'name' field is not null
5996-
* field("name").isNotNull()
5997-
* ```
5998-
*
5999-
* @return A new [BooleanExpression] representing the isNotNull operation.
6000-
*/
6001-
internal fun isNotNull(): BooleanExpression = Companion.isNotNull(this)
6002-
60035834
/**
60045835
* Creates an expression that calculates the length of a string, array, map, vector, or blob
60055836
* expression.

0 commit comments

Comments
 (0)