From e2a90bf678eb6fa505f8b2f627e03cff622607b5 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Fri, 28 Oct 2022 08:41:54 -0700 Subject: [PATCH] Fix transaction.set() failure without retry on "already-exists" error (#6729) --- .changeset/young-knives-shake.md | 6 +++++ .../firestore/src/core/transaction_runner.ts | 1 + .../test/integration/api/transactions.test.ts | 24 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 .changeset/young-knives-shake.md diff --git a/.changeset/young-knives-shake.md b/.changeset/young-knives-shake.md new file mode 100644 index 00000000000..3b3813ae018 --- /dev/null +++ b/.changeset/young-knives-shake.md @@ -0,0 +1,6 @@ +--- +'@firebase/firestore': patch +'firebase': patch +--- + +Fix transaction.set() failure without retry on "already-exists" error. diff --git a/packages/firestore/src/core/transaction_runner.ts b/packages/firestore/src/core/transaction_runner.ts index 30ef5ea0b32..d9e679321b5 100644 --- a/packages/firestore/src/core/transaction_runner.ts +++ b/packages/firestore/src/core/transaction_runner.ts @@ -120,6 +120,7 @@ export class TransactionRunner { return ( code === 'aborted' || code === 'failed-precondition' || + code === 'already-exists' || !isPermanentError(code) ); } diff --git a/packages/firestore/test/integration/api/transactions.test.ts b/packages/firestore/test/integration/api/transactions.test.ts index 3c26f085042..6126e9f9cb8 100644 --- a/packages/firestore/test/integration/api/transactions.test.ts +++ b/packages/firestore/test/integration/api/transactions.test.ts @@ -629,6 +629,30 @@ apiDescribe('Database transactions', (persistence: boolean) => { }); }); + it('retries when document already exists', () => { + return withTestDb(persistence, async db => { + let retryCounter = 0; + const docRef = doc(collection(db, 'nonexistent')); + + await runTransaction(db, async transaction => { + ++retryCounter; + const snap = await transaction.get(docRef); + + if (retryCounter === 1) { + expect(snap.exists()).to.be.false; + // On the first attempt, create a doc before transaction.set(), so that + // the transaction fails with "already-exists" error, and retries. + await setDoc(docRef, { count: 1 }); + } + + transaction.set(docRef, { count: 2 }); + }); + expect(retryCounter).to.equal(2); + const snap = await getDoc(docRef); + expect(snap.get('count')).to.equal(2); + }); + }); + it('are successful with no transaction operations', () => { return withTestDb(persistence, db => runTransaction(db, async () => {})); });