Skip to content

Commit e8f14eb

Browse files
authored
feat(firestore): Add ifNull and coalesce expressions (#9753)
1 parent 742e17a commit e8f14eb

12 files changed

Lines changed: 1152 additions & 2 deletions

File tree

.changeset/rotten-tigers-bake.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'firebase': minor
3+
'@firebase/firestore': minor
4+
---
5+
6+
Add support for pipeline expressions `ifNull` and `coalesce`.

common/api-review/firestore-lite-pipelines.api.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,12 @@ export function charLength(fieldName: string): FunctionExpression;
274274
// @beta
275275
export function charLength(stringExpression: Expression): FunctionExpression;
276276

277+
// @beta
278+
export function coalesce(expression: Expression, replacement: Expression | unknown, ...others: Array<Expression | unknown>): FunctionExpression;
279+
280+
// @beta
281+
export function coalesce(fieldName: string, replacement: Expression | unknown, ...others: Array<Expression | unknown>): FunctionExpression;
282+
277283
// @beta
278284
export type CollectionGroupStageOptions = StageOptions & {
279285
collectionId: string;
@@ -557,6 +563,8 @@ export abstract class Expression {
557563
/* Excluded from this release type: _readUserData */
558564
charLength(): FunctionExpression;
559565
/* Excluded from this release type: _readUserData */
566+
coalesce(replacement: Expression | unknown, ...others: Array<Expression | unknown>): FunctionExpression;
567+
/* Excluded from this release type: _readUserData */
560568
collectionId(): FunctionExpression;
561569
/* Excluded from this release type: _readUserData */
562570
concat(second: Expression | unknown, ...others: Array<Expression | unknown>): FunctionExpression;
@@ -624,6 +632,10 @@ export abstract class Expression {
624632
/* Excluded from this release type: _readUserData */
625633
ifError(catchValue: unknown): FunctionExpression;
626634
/* Excluded from this release type: _readUserData */
635+
ifNull(elseExpression: Expression): FunctionExpression;
636+
/* Excluded from this release type: _readUserData */
637+
ifNull(elseValue: unknown): FunctionExpression;
638+
/* Excluded from this release type: _readUserData */
627639
isAbsent(): BooleanExpression;
628640
/* Excluded from this release type: _readUserData */
629641
isError(): BooleanExpression;
@@ -906,6 +918,18 @@ export function ifError(tryExpr: Expression, catchExpr: Expression): FunctionExp
906918
// @beta
907919
export function ifError(tryExpr: Expression, catchValue: unknown): FunctionExpression;
908920

921+
// @beta
922+
export function ifNull(ifExpr: Expression, elseExpr: Expression): FunctionExpression;
923+
924+
// @beta
925+
export function ifNull(ifExpr: Expression, elseValue: unknown): FunctionExpression;
926+
927+
// @beta
928+
export function ifNull(ifFieldName: string, elseExpr: Expression): FunctionExpression;
929+
930+
// @beta
931+
export function ifNull(ifFieldName: string, elseValue: unknown): FunctionExpression;
932+
909933
// @beta
910934
export function isAbsent(value: Expression): BooleanExpression;
911935

common/api-review/firestore-pipelines.api.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,12 @@ export function charLength(fieldName: string): FunctionExpression;
274274
// @beta
275275
export function charLength(stringExpression: Expression): FunctionExpression;
276276

277+
// @beta
278+
export function coalesce(expression: Expression, replacement: Expression | unknown, ...others: Array<Expression | unknown>): FunctionExpression;
279+
280+
// @beta
281+
export function coalesce(fieldName: string, replacement: Expression | unknown, ...others: Array<Expression | unknown>): FunctionExpression;
282+
277283
// @beta
278284
export type CollectionGroupStageOptions = StageOptions & {
279285
collectionId: string;
@@ -560,6 +566,8 @@ export abstract class Expression {
560566
/* Excluded from this release type: _readUserData */
561567
charLength(): FunctionExpression;
562568
/* Excluded from this release type: _readUserData */
569+
coalesce(replacement: Expression | unknown, ...others: Array<Expression | unknown>): FunctionExpression;
570+
/* Excluded from this release type: _readUserData */
563571
collectionId(): FunctionExpression;
564572
/* Excluded from this release type: _readUserData */
565573
concat(second: Expression | unknown, ...others: Array<Expression | unknown>): FunctionExpression;
@@ -627,6 +635,10 @@ export abstract class Expression {
627635
/* Excluded from this release type: _readUserData */
628636
ifError(catchValue: unknown): FunctionExpression;
629637
/* Excluded from this release type: _readUserData */
638+
ifNull(elseExpression: Expression): FunctionExpression;
639+
/* Excluded from this release type: _readUserData */
640+
ifNull(elseValue: unknown): FunctionExpression;
641+
/* Excluded from this release type: _readUserData */
630642
isAbsent(): BooleanExpression;
631643
/* Excluded from this release type: _readUserData */
632644
isError(): BooleanExpression;
@@ -909,6 +921,18 @@ export function ifError(tryExpr: Expression, catchExpr: Expression): FunctionExp
909921
// @beta
910922
export function ifError(tryExpr: Expression, catchValue: unknown): FunctionExpression;
911923

924+
// @beta
925+
export function ifNull(ifExpr: Expression, elseExpr: Expression): FunctionExpression;
926+
927+
// @beta
928+
export function ifNull(ifExpr: Expression, elseValue: unknown): FunctionExpression;
929+
930+
// @beta
931+
export function ifNull(ifFieldName: string, elseExpr: Expression): FunctionExpression;
932+
933+
// @beta
934+
export function ifNull(ifFieldName: string, elseValue: unknown): FunctionExpression;
935+
912936
// @beta
913937
export function isAbsent(value: Expression): BooleanExpression;
914938

docs-devsite/firestore_lite_pipelines.expression.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export declare abstract class Expression
7878
| [byteLength()](./firestore_lite_pipelines.expression.md#expressionbytelength) | | <b><i>(Public Preview)</i></b> Creates an expression that calculates the length of this string expression in bytes. |
7979
| [ceil()](./firestore_lite_pipelines.expression.md#expressionceil) | | <b><i>(Public Preview)</i></b> Creates an expression that computes the ceiling of a numeric value. |
8080
| [charLength()](./firestore_lite_pipelines.expression.md#expressioncharlength) | | <b><i>(Public Preview)</i></b> Creates an expression that calculates the character length of a string in UTF-8. |
81+
| [coalesce(replacement, others)](./firestore_lite_pipelines.expression.md#expressioncoalesce) | | <b><i>(Public Preview)</i></b> Creates an expression that returns the first non-null, non-absent argument, without evaluating the rest of the arguments. When all arguments are null or absent, returns the last argument. |
8182
| [collectionId()](./firestore_lite_pipelines.expression.md#expressioncollectionid) | | <b><i>(Public Preview)</i></b> Creates an expression that returns the collection ID from a path. |
8283
| [concat(second, others)](./firestore_lite_pipelines.expression.md#expressionconcat) | | <b><i>(Public Preview)</i></b> Creates an expression that concatenates expression results together. |
8384
| [cosineDistance(vectorExpression)](./firestore_lite_pipelines.expression.md#expressioncosinedistance) | | <b><i>(Public Preview)</i></b> Calculates the cosine distance between two vectors. |
@@ -110,6 +111,8 @@ export declare abstract class Expression
110111
| [ifAbsent(elseExpression)](./firestore_lite_pipelines.expression.md#expressionifabsent) | | <b><i>(Public Preview)</i></b> Creates an expression that returns the <code>elseValue</code> argument if this expression results in an absent value, else return the result of this expression evaluation. |
111112
| [ifError(catchExpr)](./firestore_lite_pipelines.expression.md#expressioniferror) | | <b><i>(Public Preview)</i></b> Creates an expression that returns the result of the <code>catchExpr</code> argument if there is an error, else return the result of this expression. |
112113
| [ifError(catchValue)](./firestore_lite_pipelines.expression.md#expressioniferror) | | <b><i>(Public Preview)</i></b> Creates an expression that returns the <code>catch</code> argument if there is an error, else return the result of this expression. |
114+
| [ifNull(elseExpression)](./firestore_lite_pipelines.expression.md#expressionifnull) | | <b><i>(Public Preview)</i></b> Creates an expression that returns the <code>elseValue</code> argument if this expression evaluates to null, else return the result of this expression evaluation. |
115+
| [ifNull(elseValue)](./firestore_lite_pipelines.expression.md#expressionifnull) | | <b><i>(Public Preview)</i></b> Creates an expression that returns the <code>elseValue</code> argument if this expression evaluates to null, else return the result of this expression evaluation. |
113116
| [isAbsent()](./firestore_lite_pipelines.expression.md#expressionisabsent) | | <b><i>(Public Preview)</i></b> Creates an expression that returns <code>true</code> if the result of this expression is absent. Otherwise, returns <code>false</code> even if the value is <code>null</code>. |
114117
| [isError()](./firestore_lite_pipelines.expression.md#expressioniserror) | | <b><i>(Public Preview)</i></b> Creates an expression that checks if a given expression produces an error. |
115118
| [isType(type)](./firestore_lite_pipelines.expression.md#expressionistype) | | <b><i>(Public Preview)</i></b> Creates an expression that checks if the result of this expression is of the given type. |
@@ -1506,6 +1509,42 @@ field("name").charLength();
15061509
15071510
```
15081511

1512+
## Expression.coalesce()
1513+
1514+
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
1515+
>
1516+
1517+
Creates an expression that returns the first non-null, non-absent argument, without evaluating the rest of the arguments. When all arguments are null or absent, returns the last argument.
1518+
1519+
<b>Signature:</b>
1520+
1521+
```typescript
1522+
coalesce(replacement: Expression | unknown, ...others: Array<Expression | unknown>): FunctionExpression;
1523+
```
1524+
1525+
#### Parameters
1526+
1527+
| Parameter | Type | Description |
1528+
| --- | --- | --- |
1529+
| replacement | [Expression](./firestore_lite_pipelines.expression.md#expression_class) \| unknown | The value to use if this expression evaluates to null. |
1530+
| others | Array&lt;[Expression](./firestore_lite_pipelines.expression.md#expression_class) \| unknown&gt; | Optional additional values to check if previous values are null. |
1531+
1532+
<b>Returns:</b>
1533+
1534+
[FunctionExpression](./firestore_lite_pipelines.functionexpression.md#functionexpression_class)
1535+
1536+
A new `Expression` representing the coalesce operation.
1537+
1538+
### Example
1539+
1540+
1541+
```typescript
1542+
// Returns the value of the first non-null, non-absent field among 'preferredName', 'fullName',
1543+
// or the last argument if all previous fields are null.
1544+
field("preferredName").coalesce(field("fullName"), "Anonymous");
1545+
1546+
```
1547+
15091548
## Expression.collectionId()
15101549

15111550
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
@@ -2537,6 +2576,78 @@ field("title").arrayGet(0).ifError("Default Title");
25372576
25382577
```
25392578

2579+
## Expression.ifNull()
2580+
2581+
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
2582+
>
2583+
2584+
Creates an expression that returns the `elseValue` argument if this expression evaluates to null, else return the result of this expression evaluation.
2585+
2586+
This function provides a fallback for both absent and explicit null values. In contrast, `ifAbsent()` only triggers for missing fields.
2587+
2588+
<b>Signature:</b>
2589+
2590+
```typescript
2591+
ifNull(elseExpression: Expression): FunctionExpression;
2592+
```
2593+
2594+
#### Parameters
2595+
2596+
| Parameter | Type | Description |
2597+
| --- | --- | --- |
2598+
| elseExpression | [Expression](./firestore_lite_pipelines.expression.md#expression_class) | The Expression that will be evaluated if this Expression evaluates to null. |
2599+
2600+
<b>Returns:</b>
2601+
2602+
[FunctionExpression](./firestore_lite_pipelines.functionexpression.md#functionexpression_class)
2603+
2604+
A new `Expression` representing the ifNull operation.
2605+
2606+
### Example
2607+
2608+
2609+
```typescript
2610+
// Returns the user's preferred name, or if that is null, returns their full name.
2611+
field("preferredName").ifNull(field("fullName"))
2612+
2613+
```
2614+
2615+
## Expression.ifNull()
2616+
2617+
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
2618+
>
2619+
2620+
Creates an expression that returns the `elseValue` argument if this expression evaluates to null, else return the result of this expression evaluation.
2621+
2622+
This function provides a fallback for both absent and explicit null values. In contrast, `ifAbsent()` only triggers for missing fields.
2623+
2624+
<b>Signature:</b>
2625+
2626+
```typescript
2627+
ifNull(elseValue: unknown): FunctionExpression;
2628+
```
2629+
2630+
#### Parameters
2631+
2632+
| Parameter | Type | Description |
2633+
| --- | --- | --- |
2634+
| elseValue | unknown | The value that will be returned if this Expression evaluates to null. |
2635+
2636+
<b>Returns:</b>
2637+
2638+
[FunctionExpression](./firestore_lite_pipelines.functionexpression.md#functionexpression_class)
2639+
2640+
A new `Expression` representing the ifNull operation.
2641+
2642+
### Example
2643+
2644+
2645+
```typescript
2646+
// Returns the user's display name, or returns "Anonymous" if the field is null.
2647+
field("displayName").ifNull("Anonymous")
2648+
2649+
```
2650+
25402651
## Expression.isAbsent()
25412652
25422653
> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.

0 commit comments

Comments
 (0)