Skip to content

Commit 832e107

Browse files
committed
Fixed all incompatibilities
1 parent c5678fe commit 832e107

File tree

3 files changed

+273
-156
lines changed

3 files changed

+273
-156
lines changed

packages/firestore/src/core/expressions.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ import {
8383
TimestampSub,
8484
Field,
8585
Constant,
86-
FilterExpr
86+
FilterExpr,
87+
IsNull
8788
} from '../lite-api/expressions';
8889
import {
8990
CREATE_TIME_NAME,
@@ -176,6 +177,8 @@ export function toEvaluable<T>(expr: T): EvaluableExpr {
176177
return new CoreNotEqAny(expr);
177178
} else if (expr instanceof IsNan) {
178179
return new CoreIsNan(expr);
180+
} else if (expr instanceof IsNull) {
181+
return new CoreIsNull(expr);
179182
} else if (expr instanceof Exists) {
180183
return new CoreExists(expr);
181184
} else if (expr instanceof Not) {
@@ -283,10 +286,7 @@ export class CoreField implements EvaluableExpr {
283286
timestampValue: toVersion(context.serializer, input.createTime)
284287
};
285288
}
286-
return (
287-
input.data.field(FieldPath.fromServerFormat(this.expr.fieldName())) ??
288-
undefined
289-
);
289+
return input.data.field(this.expr.fieldPath) ?? undefined;
290290
}
291291
}
292292

@@ -831,6 +831,24 @@ export class CoreIsNan implements EvaluableExpr {
831831
}
832832
}
833833

834+
export class CoreIsNull implements EvaluableExpr {
835+
constructor(private expr: IsNull) {}
836+
837+
evaluate(
838+
context: EvaluationContext,
839+
input: PipelineInputOutput
840+
): Value | undefined {
841+
const evaluated = toEvaluable(this.expr.expr).evaluate(context, input);
842+
return {
843+
booleanValue: evaluated === undefined ? false : isNullValue(evaluated)
844+
};
845+
}
846+
847+
static fromProtoToApiObj(value: ProtoFunction): IsNan {
848+
return new IsNan(exprFromProto(value.args![0]));
849+
}
850+
}
851+
834852
export class CoreExists implements EvaluableExpr {
835853
constructor(private expr: Exists) {}
836854

@@ -839,11 +857,7 @@ export class CoreExists implements EvaluableExpr {
839857
input: PipelineInputOutput
840858
): Value | undefined {
841859
const evaluated = toEvaluable(this.expr.expr).evaluate(context, input);
842-
if (evaluated === undefined) {
843-
return undefined;
844-
}
845-
846-
return TRUE_VALUE;
860+
return evaluated === undefined ? FALSE_VALUE : TRUE_VALUE;
847861
}
848862

849863
static fromProtoToApiObj(value: ProtoFunction): Exists {

packages/firestore/src/lite-api/expressions.ts

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,21 @@ export abstract class Expr implements ProtoSerializable<ProtoValue>, UserData {
885885
return new IsNan(this);
886886
}
887887

888+
/**
889+
* Creates an expression that checks if this expression evaluates to `null`.
890+
*
891+
* ```typescript
892+
* // Check if a field is set to value `null`. Returns false if it is set to
893+
* // other values or is not set at all.
894+
* Field.of("value").isNull();
895+
* ```
896+
*
897+
* @return A new `Expr` representing the 'isNull' check.
898+
*/
899+
isNull(): IsNan {
900+
return new IsNull(this);
901+
}
902+
888903
/**
889904
* Creates an expression that checks if a field exists in the document.
890905
*
@@ -1923,7 +1938,7 @@ export class Field extends Expr implements Selectable {
19231938
* @private
19241939
*/
19251940
constructor(
1926-
private fieldPath: InternalFieldPath,
1941+
readonly fieldPath: InternalFieldPath,
19271942
private pipeline: Pipeline | null = null
19281943
) {
19291944
super();
@@ -1957,7 +1972,7 @@ export class Field extends Expr implements Selectable {
19571972
if (DOCUMENT_KEY_NAME === pipelineOrName) {
19581973
return new Field(documentId()._internalPath);
19591974
}
1960-
return new Field(fieldPathFromArgument('of', pipelineOrName));
1975+
return new Field(InternalFieldPath.fromServerFormat(pipelineOrName));
19611976
} else if (pipelineOrName instanceof FieldPath) {
19621977
if (documentId().isEqual(pipelineOrName)) {
19631978
return new Field(documentId()._internalPath);
@@ -2576,6 +2591,16 @@ export class IsNan extends FirestoreFunction implements FilterCondition {
25762591
filterable = true as const;
25772592
}
25782593

2594+
/**
2595+
* @beta
2596+
*/
2597+
export class IsNull extends FirestoreFunction implements FilterCondition {
2598+
constructor(readonly expr: Expr) {
2599+
super('is_null', [expr]);
2600+
}
2601+
filterable = true as const;
2602+
}
2603+
25792604
/**
25802605
* @beta
25812606
*/
@@ -4897,6 +4922,41 @@ export function isNan(value: Expr | string): IsNan {
48974922
return new IsNan(valueExpr);
48984923
}
48994924

4925+
/**
4926+
* @beta
4927+
*
4928+
* Creates an expression that checks if an expression evaluates to 'null'.
4929+
*
4930+
* ```typescript
4931+
* // Check if the field is set to 'null'. Returns false if it is not set, or
4932+
* // set to any other value.
4933+
* isNull(Field.of("value"));
4934+
* ```
4935+
*
4936+
* @param value The expression to check.
4937+
* @return A new {@code Expr} representing the 'isNull' check.
4938+
*/
4939+
export function isNull(value: Expr): IsNull;
4940+
4941+
/**
4942+
* @beta
4943+
*
4944+
* Creates an expression that checks if a field's value evaluates to 'null'.
4945+
*
4946+
* ```typescript
4947+
* // Check if the result of a calculation is null.
4948+
* isNull("value");
4949+
* ```
4950+
*
4951+
* @param value The name of the field to check.
4952+
* @return A new {@code Expr} representing the 'isNull' check.
4953+
*/
4954+
export function isNull(value: string): IsNull;
4955+
export function isNull(value: Expr | string): IsNull {
4956+
const valueExpr = value instanceof Expr ? value : Field.of(value);
4957+
return new IsNull(valueExpr);
4958+
}
4959+
49004960
/**
49014961
* @beta
49024962
*

0 commit comments

Comments
 (0)