diff --git a/.changeset/blue-geese-approve.md b/.changeset/blue-geese-approve.md new file mode 100644 index 00000000000..01e5dd9cb72 --- /dev/null +++ b/.changeset/blue-geese-approve.md @@ -0,0 +1,5 @@ +--- +"@firebase/firestore": patch +--- + +Internal changes for the upcoming modular API. diff --git a/packages/firestore/exp/src/api/write_batch.ts b/packages/firestore/exp/src/api/write_batch.ts index 9296026d7b3..e20132709a6 100644 --- a/packages/firestore/exp/src/api/write_batch.ts +++ b/packages/firestore/exp/src/api/write_batch.ts @@ -20,6 +20,8 @@ import { FirebaseFirestore } from './database'; import { executeWrite } from './reference'; import { ensureFirestoreConfigured } from '../../../src/api/database'; +export { WriteBatch }; + /** * Creates a write batch, used for performing multiple writes as a single * atomic operation. The maximum number of writes allowed in a single WriteBatch diff --git a/packages/firestore/exp/test/shim.ts b/packages/firestore/exp/test/shim.ts index b2b9b5ba896..dc895395907 100644 --- a/packages/firestore/exp/test/shim.ts +++ b/packages/firestore/exp/test/shim.ts @@ -128,63 +128,6 @@ export class Transaction } } -export class WriteBatch - extends Compat - implements legacy.WriteBatch { - set( - documentRef: DocumentReference, - data: T, - options?: legacy.SetOptions - ): WriteBatch { - if (options) { - validateSetOptions('WriteBatch.set', options); - this._delegate.set(documentRef._delegate, unwrap(data), options); - } else { - this._delegate.set(documentRef._delegate, unwrap(data)); - } - return this; - } - - update( - documentRef: DocumentReference, - data: legacy.UpdateData - ): WriteBatch; - update( - documentRef: DocumentReference, - field: string | FieldPath, - value: any, - ...moreFieldsAndValues: any[] - ): WriteBatch; - update( - documentRef: DocumentReference, - dataOrField: any, - value?: any, - ...moreFieldsAndValues: any[] - ): WriteBatch { - if (arguments.length === 2) { - this._delegate.update(documentRef._delegate, unwrap(dataOrField)); - } else { - this._delegate.update( - documentRef._delegate, - unwrap(dataOrField), - unwrap(value), - ...unwrap(moreFieldsAndValues) - ); - } - - return this; - } - - delete(documentRef: DocumentReference): WriteBatch { - this._delegate.delete(documentRef._delegate); - return this; - } - - commit(): Promise { - return this._delegate.commit(); - } -} - export class Query extends Compat> implements legacy.Query { diff --git a/packages/firestore/lite/src/api/reference.ts b/packages/firestore/lite/src/api/reference.ts index a0e915d9c10..ff05ae4c46d 100644 --- a/packages/firestore/lite/src/api/reference.ts +++ b/packages/firestore/lite/src/api/reference.ts @@ -81,6 +81,7 @@ import { getDatastore } from './components'; import { ByteString } from '../../../src/util/byte_string'; import { Bytes } from './bytes'; import { AbstractUserDataWriter } from '../../../src/api/user_data_writer'; +import { Compat } from '../../../src/compat/compat'; /** * Document data (for use with {@link setDoc()}) consists of fields mapped to @@ -1109,6 +1110,12 @@ export function updateDoc( ): Promise { const dataReader = newUserDataReader(reference.firestore); + // For Compat types, we have to "extract" the underlying types before + // performing validation. + if (fieldOrUpdateData instanceof Compat) { + fieldOrUpdateData = fieldOrUpdateData._delegate; + } + let parsed: ParsedUpdateData; if ( typeof fieldOrUpdateData === 'string' || diff --git a/packages/firestore/lite/src/api/transaction.ts b/packages/firestore/lite/src/api/transaction.ts index 88f5c8419af..1350986b3c9 100644 --- a/packages/firestore/lite/src/api/transaction.ts +++ b/packages/firestore/lite/src/api/transaction.ts @@ -44,6 +44,7 @@ import { } from './reference'; import { FieldPath } from './field_path'; import { getDatastore } from './components'; +import { Compat } from '../../../src/compat/compat'; // TODO(mrschmidt) Consider using `BaseTransaction` as the base class in the // legacy SDK. @@ -198,6 +199,12 @@ export class Transaction { ): this { const ref = validateReference(documentRef, this._firestore); + // For Compat types, we have to "extract" the underlying types before + // performing validation. + if (fieldOrUpdateData instanceof Compat) { + fieldOrUpdateData = fieldOrUpdateData._delegate; + } + let parsed; if ( typeof fieldOrUpdateData === 'string' || diff --git a/packages/firestore/lite/src/api/write_batch.ts b/packages/firestore/lite/src/api/write_batch.ts index 1f78e05e32e..4e094b4dbcc 100644 --- a/packages/firestore/lite/src/api/write_batch.ts +++ b/packages/firestore/lite/src/api/write_batch.ts @@ -38,6 +38,7 @@ import { FirebaseFirestore } from './database'; import { invokeCommitRpc } from '../../../src/remote/datastore'; import { FieldPath } from './field_path'; import { getDatastore } from './components'; +import { Compat } from '../../../src/compat/compat'; /** * A write batch, used to perform multiple writes as a single atomic unit. @@ -155,8 +156,13 @@ export class WriteBatch { this.verifyNotCommitted(); const ref = validateReference(documentRef, this._firestore); - let parsed; + // For Compat types, we have to "extract" the underlying types before + // performing validation. + if (fieldOrUpdateData instanceof Compat) { + fieldOrUpdateData = fieldOrUpdateData._delegate; + } + let parsed; if ( typeof fieldOrUpdateData === 'string' || fieldOrUpdateData instanceof FieldPath @@ -233,9 +239,12 @@ export class WriteBatch { } export function validateReference( - documentRef: DocumentReference, + documentRef: DocumentReference | Compat>, firestore: FirebaseFirestore ): DocumentReference { + if (documentRef instanceof Compat) { + documentRef = documentRef._delegate; + } if (documentRef.firestore !== firestore) { throw new FirestoreError( Code.INVALID_ARGUMENT, diff --git a/packages/firestore/src/api/database.ts b/packages/firestore/src/api/database.ts index 6874fd9b9f1..1513773167b 100644 --- a/packages/firestore/src/api/database.ts +++ b/packages/firestore/src/api/database.ts @@ -28,8 +28,7 @@ import { firestoreClientGetNamedQuery, firestoreClientListen, firestoreClientLoadBundle, - firestoreClientTransaction, - firestoreClientWrite + firestoreClientTransaction } from '../core/firestore_client'; import { Bound, @@ -59,7 +58,6 @@ import { Transaction as InternalTransaction } from '../core/transaction'; import { ViewSnapshot } from '../core/view_snapshot'; import { Document, MaybeDocument, NoDocument } from '../model/document'; import { DocumentKey } from '../model/document_key'; -import { DeleteMutation, Mutation, Precondition } from '../model/mutation'; import { FieldPath, ResourcePath } from '../model/path'; import { isServerTimestamp } from '../model/server_timestamps'; import { refValue } from '../model/values'; @@ -121,10 +119,12 @@ import { getDoc, onSnapshot, DocumentReference as ExpDocumentReference, - Query as ExpQuery + Query as ExpQuery, + executeWrite } from '../../exp/src/api/reference'; import { LRU_COLLECTION_DISABLED } from '../local/lru_garbage_collector'; import { Compat } from '../compat/compat'; +import { WriteBatch as ExpWriteBatch } from '../../exp/src/api/write_batch'; import { CollectionReference as PublicCollectionReference, @@ -403,7 +403,11 @@ export class Firestore batch(): PublicWriteBatch { ensureFirestoreConfigured(this._delegate); - return new WriteBatch(this); + return new WriteBatch( + new ExpWriteBatch(this._delegate, mutations => + executeWrite(this._delegate, mutations) + ) + ); } } @@ -637,15 +641,9 @@ export class Transaction implements PublicTransaction { } } -export class WriteBatch implements PublicWriteBatch { - private _mutations = [] as Mutation[]; - private _committed = false; - private _dataReader: UserDataReader; - - constructor(private _firestore: Firestore) { - this._dataReader = newUserDataReader(this._firestore._delegate); - } - +export class WriteBatch + extends Compat + implements PublicWriteBatch { set( documentRef: DocumentReference, data: Partial, @@ -654,38 +652,22 @@ export class WriteBatch implements PublicWriteBatch { set(documentRef: DocumentReference, data: T): WriteBatch; set( documentRef: PublicDocumentReference, - value: T | Partial, + data: T | Partial, options?: PublicSetOptions ): WriteBatch { - this.verifyNotCommitted(); - const ref = validateReference( - 'WriteBatch.set', - documentRef, - this._firestore - ); - options = validateSetOptions('WriteBatch.set', options); - const convertedValue = applyFirestoreDataConverter( - ref._converter, - value, - options - ); - const parsed = parseSetData( - this._dataReader, - 'WriteBatch.set', - ref._key, - convertedValue, - ref._converter !== null, - options - ); - this._mutations = this._mutations.concat( - parsed.toMutations(ref._key, Precondition.none()) - ); + const ref = castReference(documentRef); + if (options) { + validateSetOptions('WriteBatch.set', options); + this._delegate.set(ref, data, options); + } else { + this._delegate.set(ref, data); + } return this; } update( documentRef: PublicDocumentReference, - value: PublicUpdateData + data: PublicUpdateData ): WriteBatch; update( documentRef: PublicDocumentReference, @@ -695,83 +677,32 @@ export class WriteBatch implements PublicWriteBatch { ): WriteBatch; update( documentRef: PublicDocumentReference, - fieldOrUpdateData: string | PublicFieldPath | PublicUpdateData, + dataOrField: string | PublicFieldPath | PublicUpdateData, value?: unknown, ...moreFieldsAndValues: unknown[] ): WriteBatch { - this.verifyNotCommitted(); - const ref = validateReference( - 'WriteBatch.update', - documentRef, - this._firestore - ); - - // For Compat types, we have to "extract" the underlying types before - // performing validation. - if (fieldOrUpdateData instanceof Compat) { - fieldOrUpdateData = (fieldOrUpdateData as Compat)._delegate; - } - - let parsed; - if ( - typeof fieldOrUpdateData === 'string' || - fieldOrUpdateData instanceof ExpFieldPath - ) { - parsed = parseUpdateVarargs( - this._dataReader, - 'WriteBatch.update', - ref._key, - fieldOrUpdateData, - value, - moreFieldsAndValues - ); + const ref = castReference(documentRef); + if (arguments.length === 2) { + this._delegate.update(ref, dataOrField as PublicUpdateData); } else { - parsed = parseUpdateData( - this._dataReader, - 'WriteBatch.update', - ref._key, - fieldOrUpdateData + this._delegate.update( + ref, + dataOrField as string | ExpFieldPath, + value, + ...moreFieldsAndValues ); } - - this._mutations = this._mutations.concat( - parsed.toMutations(ref._key, Precondition.exists(true)) - ); return this; } delete(documentRef: PublicDocumentReference): WriteBatch { - this.verifyNotCommitted(); - const ref = validateReference( - 'WriteBatch.delete', - documentRef, - this._firestore - ); - this._mutations = this._mutations.concat( - new DeleteMutation(ref._key, Precondition.none()) - ); + const ref = castReference(documentRef); + this._delegate.delete(ref); return this; } commit(): Promise { - this.verifyNotCommitted(); - this._committed = true; - if (this._mutations.length > 0) { - const client = ensureFirestoreConfigured(this._firestore._delegate); - return firestoreClientWrite(client, this._mutations); - } - - return Promise.resolve(); - } - - private verifyNotCommitted(): void { - if (this._committed) { - throw new FirestoreError( - Code.FAILED_PRECONDITION, - 'A write batch can no longer be used after commit() ' + - 'has been called.' - ); - } + return this._delegate.commit(); } } @@ -2016,6 +1947,15 @@ export class CollectionReference } } +function castReference( + documentRef: PublicDocumentReference +): ExpDocumentReference { + if (documentRef instanceof Compat) { + documentRef = documentRef._delegate; + } + return cast>(documentRef, ExpDocumentReference); +} + function validateReference( methodName: string, documentRef: PublicDocumentReference,