Skip to content

Add request-scoped transaction wrappers to Tango host adapters #44

@danceroutine

Description

@danceroutine

Summary

Tango's core transaction boundary is now solid: transaction.atomic(async (tx) => ...) supports nested savepoints and post-commit work.

The next ergonomics gap is that adapters still hand requests directly to viewsets/APIViews without any first-class request-scoped transaction wrapper. Applications have to decide and wire this policy themselves even when they want a uniform request-level unit of work.

Current codebase context

  • packages/orm/src/transaction/atomic.ts exposes the application-facing atomic API against the default runtime.
  • packages/orm/src/transaction/internal/context/AsyncLocalTransactionEngine.ts already owns request-local transaction state once a transaction exists.
  • packages/adapters/express/src/adapter/ExpressAdapter.ts, packages/adapters/next/src/adapter/NextAdapter.ts, and packages/adapters/nuxt/src/adapter/NuxtAdapter.ts adapt handlers directly and do not offer a transaction wrapper option.
  • Runtime-bound managers already enroll in an active transaction.atomic(...) boundary when one exists.

Problem

A large class of applications wants one of these policies:

  • wrap mutating requests in a transaction automatically
  • wrap all resource dispatches in one transaction boundary
  • opt in per route/viewset/action to request-level atomicity

Right now Tango has the low-level primitive but not the adapter-level ergonomic path.

Proposed implementation plan

  1. Define the adapter-facing policy surface.
    • Decide whether the feature is global, per-adapter, per-route, or per-viewset/action.
    • Preserve an opt-in path so frameworks with their own transaction policies are not forced into one mode.
  2. Implement adapter-level wrappers.
    • Extend the three host adapters with a shared option or helper that runs the adapted handler inside transaction.atomic(...).
    • Keep host-specific error propagation and response handling intact.
  3. Clarify scope and lifecycle semantics.
    • Decide how post-commit callbacks, streaming responses, and non-mutating endpoints should behave.
    • Ensure nested atomic usage inside handlers remains valid.
  4. Add tests and docs.
    • Cover success, rollback, nested usage, and adapter parity across Express, Next, and Nuxt.

Acceptance criteria

  • Tango adapters expose a documented, opt-in way to run request handling inside transaction.atomic(...).
  • The contract works consistently across Express, Next, and Nuxt.
  • Rollback and post-commit behavior are covered by tests.
  • Nested transactional work inside handlers remains correct.
  • Docs explain when to use request-scoped wrapping versus explicit local atomic(...) blocks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions