Expand description
ORM-agnostic seam for the request/job data layer.
nest-rs-database ships only the seam: the Executor trait, the
ExecutorScope tag, and the tokio::task_local! plumbing
(with_request_executor, with_job_executor, current_executor,
current_executor_scope) that carries “the request’s current handle
on a unit of work” across the framework. It is what every ORM
integration plugs into — not an ORM itself. The non-HTTP side is wired
through nest_rs_worker::JobContext, which a worker transport
(#[scheduled], #[processor]) resolves before each job.
The first-class implementation is nest-rs-seaorm (SeaORM): it ships
Repo (row-level filter), CrudService, Bind, the HTTP mask
shaper, and DatabaseModule (the request interceptor that opens the
transaction). Those pieces are SeaORM-specific by design — the
leverage comes from binding tightly to the ORM’s query/model types.
A future third-party nest-rs-<other-orm> crate (sqlx, diesel,
prisma-client-rust, mongo, …) can plug a different engine into the
same ambient seam without touching nest-rs-core or any feature code.
§Extension contract
To add a new ORM:
- Implement
Executoron the type that represents your handle (a pool, a transaction, or an enum forwarding to either). - Ship a
Modulethat, for each HTTP request, wraps the handler inwith_request_executorpassing yourArc<dyn Executor>. For worker transports do the same withwith_job_executorvianest_rs_worker::JobContext. - Provide your own
Repo-equivalent query API that callscurrent_executorand downcasts to your concrete type.
The SeaORM-specific pieces (Repo, condition_for, the mask shaper,
Bind<S, A>, CrudService) are unreachable from your implementation —
that is intentional. They couple to SeaORM’s EntityTrait/Model; a
generic abstraction over them would lose 80% of their value. A new ORM
integration ships its own row-level-filter equivalent.
Enums§
- Executor
Scope - Whether the ambient executor belongs to a request or a worker job. An
ORM’s
Reporeads this back to fail closed when a request path lacks an ambient authorization context (a missing principal on a worker is expected — it’s system work; on a request it’s a bug).
Traits§
- Executor
- An ambient handle to a unit of database work, installed in the task-local for the lifetime of a request or a worker job.
Functions§
- current_
executor - The installed ambient executor, or
Noneoutside any scope. An ORM-specificRepocalls this and downcasts viaExecutor::as_any. - current_
executor_ scope - The installed ambient executor scope, or
Noneoutside any scope. - with_
executor - Install
executorwithout tagging a scope. Prefer the request/job variants at framework boundaries so authorization can distinguish the two paths. An untagged (unset) scope is treated as fail-closed by a scope-awareRepo: with no ambient ability it denies every row, exactly like a request — onlywith_job_executorgrants unscoped reads. - with_
job_ executor - Install
executorand tag the scope as a worker job — the path on which aReporuns unscoped (no principal ⇒ system work). - with_
request_ executor - Install
executorand tag the scope as a request — the path on which aRepofails closed when no ambient authorization context is present.