#[non_exhaustive]pub struct MutationContext {
pub auth: AuthContext,
pub request: RequestMetadata,
/* private fields */
}Expand description
Context for mutation functions (transactional database access).
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.auth: AuthContext§request: RequestMetadataImplementations§
Source§impl MutationContext
impl MutationContext
Sourcepub fn new(db_pool: PgPool, auth: AuthContext, request: RequestMetadata) -> Self
pub fn new(db_pool: PgPool, auth: AuthContext, request: RequestMetadata) -> Self
Create a new mutation context.
Sourcepub fn with_dispatch(
db_pool: PgPool,
auth: AuthContext,
request: RequestMetadata,
http_client: CircuitBreakerClient,
job_dispatch: Option<Arc<dyn JobDispatch>>,
workflow_dispatch: Option<Arc<dyn WorkflowDispatch>>,
) -> Self
pub fn with_dispatch( db_pool: PgPool, auth: AuthContext, request: RequestMetadata, http_client: CircuitBreakerClient, job_dispatch: Option<Arc<dyn JobDispatch>>, workflow_dispatch: Option<Arc<dyn WorkflowDispatch>>, ) -> Self
Create a mutation context with dispatch capabilities.
Sourcepub fn with_env(
db_pool: PgPool,
auth: AuthContext,
request: RequestMetadata,
http_client: CircuitBreakerClient,
job_dispatch: Option<Arc<dyn JobDispatch>>,
workflow_dispatch: Option<Arc<dyn WorkflowDispatch>>,
env_provider: Arc<dyn EnvProvider>,
) -> Self
pub fn with_env( db_pool: PgPool, auth: AuthContext, request: RequestMetadata, http_client: CircuitBreakerClient, job_dispatch: Option<Arc<dyn JobDispatch>>, workflow_dispatch: Option<Arc<dyn WorkflowDispatch>>, env_provider: Arc<dyn EnvProvider>, ) -> Self
Create a mutation context with a custom environment provider.
Sourcepub fn with_transaction(
db_pool: PgPool,
tx: Transaction<'static, Postgres>,
auth: AuthContext,
request: RequestMetadata,
http_client: CircuitBreakerClient,
job_dispatch: Option<Arc<dyn JobDispatch>>,
workflow_dispatch: Option<Arc<dyn WorkflowDispatch>>,
) -> (Self, Arc<AsyncMutex<Option<Transaction<'static, Postgres>>>>)
pub fn with_transaction( db_pool: PgPool, tx: Transaction<'static, Postgres>, auth: AuthContext, request: RequestMetadata, http_client: CircuitBreakerClient, job_dispatch: Option<Arc<dyn JobDispatch>>, workflow_dispatch: Option<Arc<dyn WorkflowDispatch>>, ) -> (Self, Arc<AsyncMutex<Option<Transaction<'static, Postgres>>>>)
Build a transactional mutation context.
Jobs/workflows dispatched through the returned context insert their
rows directly on tx, so they commit atomically with the mutation
and are rolled back on failure.
The caller retains ownership of the transaction via the returned handle; commit it after the handler returns successfully.
Sourcepub fn set_kv(&mut self, kv: Arc<dyn KvHandle>)
pub fn set_kv(&mut self, kv: Arc<dyn KvHandle>)
Attach a KV store handle. Called by the runtime before handing the context to the handler.
Sourcepub fn kv(&self) -> Result<&dyn KvHandle>
pub fn kv(&self) -> Result<&dyn KvHandle>
Access the KV store.
Returns an error if the runtime did not supply a KV handle (this should
not happen in production; it can only occur in unit tests that construct
a bare MutationContext without going through the runtime).
Sourcepub fn set_email(&mut self, sender: Arc<dyn EmailSender>)
pub fn set_email(&mut self, sender: Arc<dyn EmailSender>)
Attach an email sender.
Sourcepub fn email(&self) -> Result<&dyn EmailSender>
pub fn email(&self) -> Result<&dyn EmailSender>
Access the email sender.
pub fn is_transactional(&self) -> bool
Sourcepub async fn conn(&self) -> Result<ForgeConn<'_>>
pub async fn conn(&self) -> Result<ForgeConn<'_>>
Acquire a connection compatible with sqlx compile-time checked macros.
In transactional mode, returns a guard over the active transaction. Otherwise acquires a fresh connection from the pool.
let mut conn = ctx.conn().await?;
sqlx::query_as!(User, "INSERT INTO users ... RETURNING *", ...)
.fetch_one(&mut *conn)
.await?Sourcepub fn bypass_pool(&self) -> &PgPool
pub fn bypass_pool(&self) -> &PgPool
Direct pool access that bypasses the active transaction.
In a transactional mutation, this returns the raw sqlx::PgPool and
any queries run on it execute outside the transaction — so they will
not see uncommitted writes and will not be rolled back if the mutation
fails. Prefer MutationContext::conn or [MutationContext::db] for
anything that should participate in the transaction. Reach for this
only for operations that fundamentally cannot run inside a transaction
(e.g. LISTEN/NOTIFY, advisory locks, or background pool work).
Sourcepub fn tx(&self) -> DbConn<'_>
pub fn tx(&self) -> DbConn<'_>
Get a DbConn for use in shared helper functions.
In transactional mode, returns a transaction-backed DbConn.
Otherwise returns a pool-backed DbConn.
pub async fn list_items(db: DbConn<'_>) -> Result<Vec<Item>> { ... }
#[forge::mutation]
pub async fn items_snapshot(ctx: &MutationContext, input: Input) -> Result<Vec<Item>> {
list_items(ctx.tx()).await
}Sourcepub fn db_conn(&self) -> DbConn<'_>
pub fn db_conn(&self) -> DbConn<'_>
Get a DbConn for use in shared helper functions (alias for tx()).
Sourcepub fn http(&self) -> HttpClient
pub fn http(&self) -> HttpClient
Get the HTTP client for external requests.
Requests go through the circuit breaker automatically. When the handler
declared an explicit timeout, that timeout is also applied to outbound
HTTP requests unless the request overrides it.
Sourcepub fn raw_http(&self) -> &Client
pub fn raw_http(&self) -> &Client
Get the raw reqwest client, bypassing circuit breaker execution.
Sourcepub fn set_http_timeout(&mut self, timeout: Option<Duration>)
pub fn set_http_timeout(&mut self, timeout: Option<Duration>)
Set the default outbound HTTP request timeout for this context.
Sourcepub fn user_id(&self) -> Result<Uuid>
pub fn user_id(&self) -> Result<Uuid>
Get the authenticated user’s UUID. Returns 401 if not authenticated.
Sourcepub fn claim(&self, key: &str) -> Option<&Value>
pub fn claim(&self, key: &str) -> Option<&Value>
Look up a custom JWT claim by name. Reserved JWT claims (iss,
aud, nbf, jti, sub, iat, exp, roles) are filtered
out. Shortcut for self.auth.claim(key).
Sourcepub fn set_token_issuer(&mut self, issuer: Arc<dyn TokenIssuer>)
pub fn set_token_issuer(&mut self, issuer: Arc<dyn TokenIssuer>)
Set the token issuer for this context.
Sourcepub fn set_token_ttl(&mut self, ttl: AuthTokenTtl)
pub fn set_token_ttl(&mut self, ttl: AuthTokenTtl)
Set the token TTL configuration (from forge.toml [auth]).
Sourcepub fn set_max_jobs_per_request(&mut self, limit: usize)
pub fn set_max_jobs_per_request(&mut self, limit: usize)
Set the maximum number of background jobs this mutation may dispatch. A value of 0 disables the limit.
Sourcepub fn issue_token(&self, claims: &Claims) -> Result<String>
pub fn issue_token(&self, claims: &Claims) -> Result<String>
Issue a signed JWT from the given claims.
Only available when HMAC auth is configured in forge.toml.
Returns an error if auth is not configured or uses an external provider (RSA/JWKS).
let claims = Claims::builder()
.user_id(user.id)
.duration_secs(7 * 24 * 3600)
.build()
.map_err(ForgeError::internal)?;
let token = ctx.issue_token(&claims)?;Sourcepub async fn issue_token_pair(
&self,
user_id: Uuid,
roles: &[&str],
) -> Result<TokenPair>
pub async fn issue_token_pair( &self, user_id: Uuid, roles: &[&str], ) -> Result<TokenPair>
Issue an access + refresh token pair for the given user.
Stores the refresh token hash in forge_refresh_tokens and returns
both tokens. Use rotate_refresh_token() to exchange a refresh token
for a new pair, and revoke_refresh_token() to invalidate one.
TTLs come from [auth] in forge.toml:
access_token_ttl(default “1h”)refresh_token_ttl(default “30d”)
Sourcepub async fn rotate_refresh_token(
&self,
old_refresh_token: &str,
) -> Result<TokenPair>
pub async fn rotate_refresh_token( &self, old_refresh_token: &str, ) -> Result<TokenPair>
Rotate a refresh token: validate the old one, issue a new pair.
The old token is atomically deleted and a new access + refresh pair is returned. Fails if the token is invalid or expired.
Sourcepub async fn revoke_refresh_token(&self, refresh_token: &str) -> Result<()>
pub async fn revoke_refresh_token(&self, refresh_token: &str) -> Result<()>
Revoke a specific refresh token (e.g., on logout).
Sourcepub async fn revoke_all_refresh_tokens(&self, user_id: Uuid) -> Result<()>
pub async fn revoke_all_refresh_tokens(&self, user_id: Uuid) -> Result<()>
Revoke all refresh tokens for a user (e.g., on password change or account deletion).
Sourcepub async fn dispatch_job<T: Serialize>(
&self,
job_type: &str,
args: T,
) -> Result<Uuid>
pub async fn dispatch_job<T: Serialize>( &self, job_type: &str, args: T, ) -> Result<Uuid>
Dispatch a background job.
In transactional mutations the job row is inserted on the active transaction, so it only becomes visible to workers after commit. Outside a transaction the dispatcher writes through the pool directly.
Returns ForgeError::Validation when the call would exceed the
per-request job dispatch cap configured via max_jobs_per_request.
Sourcepub async fn dispatch_job_at<T: Serialize>(
&self,
job_type: &str,
args: T,
scheduled_at: DateTime<Utc>,
) -> Result<Uuid>
pub async fn dispatch_job_at<T: Serialize>( &self, job_type: &str, args: T, scheduled_at: DateTime<Utc>, ) -> Result<Uuid>
Dispatch a background job at a specific time.
The job row is inserted immediately but workers will not pick it up
until scheduled_at is reached. In transactional mutations the insert
participates in the active transaction, so the job is only committed
(and becomes schedulable) once the mutation succeeds.
Returns ForgeError::Validation when the call would exceed the
per-request job dispatch cap.
Sourcepub async fn dispatch_job_after<T: Serialize>(
&self,
job_type: &str,
args: T,
delay: Duration,
) -> Result<Uuid>
pub async fn dispatch_job_after<T: Serialize>( &self, job_type: &str, args: T, delay: Duration, ) -> Result<Uuid>
Dispatch a background job after a delay.
Equivalent to dispatch_job_at(job_type, args, Utc::now() + delay).
The delay is computed at call time.
Returns ForgeError::Validation when the call would exceed the
per-request job dispatch cap, or when delay is too large to
represent as a chrono duration.
Sourcepub async fn dispatch<J: ForgeJob>(&self, args: J::Args) -> Result<Uuid>
pub async fn dispatch<J: ForgeJob>(&self, args: J::Args) -> Result<Uuid>
Type-safe dispatch: resolves the job name from the type’s ForgeJob
impl and serializes the args at the call site.
Sourcepub async fn dispatch_at<J: ForgeJob>(
&self,
args: J::Args,
scheduled_at: DateTime<Utc>,
) -> Result<Uuid>
pub async fn dispatch_at<J: ForgeJob>( &self, args: J::Args, scheduled_at: DateTime<Utc>, ) -> Result<Uuid>
Type-safe dispatch at a specific time.
Sourcepub async fn dispatch_after<J: ForgeJob>(
&self,
args: J::Args,
delay: Duration,
) -> Result<Uuid>
pub async fn dispatch_after<J: ForgeJob>( &self, args: J::Args, delay: Duration, ) -> Result<Uuid>
Type-safe dispatch after a delay.
Sourcepub async fn cancel_job(
&self,
job_id: Uuid,
reason: Option<String>,
) -> Result<bool>
pub async fn cancel_job( &self, job_id: Uuid, reason: Option<String>, ) -> Result<bool>
Request cancellation for a job.
Sourcepub async fn start_workflow<T: Serialize>(
&self,
workflow_name: &str,
input: T,
) -> Result<Uuid>
pub async fn start_workflow<T: Serialize>( &self, workflow_name: &str, input: T, ) -> Result<Uuid>
Start a durable workflow.
In transactional mutations the run row and its $workflow_resume
job are written on the active transaction, so the worker only picks
the run up after commit. Outside a transaction the dispatcher writes
through the pool directly.
Trait Implementations§
Source§impl EnvAccess for MutationContext
impl EnvAccess for MutationContext
fn env_provider(&self) -> &dyn EnvProvider
fn env(&self, key: &str) -> Option<String>
fn env_or(&self, key: &str, default: &str) -> String
fn env_require(&self, key: &str) -> Result<String>
fn env_parse<T: FromStr>(&self, key: &str) -> Result<T>
Source§fn env_parse_or<T: FromStr>(&self, key: &str, default: T) -> Result<T>
fn env_parse_or<T: FromStr>(&self, key: &str, default: T) -> Result<T>
fn env_contains(&self, key: &str) -> bool
Auto Trait Implementations§
impl Freeze for MutationContext
impl !RefUnwindSafe for MutationContext
impl Send for MutationContext
impl Sync for MutationContext
impl Unpin for MutationContext
impl UnsafeUnpin for MutationContext
impl !UnwindSafe for MutationContext
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more