123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668 |
- "use strict";
- /*!
- * Copyright 2019 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.WriteBatch = exports.WriteResult = void 0;
- exports.validateSetOptions = validateSetOptions;
- exports.validateDocumentData = validateDocumentData;
- exports.validateFieldValue = validateFieldValue;
- const document_1 = require("./document");
- const logger_1 = require("./logger");
- const path_1 = require("./path");
- const helpers_1 = require("./reference/helpers");
- const serializer_1 = require("./serializer");
- const timestamp_1 = require("./timestamp");
- const util_1 = require("./util");
- const validate_1 = require("./validate");
- const trace_util_1 = require("./telemetry/trace-util");
- /**
- * A WriteResult wraps the write time set by the Firestore servers on sets(),
- * updates(), and creates().
- *
- * @class WriteResult
- */
- class WriteResult {
- /**
- * @private
- *
- * @param _writeTime The time of the corresponding document write.
- */
- constructor(_writeTime) {
- this._writeTime = _writeTime;
- }
- /**
- * The write time as set by the Firestore servers.
- *
- * @type {Timestamp}
- * @name WriteResult#writeTime
- * @readonly
- *
- * @example
- * ```
- * let documentRef = firestore.doc('col/doc');
- *
- * documentRef.set({foo: 'bar'}).then(writeResult => {
- * console.log(`Document written at: ${writeResult.writeTime.toDate()}`);
- * });
- * ```
- */
- get writeTime() {
- return this._writeTime;
- }
- /**
- * Returns true if this `WriteResult` is equal to the provided value.
- *
- * @param {*} other The value to compare against.
- * @return true if this `WriteResult` is equal to the provided value.
- */
- isEqual(other) {
- return (this === other ||
- (other instanceof WriteResult &&
- this._writeTime.isEqual(other._writeTime)));
- }
- }
- exports.WriteResult = WriteResult;
- /**
- * A Firestore WriteBatch that can be used to atomically commit multiple write
- * operations at once.
- *
- * @class WriteBatch
- */
- class WriteBatch {
- /**
- * The number of writes in this batch.
- * @private
- * @internal
- */
- get _opCount() {
- return this._ops.length;
- }
- /** @private */
- constructor(firestore) {
- /**
- * An array of document paths and the corresponding write operations that are
- * executed as part of the commit. The resulting `api.IWrite` will be sent to
- * the backend.
- *
- * @private
- * @internal
- */
- this._ops = [];
- this._committed = false;
- this._firestore = firestore;
- this._serializer = new serializer_1.Serializer(firestore);
- this._allowUndefined = !!firestore._settings.ignoreUndefinedProperties;
- }
- /**
- * Checks if this write batch has any pending operations.
- *
- * @private
- * @internal
- */
- get isEmpty() {
- return this._ops.length === 0;
- }
- /**
- * Throws an error if this batch has already been committed.
- *
- * @private
- * @internal
- */
- verifyNotCommitted() {
- if (this._committed) {
- throw new Error('Cannot modify a WriteBatch that has been committed.');
- }
- }
- /**
- * Create a document with the provided object values. This will fail the batch
- * if a document exists at its location.
- *
- * @param {DocumentReference} documentRef A reference to the document to be
- * created.
- * @param {T} data The object to serialize as the document.
- * @throws {Error} If the provided input is not a valid Firestore document.
- * @returns {WriteBatch} This WriteBatch instance. Used for chaining
- * method calls.
- *
- * @example
- * ```
- * let writeBatch = firestore.batch();
- * let documentRef = firestore.collection('col').doc();
- *
- * writeBatch.create(documentRef, {foo: 'bar'});
- *
- * writeBatch.commit().then(() => {
- * console.log('Successfully executed batch.');
- * });
- * ```
- */
- create(documentRef, data) {
- const ref = (0, helpers_1.validateDocumentReference)('documentRef', documentRef);
- const firestoreData = ref._converter.toFirestore(data);
- validateDocumentData('data', firestoreData,
- /* allowDeletes= */ false, this._allowUndefined);
- this.verifyNotCommitted();
- const transform = document_1.DocumentTransform.fromObject(ref, firestoreData);
- transform.validate();
- const precondition = new document_1.Precondition({ exists: false });
- const op = () => {
- const document = document_1.DocumentSnapshot.fromObject(ref, firestoreData);
- const write = document.toWriteProto();
- if (!transform.isEmpty) {
- write.updateTransforms = transform.toProto(this._serializer);
- }
- write.currentDocument = precondition.toProto();
- return write;
- };
- this._ops.push({ docPath: documentRef.path, op });
- return this;
- }
- /**
- * Deletes a document from the database.
- *
- * @param {DocumentReference} documentRef A reference to the document to be
- * deleted.
- * @param {Precondition=} precondition A precondition to enforce for this
- * delete.
- * @param {Timestamp=} precondition.lastUpdateTime If set, enforces that the
- * document was last updated at lastUpdateTime. Fails the batch if the
- * document doesn't exist or was last updated at a different time.
- * @param {boolean= } precondition.exists If set to true, enforces that the target
- * document must or must not exist.
- * @returns {WriteBatch} This WriteBatch instance. Used for chaining
- * method calls.
- *
- * @example
- * ```
- * let writeBatch = firestore.batch();
- * let documentRef = firestore.doc('col/doc');
- *
- * writeBatch.delete(documentRef);
- *
- * writeBatch.commit().then(() => {
- * console.log('Successfully executed batch.');
- * });
- * ```
- */
- delete(
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- documentRef, precondition) {
- const ref = (0, helpers_1.validateDocumentReference)('documentRef', documentRef);
- validateDeletePrecondition('precondition', precondition, { optional: true });
- this.verifyNotCommitted();
- const conditions = new document_1.Precondition(precondition);
- const op = () => {
- const write = { delete: ref.formattedName };
- if (!conditions.isEmpty) {
- write.currentDocument = conditions.toProto();
- }
- return write;
- };
- this._ops.push({ docPath: documentRef.path, op });
- return this;
- }
- /**
- * Write to the document referred to by the provided
- * [DocumentReference]{@link DocumentReference}. If the document does not
- * exist yet, it will be created. If you pass [SetOptions]{@link SetOptions},
- * the provided data can be merged into the existing document.
- *
- * @param {DocumentReference} documentRef A reference to the document to be
- * set.
- * @param {T|Partial<T>} data The object to serialize as the document.
- * @param {SetOptions=} options An object to configure the set behavior.
- * @param {boolean=} options.merge - If true, set() merges the values
- * specified in its data argument. Fields omitted from this set() call
- * remain untouched. If your input sets any field to an empty map, all nested
- * fields are overwritten.
- * @param {Array.<string|FieldPath>=} options.mergeFields - If provided,
- * set() only replaces the specified field paths. Any field path that is no
- * specified is ignored and remains untouched. If your input sets any field to
- * an empty map, all nested fields are overwritten.
- * @throws {Error} If the provided input is not a valid Firestore document.
- * @returns {WriteBatch} This WriteBatch instance. Used for chaining
- * method calls.
- *
- * @example
- * ```
- * let writeBatch = firestore.batch();
- * let documentRef = firestore.doc('col/doc');
- *
- * writeBatch.set(documentRef, {foo: 'bar'});
- *
- * writeBatch.commit().then(() => {
- * console.log('Successfully executed batch.');
- * });
- * ```
- */
- set(documentRef, data, options) {
- validateSetOptions('options', options, { optional: true });
- const mergeLeaves = options && 'merge' in options && options.merge;
- const mergePaths = options && 'mergeFields' in options;
- const ref = (0, helpers_1.validateDocumentReference)('documentRef', documentRef);
- let firestoreData;
- if (mergeLeaves || mergePaths) {
- firestoreData = ref._converter.toFirestore(data, options);
- }
- else {
- firestoreData = ref._converter.toFirestore(data);
- }
- validateDocumentData('data', firestoreData,
- /* allowDeletes= */ !!(mergePaths || mergeLeaves), this._allowUndefined);
- this.verifyNotCommitted();
- let documentMask;
- if (mergePaths) {
- documentMask = document_1.DocumentMask.fromFieldMask(options.mergeFields);
- firestoreData = documentMask.applyTo(firestoreData);
- }
- const transform = document_1.DocumentTransform.fromObject(ref, firestoreData);
- transform.validate();
- const op = () => {
- const document = document_1.DocumentSnapshot.fromObject(ref, firestoreData);
- if (mergePaths) {
- documentMask.removeFields(transform.fields);
- }
- else if (mergeLeaves) {
- documentMask = document_1.DocumentMask.fromObject(firestoreData);
- }
- const write = document.toWriteProto();
- if (!transform.isEmpty) {
- write.updateTransforms = transform.toProto(this._serializer);
- }
- if (mergePaths || mergeLeaves) {
- write.updateMask = documentMask.toProto();
- }
- return write;
- };
- this._ops.push({ docPath: documentRef.path, op });
- return this;
- }
- /**
- * Update fields of the document referred to by the provided
- * [DocumentReference]{@link DocumentReference}. If the document
- * doesn't yet exist, the update fails and the entire batch will be rejected.
- *
- * The update() method accepts either an object with field paths encoded as
- * keys and field values encoded as values, or a variable number of arguments
- * that alternate between field paths and field values. Nested fields can be
- * updated by providing dot-separated field path strings or by providing
- * FieldPath objects.
- *
- * A Precondition restricting this update can be specified as the last
- * argument.
- *
- * @param {DocumentReference} documentRef A reference to the document to be
- * updated.
- * @param {UpdateData|string|FieldPath} dataOrField An object
- * containing the fields and values with which to update the document
- * or the path of the first field to update.
- * @param {
- * ...(Precondition|*|string|FieldPath)} preconditionOrValues -
- * An alternating list of field paths and values to update or a Precondition
- * to restrict this update.
- * @throws {Error} If the provided input is not valid Firestore data.
- * @returns {WriteBatch} This WriteBatch instance. Used for chaining
- * method calls.
- *
- * @example
- * ```
- * let writeBatch = firestore.batch();
- * let documentRef = firestore.doc('col/doc');
- *
- * writeBatch.update(documentRef, {foo: 'bar'});
- *
- * writeBatch.commit().then(() => {
- * console.log('Successfully executed batch.');
- * });
- * ```
- */
- update(documentRef, dataOrField, ...preconditionOrValues) {
- // eslint-disable-next-line prefer-rest-params
- (0, validate_1.validateMinNumberOfArguments)('WriteBatch.update', arguments, 2);
- (0, helpers_1.validateDocumentReference)('documentRef', documentRef);
- this.verifyNotCommitted();
- const updateMap = new Map();
- let precondition = new document_1.Precondition({ exists: true });
- const argumentError = 'Update() requires either a single JavaScript ' +
- 'object or an alternating list of field/value pairs that can be ' +
- 'followed by an optional precondition.';
- const usesVarargs = typeof dataOrField === 'string' || dataOrField instanceof path_1.FieldPath;
- if (usesVarargs) {
- const argumentOffset = 1; // Respect 'documentRef' in the error message
- const fieldOrValues = [dataOrField, ...preconditionOrValues];
- try {
- for (let i = 0; i < fieldOrValues.length; i += 2) {
- if (i === fieldOrValues.length - 1) {
- const maybePrecondition = fieldOrValues[i];
- validateUpdatePrecondition(i + argumentOffset, maybePrecondition);
- precondition = new document_1.Precondition(maybePrecondition);
- }
- else {
- const maybeFieldPath = fieldOrValues[i];
- (0, path_1.validateFieldPath)(i + argumentOffset, maybeFieldPath);
- // Unlike the `validateMinNumberOfArguments` invocation above, this
- // validation can be triggered both from `WriteBatch.update()` and
- // `DocumentReference.update()`. Hence, we don't use the fully
- // qualified API name in the error message.
- (0, validate_1.validateMinNumberOfArguments)('update', fieldOrValues, i + 1);
- const fieldPath = path_1.FieldPath.fromArgument(maybeFieldPath);
- validateFieldValue(i + argumentOffset, fieldOrValues[i + 1], this._allowUndefined, fieldPath);
- updateMap.set(fieldPath, fieldOrValues[i + 1]);
- }
- }
- }
- catch (err) {
- (0, logger_1.logger)('WriteBatch.update', null, 'Varargs validation failed:', err);
- // We catch the validation error here and re-throw to provide a better
- // error message.
- throw new Error(`${argumentError} ${err.message}`);
- }
- }
- else {
- try {
- validateUpdateMap('dataOrField', dataOrField, this._allowUndefined);
- // eslint-disable-next-line prefer-rest-params
- (0, validate_1.validateMaxNumberOfArguments)('update', arguments, 3);
- Object.entries(dataOrField).forEach(([key, value]) => {
- // Skip `undefined` values (can be hit if `ignoreUndefinedProperties`
- // is set)
- if (value !== undefined) {
- (0, path_1.validateFieldPath)(key, key);
- updateMap.set(path_1.FieldPath.fromArgument(key), value);
- }
- });
- if (preconditionOrValues.length > 0) {
- validateUpdatePrecondition('preconditionOrValues', preconditionOrValues[0]);
- precondition = new document_1.Precondition(preconditionOrValues[0]);
- }
- }
- catch (err) {
- (0, logger_1.logger)('WriteBatch.update', null, 'Non-varargs validation failed:', err);
- // We catch the validation error here and prefix the error with a custom
- // message to describe the usage of update() better.
- throw new Error(`${argumentError} ${err.message}`);
- }
- }
- validateNoConflictingFields('dataOrField', updateMap);
- const transform = document_1.DocumentTransform.fromUpdateMap(documentRef, updateMap);
- transform.validate();
- const documentMask = document_1.DocumentMask.fromUpdateMap(updateMap);
- const op = () => {
- const document = document_1.DocumentSnapshot.fromUpdateMap(documentRef, updateMap);
- const write = document.toWriteProto();
- write.updateMask = documentMask.toProto();
- if (!transform.isEmpty) {
- write.updateTransforms = transform.toProto(this._serializer);
- }
- write.currentDocument = precondition.toProto();
- return write;
- };
- this._ops.push({ docPath: documentRef.path, op });
- return this;
- }
- /**
- * Atomically commits all pending operations to the database and verifies all
- * preconditions. Fails the entire write if any precondition is not met.
- *
- * @returns {Promise.<Array.<WriteResult>>} A Promise that resolves
- * when this batch completes.
- *
- * @example
- * ```
- * let writeBatch = firestore.batch();
- * let documentRef = firestore.doc('col/doc');
- *
- * writeBatch.set(documentRef, {foo: 'bar'});
- *
- * writeBatch.commit().then(() => {
- * console.log('Successfully executed batch.');
- * });
- * ```
- */
- commit() {
- return this._firestore._traceUtil.startActiveSpan(trace_util_1.SPAN_NAME_BATCH_COMMIT, async () => {
- // Capture the error stack to preserve stack tracing across async calls.
- const stack = Error().stack;
- // Commits should also be retried when they fail with status code ABORTED.
- const retryCodes = [10 /* StatusCode.ABORTED */, ...(0, util_1.getRetryCodes)('commit')];
- return this._commit({ retryCodes })
- .then(response => {
- return (response.writeResults || []).map(writeResult => new WriteResult(timestamp_1.Timestamp.fromProto(writeResult.updateTime || response.commitTime)));
- })
- .catch(err => {
- throw (0, util_1.wrapError)(err, stack);
- });
- }, {
- [trace_util_1.ATTRIBUTE_KEY_IS_TRANSACTIONAL]: false,
- [trace_util_1.ATTRIBUTE_KEY_DOC_COUNT]: this._opCount,
- });
- }
- /**
- * Commit method that takes an optional transaction ID.
- *
- * @private
- * @internal
- * @param commitOptions Options to use for this commit.
- * @param commitOptions.transactionId The transaction ID of this commit.
- * @param commitOptions.requestTag A unique client-assigned identifier for
- * this request.
- * @returns A Promise that resolves when this batch completes.
- */
- async _commit(commitOptions) {
- var _a;
- // Note: We don't call `verifyNotCommitted()` to allow for retries.
- this._committed = true;
- const tag = (_a = commitOptions === null || commitOptions === void 0 ? void 0 : commitOptions.requestTag) !== null && _a !== void 0 ? _a : (0, util_1.requestTag)();
- await this._firestore.initializeIfNeeded(tag);
- // Note that the request may not always be of type ICommitRequest. This is
- // just here to ensure type safety.
- const request = {
- database: this._firestore.formattedName,
- writes: this._ops.map(op => op.op()),
- };
- if (commitOptions === null || commitOptions === void 0 ? void 0 : commitOptions.transactionId) {
- request.transaction = commitOptions.transactionId;
- }
- (0, logger_1.logger)('WriteBatch.commit', tag, 'Sending %d writes', request.writes.length);
- return this._firestore.request((commitOptions === null || commitOptions === void 0 ? void 0 : commitOptions.methodName) || 'commit', request, tag, commitOptions === null || commitOptions === void 0 ? void 0 : commitOptions.retryCodes);
- }
- /**
- * Resets the WriteBatch and dequeues all pending operations.
- * @private
- * @internal
- */
- _reset() {
- this._ops.splice(0);
- this._committed = false;
- }
- }
- exports.WriteBatch = WriteBatch;
- /**
- * Validates the use of 'value' as a Precondition and enforces that 'exists'
- * and 'lastUpdateTime' use valid types.
- *
- * @private
- * @internal
- * @param arg The argument name or argument index (for varargs methods).
- * @param value The object to validate
- * @param options Options describing other things for this function to validate.
- */
- function validatePrecondition(arg, value, options) {
- if (typeof value !== 'object' || value === null) {
- throw new Error('Input is not an object.');
- }
- const precondition = value;
- let conditions = 0;
- if (precondition.exists !== undefined) {
- ++conditions;
- if (typeof precondition.exists !== 'boolean') {
- throw new Error(`${(0, validate_1.invalidArgumentMessage)(arg, 'precondition')} "exists" is not a boolean.'`);
- }
- if ((options === null || options === void 0 ? void 0 : options.allowedExistsValues) &&
- options.allowedExistsValues.indexOf(precondition.exists) < 0) {
- throw new Error(`${(0, validate_1.invalidArgumentMessage)(arg, 'precondition')} ` +
- `"exists" is not allowed to have the value ${precondition.exists} ` +
- `(allowed values: ${options.allowedExistsValues.join(', ')})`);
- }
- }
- if (precondition.lastUpdateTime !== undefined) {
- ++conditions;
- if (!(precondition.lastUpdateTime instanceof timestamp_1.Timestamp)) {
- throw new Error(`${(0, validate_1.invalidArgumentMessage)(arg, 'precondition')} "lastUpdateTime" is not a Firestore Timestamp.`);
- }
- }
- if (conditions > 1) {
- throw new Error(`${(0, validate_1.invalidArgumentMessage)(arg, 'precondition')} Input specifies more than one precondition.`);
- }
- }
- /**
- * Validates the use of 'value' as an update Precondition.
- *
- * @private
- * @internal
- * @param arg The argument name or argument index (for varargs methods).
- * @param value The object to validate.
- * @param options Optional validation options specifying whether the value can
- * be omitted.
- */
- function validateUpdatePrecondition(arg, value, options) {
- if (!(0, validate_1.validateOptional)(value, options)) {
- validatePrecondition(arg, value, { allowedExistsValues: [true] });
- }
- }
- /**
- * Validates the use of 'value' as a delete Precondition.
- *
- * @private
- * @internal
- * @param arg The argument name or argument index (for varargs methods).
- * @param value The object to validate.
- * @param options Optional validation options specifying whether the value can
- * be omitted.
- */
- function validateDeletePrecondition(arg, value, options) {
- if (!(0, validate_1.validateOptional)(value, options)) {
- validatePrecondition(arg, value);
- }
- }
- /**
- * Validates the use of 'value' as SetOptions and enforces that 'merge' is a
- * boolean.
- *
- * @private
- * @internal
- * @param arg The argument name or argument index (for varargs methods).
- * @param value The object to validate.
- * @param options Optional validation options specifying whether the value can
- * be omitted.
- * @throws if the input is not a valid SetOptions object.
- */
- function validateSetOptions(arg, value, options) {
- if (!(0, validate_1.validateOptional)(value, options)) {
- if (!(0, util_1.isObject)(value)) {
- throw new Error(`${(0, validate_1.invalidArgumentMessage)(arg, 'set() options argument')} Input is not an object.`);
- }
- const setOptions = value;
- if ('mergeFields' in setOptions) {
- for (let i = 0; i < setOptions.mergeFields.length; ++i) {
- try {
- (0, path_1.validateFieldPath)(i, setOptions.mergeFields[i]);
- }
- catch (err) {
- throw new Error(`${(0, validate_1.invalidArgumentMessage)(arg, 'set() options argument')} "mergeFields" is not valid: ${err.message}`);
- }
- }
- }
- if ('merge' in setOptions && 'mergeFields' in setOptions) {
- throw new Error(`${(0, validate_1.invalidArgumentMessage)(arg, 'set() options argument')} You cannot specify both "merge" and "mergeFields".`);
- }
- }
- }
- /**
- * Validates a JavaScript object for usage as a Firestore document.
- *
- * @private
- * @internal
- * @param arg The argument name or argument index (for varargs methods).
- * @param obj JavaScript object to validate.
- * @param allowDeletes Whether to allow FieldValue.delete() sentinels.
- * @param allowUndefined Whether to allow nested properties that are `undefined`.
- * @throws when the object is invalid.
- */
- function validateDocumentData(arg, obj, allowDeletes, allowUndefined) {
- if (!(0, util_1.isPlainObject)(obj)) {
- throw new Error((0, validate_1.customObjectMessage)(arg, obj));
- }
- (0, serializer_1.validateUserInput)(arg, obj, 'Firestore document', {
- allowDeletes: allowDeletes ? 'all' : 'none',
- allowTransforms: true,
- allowUndefined,
- });
- }
- /**
- * Validates that a value can be used as field value during an update.
- *
- * @private
- * @internal
- * @param arg The argument name or argument index (for varargs methods).
- * @param val The value to verify.
- * @param allowUndefined Whether to allow nested properties that are `undefined`.
- * @param path The path to show in the error message.
- */
- function validateFieldValue(arg, val, allowUndefined, path) {
- (0, serializer_1.validateUserInput)(arg, val, 'Firestore value', { allowDeletes: 'root', allowTransforms: true, allowUndefined }, path);
- }
- /**
- * Validates that the update data does not contain any ambiguous field
- * definitions (such as 'a.b' and 'a').
- *
- * @private
- * @internal
- * @param arg The argument name or argument index (for varargs methods).
- * @param data An update map with field/value pairs.
- */
- function validateNoConflictingFields(arg, data) {
- const fields = [];
- data.forEach((value, key) => {
- fields.push(key);
- });
- fields.sort((left, right) => left.compareTo(right));
- for (let i = 1; i < fields.length; ++i) {
- if (fields[i - 1].isPrefixOf(fields[i])) {
- throw new Error(`${(0, validate_1.invalidArgumentMessage)(arg, 'update map')} Field "${fields[i - 1]}" was specified multiple times.`);
- }
- }
- }
- /**
- * Validates that a JavaScript object is a map of field paths to field values.
- *
- * @private
- * @internal
- * @param arg The argument name or argument index (for varargs methods).
- * @param obj JavaScript object to validate.
- * @param allowUndefined Whether to allow nested properties that are `undefined`.
- * @throws when the object is invalid.
- */
- function validateUpdateMap(arg, obj, allowUndefined) {
- if (!(0, util_1.isPlainObject)(obj)) {
- throw new Error((0, validate_1.customObjectMessage)(arg, obj));
- }
- if (Object.keys(obj).length === 0) {
- throw new Error('At least one field must be updated.');
- }
- validateFieldValue(arg, obj, allowUndefined);
- }
- //# sourceMappingURL=write-batch.js.map
|