pub trait SqlBackend: Send + Sync {
// Required method
fn begin<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlTransaction>, SqlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
// Provided methods
fn dialect(&self) -> Dialect { ... }
fn rls_guc(&self) -> Option<&RlsGuc> { ... }
fn begin_read_only<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlTransaction>, SqlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn run_script<'life0, 'life1, 'async_trait>(
&'life0 self,
_sql: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), SqlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn run_query<'life0, 'life1, 'async_trait>(
&'life0 self,
sql: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<SqlRows, SqlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn injects_session_context(&self) -> bool { ... }
}Expand description
A per-site SQL backend (libsql — a local file or a remote sqld namespace).
One instance serves one site. The handler engine calls begin once per
invocation that uses SQL and drives the resulting SqlTransaction to a
commit (on a successful response) or rollback (on trap/error).
Required Methods§
Sourcefn begin<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlTransaction>, SqlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn begin<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlTransaction>, SqlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Open a new read-write transaction. Backends are free to draw the underlying connection from a pool, a fresh embedded connection, or a remote session. Writes always land on the primary.
Provided Methods§
Sourcefn dialect(&self) -> Dialect
fn dialect(&self) -> Dialect
The SQL dialect this backend speaks — used by the orm compiler for the few
dialect-divergent constructs (e.g. JSON extraction). Defaults to SQLite-family
(libsql); the Postgres/MySQL backends override it.
Sourcefn rls_guc(&self) -> Option<&RlsGuc>
fn rls_guc(&self) -> Option<&RlsGuc>
The operator-configured RLS session-GUC names (RlsGuc) this backend carries, or None
(the common case). When Some and dialect is
Postgres, the handler sql/orm binding sets the host-resolved tenant
(own/target/session) per transaction, and the row’s tenant per all write, via
render_set_local_guc, so an app’s RLS mirrors the injected predicate. The guest can never
set these itself (reject_reserved_session_writes blocks the configured names).
Sourcefn begin_read_only<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlTransaction>, SqlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn begin_read_only<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlTransaction>, SqlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Open a transaction for a read-only invocation, which a backend configured with a read replica may route to that replica (separate read vs write endpoint: reads → replicas, writes → primary). A replica may lag the primary, so such reads are eventually consistent; issuing a write on this transaction is a caller error (it hits the read endpoint, which a replica rejects).
The default has no replica and simply opens a normal transaction, so single-node and replica-less deployments behave identically.
Sourcefn run_script<'life0, 'life1, 'async_trait>(
&'life0 self,
_sql: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), SqlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn run_script<'life0, 'life1, 'async_trait>(
&'life0 self,
_sql: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), SqlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Run a multi-statement SQL script as one unit (the simple-query protocol),
for operator migrations: CREATE EXTENSION and long chains of DDL/DML that the
parameterized per-statement path can’t express. Only the external
Postgres/MySQL backends implement it (the per-site libsql backend rejects it);
it is an operator tool, not a guest capability.
Sourcefn run_query<'life0, 'life1, 'async_trait>(
&'life0 self,
sql: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<SqlRows, SqlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn run_query<'life0, 'life1, 'async_trait>(
&'life0 self,
sql: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<SqlRows, SqlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Run one row-returning statement directly, in its own short-lived read-only
transaction — backs the operator sql query. The default composes the existing
transaction methods, so every backend supports it.
Sourcefn injects_session_context(&self) -> bool
fn injects_session_context(&self) -> bool
Whether this backend injects a reserved boatramp session context
(rls_session — the boatramp.project / boatramp.site GUC on Postgres, or
the @boatramp_project / @boatramp_site MySQL session var) that an app’s
row-level-security policy keys on. Default false.
When true, the guest sql binding must refuse any guest statement that
would set/reset those reserved keys (see reject_reserved_session_writes):
otherwise a hostile guest could spoof its injected tenant and defeat the app’s
RLS. This is a security signal, not a routing one — see the rls_session doc for
the trust model (the real isolation boundary is the per-tenant database + role).
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".