diff --git a/.changeset/eleven-towns-carry.md b/.changeset/eleven-towns-carry.md new file mode 100644 index 000000000..4333b572a --- /dev/null +++ b/.changeset/eleven-towns-carry.md @@ -0,0 +1,5 @@ +--- +"@tanstack/electric-db-collection": patch +--- + +fix the handling of an electric must-refetch message so that the truncate is handled in the same transaction as the next up-to-date, ensuring you don't get a momentary empty collection. diff --git a/packages/electric-db-collection/src/electric.ts b/packages/electric-db-collection/src/electric.ts index a89331700..6655020c4 100644 --- a/packages/electric-db-collection/src/electric.ts +++ b/packages/electric-db-collection/src/electric.ts @@ -476,17 +476,27 @@ function createElectricSync>( return { sync: (params: Parameters[`sync`]>[0]) => { - const { begin, write, commit, markReady, truncate } = params + const { begin, write, commit, markReady, truncate, collection } = params const stream = new ShapeStream({ ...shapeOptions, signal: abortController.signal, onError: (errorParams) => { // Just immediately mark ready if there's an error to avoid blocking // apps waiting for `.preload()` to finish. + // Note that Electric sends a 409 error on a `must-refetch` message, but the + // ShapeStream handled this and it will not reach this handler, therefor + // this markReady will not be triggers by a `must-refetch`. markReady() if (shapeOptions.onError) { return shapeOptions.onError(errorParams) + } else { + console.error( + `An error occurred while syncing collection: ${collection.id}, \n` + + `it has been marked as ready to avoid blocking apps waiting for '.preload()' to finish. \n` + + `You can provide an 'onError' handler on the shapeOptions to handle this error, and this message will not be logged.`, + errorParams + ) } return @@ -540,9 +550,8 @@ function createElectricSync>( truncate() - // Commit the truncate transaction immediately - commit() - transactionStarted = false + // Reset hasUpToDate so we continue accumulating changes until next up-to-date + hasUpToDate = false } } diff --git a/packages/electric-db-collection/tests/electric.test.ts b/packages/electric-db-collection/tests/electric.test.ts index e8167efbb..6ea0c1b1b 100644 --- a/packages/electric-db-collection/tests/electric.test.ts +++ b/packages/electric-db-collection/tests/electric.test.ts @@ -254,8 +254,10 @@ describe(`Electric Integration`, () => { }, ]) - // The collection should be cleared but remain in ready state - expect(collection.state.size).toBe(0) + // The collection should still have old data because truncate is in pending + // transaction. This is the intended behavior of the collection, you should have + // the old data until the next up-to-date message. + expect(collection.state.size).toBe(2) expect(collection.status).toBe(`ready`) // Send new data after must-refetch