Expand description
A small, engine-agnostic SQL backend contract for the handler sql binding.
The handler engine exposes a sql capability to guests, but which database
serves it is a deployment detail — the same seam as the blob (Storage)
and KV (kv::KvStore) backends. SqlBackend is that seam, so the guest
interface and the server UX stay identical across single-node and cluster
deployments. The one implementation is libsql (SQLite-compatible): an
embedded file per site (single-node) or a sqld namespace per site (cluster,
read-replicable) — one engine, the split being config, not a backend choice.
Each backend instance is scoped to one site; the engine/transport and the
per-site database mapping live behind the trait, so a handler can never
address another site’s data (crate::deploy-style isolation).
The contract is deliberately tiny — begin a transaction, query/execute
within it, then commit/rollback — and the trait keeps the engine
decoupled from libsql’s specifics (and lets tests substitute a fake). The
handler engine wraps each invocation in one transaction (commit on success,
roll back on trap/error).
Structs§
- RlsGuc
- Operator-configured SQL session-context GUC names carrying the host-resolved tenant (and the
anonymous session) to an app’s Postgres RLS, so its policies (
current_setting(name, true)) mirror boatramp’s injected tenancy predicate as a defense-in-depth backstop. Set on a managed / external SQL binding (therls_sessionflag + these names, e.g.app.tenant_id). Postgres only — the backstop is thecurrent_settingRLS pattern; a libsql/MySQL backend leaves these unset. The guest can NEVER set them itself (the reserved-write guard blocks the configured names,reject_reserved_session_writes); the host derives the value from the SAME resolution the injected predicate uses (own / target / session) or, for a posture-vettedallwrite, from the row/statement being written — the DB’sWITH CHECK/USINGis the final arbiter of a mismatch. - SqlPing
Replica - One replica’s reachability, returned by
OperatorSql::ping. - SqlRows
- The rows a
SqlTransaction::queryreturned: column names plus row-major cells (each row’s length equalscolumns.len()).
Enums§
- Dialect
- The SQL dialect a backend speaks. The
ormcompiler is?N-portable for almost everything (the backend rewrites the placeholders), and only consults this for the handful of constructs whose syntax genuinely differs across engines — currently JSON extraction (json_extract(...)on SQLite/MySQL vs#>>on Postgres). - Preview
SqlMode - How a preview deployment’s SQL database relates to the site’s live one (operator policy; see the per-site/server config). The default is the safe, isolated choice.
- SqlError
- Why a SQL operation failed.
- SqlValue
- A single SQL value.
Booleanis carried as a distinct class (so a guest can express one and a strictly-typed engine could bind a nativeBOOL); libsql, being SQLite-family, maps it to0/1.
Traits§
- Operator
Sql - The operator-facing SQL capability for a managed database: run a migration
script or a single query against a compute-backed database boatramp runs, using
its sealed managed credential (resolved server-side — the credential never leaves
the node). Backs
POST /api/sql/{db}/{exec,query}and theboatramp sqlCLI. Distinct fromSqlBackends(the per-site guest binding): this is a project-scoped operator tool, admin-gated at the API. - SqlBackend
- A per-site SQL backend (libsql — a local file or a remote sqld namespace).
- SqlBackends
- Resolves a site’s named SQL databases to
SqlBackends — the seam the server’s handler runtime uses to obtain a per-site database on demand (opening/caching it lazily). The concrete mapping (a libsql file per site, or a sqld namespace per site) lives behind this, so the server stays storage-agnostic. - SqlTransaction
- One transaction’s worth of work. Dropping it without
commitmust leave the database unchanged (the engine rolls back). - Tenant
Deprovisioner - Tear down a deleted tenant’s managed databases — the delete-time counterpart
to the create-time provisioning of a per-tenant managed
sqlbinding. When a project (or site) is deleted through the control plane, boatramp drops that tenant’s databases + login roles + sealed credentials — exactly that tenant’s, nothing else — so a deleted tenant leaves no orphaned data plane behind.
Functions§
- reject_
reserved_ session_ writes - Reject a guest SQL statement that would set or reset a boatramp-reserved
session key — the
boatramp.*GUC (Postgres) or an@boatramp_*user variable (MySQL). Used by the guestsqlbinding when the backendinjects_session_context: withrls_sessionon, boatramp injects the request’s tenant into those keys for the app’s RLS, so a guest that could overwrite them would spoof its tenant and defeat that RLS. - render_
set_ local_ guc - Render a transaction-local Postgres GUC set (
SELECT set_config($1, $2, true)). Both the setting NAME and the VALUE are BOUND parameters (never interpolated), so a dotted operator name likeapp.tenant_idand any value are injection-safe; thetruescopes the setting to the current transaction (auto-cleared at COMMIT/ROLLBACK, like theboatramp.project/sitecontext). The value is bound as TEXT (set_config’s argument type); the operator’s RLS policy casts if its key column isn’t text. Postgres only — callers gate onDialect::Postgres.