From 535e5b482763c0ec419d2faa3e9e92e3236498ab Mon Sep 17 00:00:00 2001 From: Marc MacLeod Date: Sat, 25 Oct 2025 16:18:54 -0500 Subject: [PATCH 1/3] fix: local collection manual transactions Signed-off-by: Marc MacLeod fix: local collection manual transactions Signed-off-by: Marc MacLeod --- .changeset/metal-results-float.md | 5 ++++ packages/db/src/local-only.ts | 10 ++++---- packages/db/tests/local-only.test.ts | 35 +++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 .changeset/metal-results-float.md diff --git a/.changeset/metal-results-float.md b/.changeset/metal-results-float.md new file mode 100644 index 000000000..24262c800 --- /dev/null +++ b/.changeset/metal-results-float.md @@ -0,0 +1,5 @@ +--- +'@tanstack/db': patch +--- + +Fixed local collection manual transactions diff --git a/packages/db/src/local-only.ts b/packages/db/src/local-only.ts index 642e286d7..9c3bef322 100644 --- a/packages/db/src/local-only.ts +++ b/packages/db/src/local-only.ts @@ -179,7 +179,10 @@ export function localOnlyCollectionOptions< ): LocalOnlyCollectionOptionsResult & { schema?: StandardSchemaV1 } { - const { initialData, onInsert, onUpdate, onDelete, ...restConfig } = config + const { initialData, onInsert, onUpdate, onDelete, id, ...restConfig } = + config + + const collectionId = id ?? crypto.randomUUID() // Create the sync configuration with transaction confirmation capability const syncResult = createLocalOnlySync(initialData) @@ -247,9 +250,7 @@ export function localOnlyCollectionOptions< }) => { // Filter mutations that belong to this collection const collectionMutations = transaction.mutations.filter( - (m) => - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - m.collection === syncResult.collection, + (m) => m.collection.id === collectionId ) if (collectionMutations.length === 0) { @@ -264,6 +265,7 @@ export function localOnlyCollectionOptions< return { ...restConfig, + id: collectionId, sync: syncResult.sync, onInsert: wrappedOnInsert, onUpdate: wrappedOnUpdate, diff --git a/packages/db/tests/local-only.test.ts b/packages/db/tests/local-only.test.ts index 1eb8ac0b5..0dd841a27 100644 --- a/packages/db/tests/local-only.test.ts +++ b/packages/db/tests/local-only.test.ts @@ -481,7 +481,7 @@ describe(`LocalOnly Collection`, () => { }) describe(`Manual transactions with acceptMutations`, () => { - it(`should accept and persist mutations from manual transactions`, () => { + it(`should accept and persist mutations from manual transactions`, async () => { const tx = createTransaction({ mutationFn: async ({ transaction }: any) => { // Simulate API call success @@ -510,6 +510,39 @@ describe(`LocalOnly Collection`, () => { id: 101, name: `Manual Tx Insert 2`, }) + + // Verify that the item is still present after async operations complete + await new Promise((resolve) => setTimeout(resolve, 1)) + expect(collection.get(100)).toEqual({ id: 100, name: `Manual Tx Insert` }) + }) + + it(`should work without explicit collection ID`, async () => { + // Create a collection without an explicit ID + const noIdCollection = createCollection< + TestItem, + number, + LocalOnlyCollectionUtils + >( + localOnlyCollectionOptions({ + getKey: (item) => item.id, + }), + ) + + const tx = createTransaction({ + mutationFn: async ({ transaction }: any) => { + noIdCollection.utils.acceptMutations(transaction) + }, + autoCommit: false, + }) + + tx.mutate(() => { + noIdCollection.insert({ id: 999, name: `No ID Test` }) + }) + + await tx.commit() + + // Data should persist even without explicit ID + expect(noIdCollection.get(999)).toEqual({ id: 999, name: `No ID Test` }) }) it(`should only accept mutations for the specific collection`, () => { From 3fe94333156a33b62c3904462d75015965909551 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 16:44:38 +0000 Subject: [PATCH 2/3] ci: apply automated fixes --- packages/db/src/local-only.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/db/src/local-only.ts b/packages/db/src/local-only.ts index 9c3bef322..27332c910 100644 --- a/packages/db/src/local-only.ts +++ b/packages/db/src/local-only.ts @@ -250,7 +250,7 @@ export function localOnlyCollectionOptions< }) => { // Filter mutations that belong to this collection const collectionMutations = transaction.mutations.filter( - (m) => m.collection.id === collectionId + (m) => m.collection.id === collectionId, ) if (collectionMutations.length === 0) { From 5594da5980e680c9c8a179e64a6f816a97451416 Mon Sep 17 00:00:00 2001 From: Kevin De Porre Date: Tue, 17 Feb 2026 11:11:03 +0100 Subject: [PATCH 3/3] docs: improve changeset description Co-Authored-By: Claude Opus 4.6 --- .changeset/metal-results-float.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/metal-results-float.md b/.changeset/metal-results-float.md index 24262c800..2c0b8e6f1 100644 --- a/.changeset/metal-results-float.md +++ b/.changeset/metal-results-float.md @@ -2,4 +2,4 @@ '@tanstack/db': patch --- -Fixed local collection manual transactions +Fixed `acceptMutations` not persisting data in local-only collections with manual transactions. The mutation filter was comparing against a stale `null` collection reference instead of using the collection ID, causing all mutations to be silently dropped after the transaction's `mutationFn` resolved.