Skip to content

feat: add transaction and write batch support - #55

Merged
fwal merged 2 commits into
mainfrom
claude/transaction-support-2atfs1
Jul 20, 2026
Merged

feat: add transaction and write batch support#55
fwal merged 2 commits into
mainfrom
claude/transaction-support-2atfs1

Conversation

@fwal

@fwal fwal commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

Adds Firestore transaction and write batch support across all packages via two new FirestoreService combinators:

Firestore.withTransaction(
  Effect.gen(function* () {
    const repo = yield* AccountRepository;
    const account = yield* repo.getById(id); // transactional read
    yield* repo.update(id, { balance });     // transactional write
  })
);

Firestore.withBatch(
  Effect.forEach(ids, (id) => repo.update(id, { status: 'archived' }))
);

Design

Reads and writes are routed through fiber-local Context.References (CurrentTransaction / CurrentBatch) that each SDK layer consults at call time. Since repositories capture the FirestoreService instance at construction, this is the only routing strategy that lets existing repositories participate in transactions with zero changes — the same pattern @effect/sql uses for withTransaction.

  • effect-firebase: withTransaction/withBatch on FirestoreServiceShape, user-facing Firestore.withTransaction/Firestore.withBatch helpers, noop layer support
  • @effect-firebase/admin: transactions via db.runTransaction, batches via db.batch(); add pre-allocates a ref and uses tx.create; queries run through tx.get(query)
  • @effect-firebase/client: same via runTransaction/writeBatch; add uses tx.set (client SDK has no create); query dies inside a transaction (client SDK only supports document reads)
  • @effect-firebase/mock: pass-through defaults (no concurrency to protect against)

Semantics

  • A failing effect rolls the transaction back and re-surfaces the typed error: the inner effect runs to Exit inside the runTransaction callback, failures are thrown as an internal wrapper to abort the SDK transaction, and the original Exit is resumed outside the promise boundary. Interruption of the outer fiber is wired through the abort signal.
  • Nested withTransaction/withBatch join the ambient one; withBatch inside a transaction routes writes to the transaction.
  • Batches are write-only: reads inside withBatch execute immediately and do not see staged writes.
  • Guard rails: streamDoc, streamQuery, and deleteRecursive die inside a transaction (deleteRecursive also inside a batch) instead of silently bypassing it.

Caveats (documented on the API)

  • Firestore may retry the transaction on contention, so the wrapped effect can run more than once.
  • All transactional reads must happen before the first write (Firestore rule, surfaces as FirestoreError at runtime).

Testing

  • 15 admin tests against a stubbed Firestore covering routing, commit/rollback, typed-failure propagation, join semantics, and defect guards
  • 10 client tests via vi.mock('firebase/firestore') covering the same plus client-specific restrictions
  • 2 core tests for helper delegation
  • Full workspace: 234 tests passing, build and lint clean on effect 4.0.0-beta.99

🤖 Generated with Claude Code

https://claude.ai/code/session_01LJB3ye9tLX17ar4rFSSLYi


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added Firestore transaction and batch helpers for atomic updates and grouped writes.
    • Nested transactions and batches now reuse the active operation context.
    • Writes are staged and committed only after successful completion; failed operations do not commit.
    • Added public API support and no-op behavior for mock Firestore services.
  • Documentation

    • Added usage examples and guidance for transactions, batches, limitations, retries, and write limits.
  • Tests

    • Added comprehensive coverage for transaction, batch, nesting, failure, and direct-operation behavior.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@fwal, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 14 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a5f2647f-f540-4a4f-9ff7-f2b44f4d19c3

📥 Commits

Reviewing files that changed from the base of the PR and between e7d3f31 and 5d0c81f.

📒 Files selected for processing (13)
  • README.md
  • packages/admin/src/lib/firestore/firestore-service.spec.ts
  • packages/admin/src/lib/firestore/firestore-service.ts
  • packages/client/src/lib/firestore/firestore-service.spec.ts
  • packages/client/src/lib/firestore/firestore-service.ts
  • packages/effect-firebase/README.md
  • packages/effect-firebase/src/lib/firestore/firestore-service.ts
  • packages/effect-firebase/src/lib/firestore/firestore.ts
  • packages/effect-firebase/src/lib/firestore/noop-layer.ts
  • packages/effect-firebase/src/lib/firestore/transaction.spec.ts
  • packages/effect-firebase/src/lib/firestore/transaction.ts
  • packages/mock/README.md
  • packages/mock/src/lib/firestore/firestore-service.ts
📝 Walkthrough

Walkthrough

Firestore transaction and batch support was added to the public API, client and admin services, mock service, tests, and documentation. Operations now use fiber-local routing, preserve typed failures, support nesting, and enforce transaction and batch restrictions.

