Skip to content

fix: manual transaction support in local-only collections#723

Closed
marbemac wants to merge 2 commits intoTanStack:mainfrom
marbemac:mbm/local-manual-transactions-fix
Closed

fix: manual transaction support in local-only collections#723
marbemac wants to merge 2 commits intoTanStack:mainfrom
marbemac:mbm/local-manual-transactions-fix

Conversation

@marbemac
Copy link
Contributor

fixes #722

🎯 Changes

Fixed an issue where acceptMutations() wasn't working for manual transactions with local-only collections. The data would appear optimistically but then disappear after the transaction committed.

When filtering mutations to find ones belonging to the collection, it was comparing against syncResult.collection, which is null at the time acceptMutations is called. This is because the collection reference gets set during the sync callback, but utils aren't assigned to the collection until after construction completes. So all mutations were being filtered out and nothing was persisted.

To resolve this, I updated the mutation filtering to compare function references instead.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

@changeset-bot
Copy link

changeset-bot bot commented Oct 25, 2025

🦋 Changeset detected

Latest commit: 44783ab

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@tanstack/db Patch
@tanstack/angular-db Patch
@tanstack/electric-db-collection Patch
@tanstack/offline-transactions Patch
@tanstack/powersync-db-collection Patch
@tanstack/query-db-collection Patch
@tanstack/react-db Patch
@tanstack/rxdb-db-collection Patch
@tanstack/solid-db Patch
@tanstack/svelte-db Patch
@tanstack/trailbase-db-collection Patch
@tanstack/vue-db Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 25, 2025

More templates

@tanstack/angular-db

npm i https://pkg.pr.new/@tanstack/angular-db@723

@tanstack/db

npm i https://pkg.pr.new/@tanstack/db@723

@tanstack/db-ivm

npm i https://pkg.pr.new/@tanstack/db-ivm@723

@tanstack/electric-db-collection

npm i https://pkg.pr.new/@tanstack/electric-db-collection@723

@tanstack/offline-transactions

npm i https://pkg.pr.new/@tanstack/offline-transactions@723

@tanstack/powersync-db-collection

npm i https://pkg.pr.new/@tanstack/powersync-db-collection@723

@tanstack/query-db-collection

npm i https://pkg.pr.new/@tanstack/query-db-collection@723

@tanstack/react-db

npm i https://pkg.pr.new/@tanstack/react-db@723

@tanstack/rxdb-db-collection

npm i https://pkg.pr.new/@tanstack/rxdb-db-collection@723

@tanstack/solid-db

npm i https://pkg.pr.new/@tanstack/solid-db@723

@tanstack/svelte-db

npm i https://pkg.pr.new/@tanstack/svelte-db@723

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/@tanstack/trailbase-db-collection@723

@tanstack/vue-db

npm i https://pkg.pr.new/@tanstack/vue-db@723

commit: 44783ab

@marbemac
Copy link
Contributor Author

Actually this might affect local only collection mutations in general (not just via manual transactions).

@KyleAMathews
Copy link
Collaborator

So it turns out we solved this in a different way in local-storage.ts — which seems a bit less fragile than this:

// local-storage.ts:503-510
const collectionMutations = transaction.mutations.filter((m) => {
  // Try to match by collection reference first
  if (sync.collection && m.collection === sync.collection) {
    return true
  }
  // Fall back to matching by collection ID
  return m.collection.id === collectionId
})

@marbemac
Copy link
Contributor Author

So it turns out we solved this in a different way in local-storage.ts

Yeah I noticed this, but this works because local storage has a much stronger guarantee of a unique id to operate off of. Since storageKey is required, it falls back to that if the user did not provide the optional collection id. The local collection has no such guarantee.

// Default id to a pattern based on storage key if not provided
const collectionId = id ?? `local-collection:${config.storageKey}`

@KyleAMathews
Copy link
Collaborator

All collections have stable ids though — if one isn't passed, a UUID is generated.

@marbemac
Copy link
Contributor Author

Ah ok I missed that! Will take a look today

@marbemac marbemac force-pushed the mbm/local-manual-transactions-fix branch 3 times, most recently from 1626573 to fc100e1 Compare October 27, 2025 19:06
const { initialData, onInsert, onUpdate, onDelete, id, ...restConfig } =
config

const collectionId = id ?? crypto.randomUUID()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KyleAMathews ok updated with the uuid approach. As far as I can tell, the id automatically generated by the base collection impl is not available in time for use in the collection filtering below, so I had to generate it here.

@marbemac marbemac force-pushed the mbm/local-manual-transactions-fix branch 2 times, most recently from bc06349 to b7f0213 Compare December 12, 2025 16:43
Signed-off-by: Marc MacLeod <marbemac+gh@gmail.com>

fix: local collection manual transactions

Signed-off-by: Marc MacLeod <marbemac+gh@gmail.com>
@marbemac marbemac force-pushed the mbm/local-manual-transactions-fix branch from b7f0213 to 58b55c8 Compare December 12, 2025 16:43
Copy link
Contributor

@kevin-dp kevin-dp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me.

@kevin-dp
Copy link
Contributor

Thanks @marbemac for your PR. I've forked your branch and opened a new PR because i couldn't make changes here. So i'm closing in favor of: #1253

@kevin-dp kevin-dp closed this Feb 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local collection manual transaction does not work

3 participants