@@ -152,7 +152,7 @@ export class FieldValue implements firestore.FieldValue {
152152
153153 /**
154154 * Returns a special value that can be used with set(), create() or update()
155- * that tells the server to increment the the field's current value by the
155+ * that tells the server to increment the field's current value by the
156156 * given value.
157157 *
158158 * If either current field value or the operand uses floating point
@@ -186,6 +186,76 @@ export class FieldValue implements firestore.FieldValue {
186186 return new NumericIncrementTransform ( n ) ;
187187 }
188188
189+ /**
190+ * Returns a special value that can be used with `set()`, `create()` or `update()`
191+ * that tells the server to set the field to the numeric minimum of the
192+ * field's current and the given value.
193+ *
194+ * If the current field value is not of type 'number', or if the field does
195+ * not yet exist, the transformation will set the field to the given value.
196+ *
197+ * If the existing value and the operand are equivalent, then the field does
198+ * not change. For example, `0`, `0.0`, and `-0.0` are all equivalent. If the
199+ * operand is `NaN` then the result is always `NaN`.
200+ *
201+ * @param {number } n The value to compare to the exiting field value.
202+ * @return {FieldValue } The FieldValue for use in a call to `set()`, `create()` or
203+ * `update()`.
204+ *
205+ * @example
206+ * ```typescript
207+ * let documentRef = firestore.doc('col/doc');
208+ *
209+ * documentRef.update(
210+ * 'counter', Firestore.FieldValue.minimum(1)
211+ * ).then(() => {
212+ * return documentRef.get();
213+ * }).then(doc => {
214+ * // doc.get('counter') is the minimum of either the existing value or 1
215+ * });
216+ * ```
217+ */
218+ static minimum ( n : number ) : FieldValue {
219+ // eslint-disable-next-line prefer-rest-params
220+ validateMinNumberOfArguments ( 'FieldValue.minimum' , arguments , 1 ) ;
221+ return new NumericMinimumTransform ( n ) ;
222+ }
223+
224+ /**
225+ * Returns a special value that can be used with `set()`, `create()` or `update()`
226+ * that tells the server to set the field to the numeric maximum of the
227+ * field's current and the given value.
228+ *
229+ * If the current field value is not of type 'number', or if the field does
230+ * not yet exist, the transformation will set the field to the given value.
231+ *
232+ * If the existing value and the operand are equivalent, then the field does
233+ * not change. For example, `0`, `0.0`, and `-0.0` are all equivalent. If the
234+ * operand is `NaN` then the result is always `NaN`.
235+ *
236+ * @param {number } n The value to compare to the exiting field value.
237+ * @return {FieldValue } The `FieldValue` for use in a call to `set()`, `create()` or
238+ * `update()`.
239+ *
240+ * @example
241+ * ```typescript
242+ * let documentRef = firestore.doc('col/doc');
243+ *
244+ * documentRef.update(
245+ * 'counter', Firestore.FieldValue.maximum(1)
246+ * ).then(() => {
247+ * return documentRef.get();
248+ * }).then(doc => {
249+ * // doc.get('counter') is the maximum of either the existing value or 1
250+ * });
251+ * ```
252+ */
253+ static maximum ( n : number ) : FieldValue {
254+ // eslint-disable-next-line prefer-rest-params
255+ validateMinNumberOfArguments ( 'FieldValue.maximum' , arguments , 1 ) ;
256+ return new NumericMaximumTransform ( n ) ;
257+ }
258+
189259 /**
190260 * Returns a special value that can be used with set(), create() or update()
191261 * that tells the server to union the given elements with any array value that
@@ -430,13 +500,12 @@ class ServerTimestampTransform extends FieldTransform {
430500}
431501
432502/**
433- * Increments a field value on the backend.
434- *
503+ * Base class of numeric field transforms.
435504 * @private
436505 * @internal
437506 */
438- class NumericIncrementTransform extends FieldTransform {
439- constructor ( private readonly operand : number ) {
507+ abstract class NumericFieldTransform extends FieldTransform {
508+ constructor ( protected readonly operand : number ) {
440509 super ( ) ;
441510 }
442511
@@ -460,12 +529,24 @@ class NumericIncrementTransform extends FieldTransform {
460529 return true ;
461530 }
462531
463- get methodName ( ) : string {
464- return 'FieldValue.increment' ;
532+ validate ( ) : void {
533+ validateNumber ( this . methodName + '()' , this . operand ) ;
465534 }
535+ }
466536
467- validate ( ) : void {
468- validateNumber ( 'FieldValue.increment()' , this . operand ) ;
537+ /**
538+ * Increments a field value on the backend.
539+ *
540+ * @private
541+ * @internal
542+ */
543+ class NumericIncrementTransform extends NumericFieldTransform {
544+ constructor ( operand : number ) {
545+ super ( operand ) ;
546+ }
547+
548+ get methodName ( ) : string {
549+ return 'FieldValue.increment' ;
469550 }
470551
471552 toProto (
@@ -480,7 +561,74 @@ class NumericIncrementTransform extends FieldTransform {
480561 return (
481562 this === other ||
482563 ( other instanceof NumericIncrementTransform &&
483- this . operand === other . operand )
564+ ( this . operand === other . operand ||
565+ ( Number . isNaN ( this . operand ) && Number . isNaN ( other . operand ) ) ) )
566+ ) ;
567+ }
568+ }
569+
570+ /**
571+ * Sets a field to the minimum of existing or operand.
572+ *
573+ * @private
574+ * @internal
575+ */
576+ class NumericMinimumTransform extends NumericFieldTransform {
577+ constructor ( operand : number ) {
578+ super ( operand ) ;
579+ }
580+
581+ get methodName ( ) : string {
582+ return 'FieldValue.minimum' ;
583+ }
584+
585+ toProto (
586+ serializer : Serializer ,
587+ fieldPath : FieldPath ,
588+ ) : api . DocumentTransform . IFieldTransform {
589+ const encodedOperand = serializer . encodeValue ( this . operand ) ! ;
590+ return { fieldPath : fieldPath . formattedName , minimum : encodedOperand } ;
591+ }
592+
593+ isEqual ( other : firestore . FieldValue ) : boolean {
594+ return (
595+ this === other ||
596+ ( other instanceof NumericMinimumTransform &&
597+ ( this . operand === other . operand ||
598+ ( Number . isNaN ( this . operand ) && Number . isNaN ( other . operand ) ) ) )
599+ ) ;
600+ }
601+ }
602+
603+ /**
604+ * Sets a field to the maximum of existing or operand.
605+ *
606+ * @private
607+ * @internal
608+ */
609+ class NumericMaximumTransform extends NumericFieldTransform {
610+ constructor ( operand : number ) {
611+ super ( operand ) ;
612+ }
613+
614+ get methodName ( ) : string {
615+ return 'FieldValue.maximum' ;
616+ }
617+
618+ toProto (
619+ serializer : Serializer ,
620+ fieldPath : FieldPath ,
621+ ) : api . DocumentTransform . IFieldTransform {
622+ const encodedOperand = serializer . encodeValue ( this . operand ) ! ;
623+ return { fieldPath : fieldPath . formattedName , maximum : encodedOperand } ;
624+ }
625+
626+ isEqual ( other : firestore . FieldValue ) : boolean {
627+ return (
628+ this === other ||
629+ ( other instanceof NumericMaximumTransform &&
630+ ( this . operand === other . operand ||
631+ ( Number . isNaN ( this . operand ) && Number . isNaN ( other . operand ) ) ) )
484632 ) ;
485633 }
486634}
0 commit comments