Changes

Firestore transactions and batches

Layer / File(s) Summary
Transaction and batch API surface
packages/effect-firebase/src/lib/firestore/..., packages/mock/..., README.md, packages/effect-firebase/README.md
Adds public withTransaction and withBatch helpers, service capabilities, fallback implementations, mock passthroughs, examples, and API documentation.
Ambient transaction and batch routing
packages/client/src/lib/firestore/firestore-service.ts, packages/admin/src/lib/firestore/firestore-service.ts
Routes reads and writes through active transactions or batches, supports nested contexts, preserves typed failures, and rejects unsupported operations.
Routing and failure coverage
packages/client/src/lib/firestore/firestore-service.spec.ts, packages/admin/src/lib/firestore/firestore-service.spec.ts, packages/effect-firebase/src/lib/firestore/transaction.spec.ts
Tests direct access, transaction and batch routing, nesting, commits, failures, restrictions, and helper delegation.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Application
  participant FirestoreService
  participant FirestoreSDK
  Application->>FirestoreService: withTransaction(effect) or withBatch(effect)
  FirestoreService->>FirestoreSDK: runTransaction(callback) or writeBatch()
  Application->>FirestoreService: repository reads and writes
  FirestoreService->>FirestoreSDK: route reads or stage writes
  FirestoreSDK-->>FirestoreService: transaction result or batch commit
  FirestoreService-->>Application: effect result or typed failure
Loading

Poem

I’m a rabbit with writes in a row,
Through transactions they safely go.
Batches wait, then commit as one,
Nested paths join the work begun.
Typed failures hop, then rest—
Firestore now passes the test!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding Firestore transaction and write batch support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@fwal fwal added this to the 1.0 - Effect v4 milestone Jul 19, 2026
@fwal fwal self-assigned this Jul 19, 2026
@fwal
fwal changed the base branch from next to main July 19, 2026 13:22
@fwal fwal added the 🚀 feature A new feature or larger change label Jul 19, 2026
@fwal
fwal marked this pull request as ready for review July 19, 2026 14:11
Adds withTransaction and withBatch to FirestoreService, routed through
fiber-local Context.References (CurrentTransaction/CurrentBatch) so all
reads and writes — including those made through repositories — are
transparently redirected to the active transaction or batch.

- effect-firebase: extend FirestoreServiceShape, add
  Firestore.withTransaction / Firestore.withBatch helpers, noop layer
- @effect-firebase/admin: transactions via db.runTransaction (typed
  failures roll back and propagate), batches via db.batch; queries run
  through transaction.get; streams and deleteRecursive die inside a
  transaction
- @effect-firebase/client: same via runTransaction/writeBatch; queries
  also die inside a transaction (client SDK supports document reads only)
- @effect-firebase/mock: pass-through defaults
- Nested withTransaction/withBatch join the ambient one; withBatch inside
  a transaction routes writes to the transaction

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJB3ye9tLX17ar4rFSSLYi

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/effect-firebase/src/lib/firestore/transaction.ts`:
- Around line 27-38: Update the JSDoc transaction example to derive the new
balances from the defined source and target objects, replacing the undefined
sourceBalance and targetBalance references while preserving the existing
repository update calls.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1cf531f2-788b-4da6-adc1-46948da8f7bb

📥 Commits

Reviewing files that changed from the base of the PR and between dd31795 and e7d3f31.

📒 Files selected for processing (13)
  • README.md
  • packages/admin/src/lib/firestore/firestore-service.spec.ts
  • packages/admin/src/lib/firestore/firestore-service.ts
  • packages/client/src/lib/firestore/firestore-service.spec.ts
  • packages/client/src/lib/firestore/firestore-service.ts
  • packages/effect-firebase/README.md
  • packages/effect-firebase/src/lib/firestore/firestore-service.ts
  • packages/effect-firebase/src/lib/firestore/firestore.ts
  • packages/effect-firebase/src/lib/firestore/noop-layer.ts
  • packages/effect-firebase/src/lib/firestore/transaction.spec.ts
  • packages/effect-firebase/src/lib/firestore/transaction.ts
  • packages/mock/README.md
  • packages/mock/src/lib/firestore/firestore-service.ts

Comment thread packages/effect-firebase/src/lib/firestore/transaction.ts
@fwal
fwal force-pushed the claude/transaction-support-2atfs1 branch from e7d3f31 to c6934e1 Compare July 19, 2026 14:20
@fwal fwal mentioned this pull request Jul 19, 2026
@fwal

fwal commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@fwal
fwal merged commit f7ce213 into main Jul 20, 2026
5 checks passed
@fwal
fwal deleted the claude/transaction-support-2atfs1 branch July 20, 2026 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🚀 feature A new feature or larger change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants