Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement FieldValue.minimum() and FieldValue.maximum() #2024

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
163 changes: 154 additions & 9 deletions dev/src/field-value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class FieldValue implements firestore.FieldValue {

/**
* Returns a special value that can be used with set(), create() or update()
* that tells the server to increment the the field's current value by the
* that tells the server to increment the field's current value by the
* given value.
*
* If either current field value or the operand uses floating point
Expand Down Expand Up @@ -122,6 +122,76 @@ export class FieldValue implements firestore.FieldValue {
return new NumericIncrementTransform(n);
}

/**
* Returns a special value that can be used with set(), create() or update()
* that tells the server to set the field to the numeric minimum of the
* field's current and the given value.
*
* If the current field value is not of type 'number', or if the field does
* not yet exist, the transformation will set the field to the given value.
*
* If the existing value and the operand are equivalent, then the field does
* not change. For example, `0`, `0.0`, and `-0.0` are all equivalent. If the
* operand is `NaN` then the result is always `NaN`.
*
* @param {number} n The value to compare to the exiting field value.
* @return {FieldValue} The FieldValue for use in a call to set(), create() or
* update().
*
* @example
* ```
* let documentRef = firestore.doc('col/doc');
*
* documentRef.update(
* 'counter', Firestore.FieldValue.minimum(1)
* ).then(() => {
* return documentRef.get();
* }).then(doc => {
* // doc.get('counter') is the minimum of either the existing value or 1
* });
* ```
*/
static minimum(n: number): FieldValue {
// eslint-disable-next-line prefer-rest-params
validateMinNumberOfArguments('FieldValue.minimum', arguments, 1);
return new NumericMinimumTransform(n);
}

/**
* Returns a special value that can be used with set(), create() or update()
* that tells the server to set the field to the numeric maximum of the
* field's current and the given value.
*
* If the current field value is not of type 'number', or if the field does
* not yet exist, the transformation will set the field to the given value.
*
* If the existing value and the operand are equivalent, then the field does
* not change. For example, `0`, `0.0`, and `-0.0` are all equivalent. If the
* operand is `NaN` then the result is always `NaN`.
*
* @param {number} n The value to compare to the exiting field value.
* @return {FieldValue} The FieldValue for use in a call to set(), create() or
* update().
*
* @example
* ```
* let documentRef = firestore.doc('col/doc');
*
* documentRef.update(
* 'counter', Firestore.FieldValue.maximum(1)
* ).then(() => {
* return documentRef.get();
* }).then(doc => {
* // doc.get('counter') is the maximum of either the existing value or 1
* });
* ```
*/
static maximum(n: number): FieldValue {
// eslint-disable-next-line prefer-rest-params
validateMinNumberOfArguments('FieldValue.maximum', arguments, 1);
return new NumericMaximumTransform(n);
}

/**
* Returns a special value that can be used with set(), create() or update()
* that tells the server to union the given elements with any array value that
Expand Down Expand Up @@ -366,13 +436,12 @@ class ServerTimestampTransform extends FieldTransform {
}

/**
* Increments a field value on the backend.
*
* Base class of numeric field transforms.
* @private
* @internal
*/
class NumericIncrementTransform extends FieldTransform {
constructor(private readonly operand: number) {
abstract class NumericFieldTransform extends FieldTransform {
constructor(protected readonly operand: number) {
super();
}

Expand All @@ -396,12 +465,24 @@ class NumericIncrementTransform extends FieldTransform {
return true;
}

get methodName(): string {
return 'FieldValue.increment';
validate(): void {
validateNumber(this.methodName + '()', this.operand);
}
}

validate(): void {
validateNumber('FieldValue.increment()', this.operand);
/**
* Increments a field value on the backend.
*
* @private
* @internal
*/
class NumericIncrementTransform extends NumericFieldTransform {
constructor(operand: number) {
super(operand);
}

get methodName(): string {
return 'FieldValue.increment';
}

toProto(
Expand All @@ -421,6 +502,70 @@ class NumericIncrementTransform extends FieldTransform {
}
}

/**
* Sets a field to the minimum of existing or operand.
*
* @private
* @internal
*/
class NumericMinimumTransform extends NumericFieldTransform {
constructor(operand: number) {
super(operand);
}

get methodName(): string {
return 'FieldValue.minimum';
}

toProto(
serializer: Serializer,
fieldPath: FieldPath
): api.DocumentTransform.IFieldTransform {
const encodedOperand = serializer.encodeValue(this.operand)!;
return {fieldPath: fieldPath.formattedName, minimum: encodedOperand};
}

isEqual(other: firestore.FieldValue): boolean {
return (
this === other ||
(other instanceof NumericMinimumTransform &&
this.operand === other.operand)
);
}
}

/**
* Sets a field to the maximum of existing or operand.
*
* @private
* @internal
*/
class NumericMaximumTransform extends NumericFieldTransform {
constructor(operand: number) {
super(operand);
}

get methodName(): string {
return 'FieldValue.maximum';
}

toProto(
serializer: Serializer,
fieldPath: FieldPath
): api.DocumentTransform.IFieldTransform {
const encodedOperand = serializer.encodeValue(this.operand)!;
return {fieldPath: fieldPath.formattedName, maximum: encodedOperand};
}

isEqual(other: firestore.FieldValue): boolean {
return (
this === other ||
(other instanceof NumericMaximumTransform &&
this.operand === other.operand)
);
}
}

/**
* Transforms an array value via a union operation.
*
Expand Down
Loading
Loading