A3S ORM
Overview
A3S ORM is a type-safe SQL query builder for Rust, inspired by Kysely. Rust table definitions constrain columns, values, and decoded results at compile time. Queries compile into SQL plus bound parameters and execute through an async, driver-neutral interface.
Despite the name, this is not an Active Record framework. Records do not own persistence behavior, queries stay explicit, and runtime values are never interpolated into generated SQL.
Basic usage
use ;
orm_table!
let query =
.select
.filter
.order_by
.limit
.compile?;
assert_eq!;
# Ok::
Features
- Typed Schema: Catch invalid columns, values, and assignments at compile time
- Immutable Queries: Build SELECT, INSERT, UPDATE, and DELETE statements explicitly
- Safe Parameters: Keep runtime values out of generated SQL
- Advanced SQL: Use joins, CTEs, subqueries, aggregates, windows, set operations, functions, casts, and PostgreSQL row/table locks
- Typed Results: Decode scalar, tuple, nullable, array, and extended database values
- Async Drivers: Run non-blocking SQLite and pooled PostgreSQL operations on Tokio
- Safe Transactions: Roll back scoped work on errors and task cancellation
- PostgreSQL HA Controls: Select transaction semantics, bound pool waits, classify retryable failures, observe health, and rotate verified TLS pools
- Migrations: Apply locked, atomic, checksummed migrations
- Extensible Runtime: Add another database through the public
Executorcontract
Support matrix
| Capability | PostgreSQL | SQLite | MySQL |
|---|---|---|---|
| SQL compilation | Yes | Yes | Yes |
| Bundled async driver | Yes | Yes | No |
RETURNING |
Yes | Yes | Rejected |
ON CONFLICT |
Yes | Yes | Rejected |
FOR UPDATE, NOWAIT, SKIP LOCKED |
Yes | Rejected | Rejected |
| Transactions | Yes | Yes | — |
| Locked migrations | Advisory lock | BEGIN IMMEDIATE |
— |
| UUID, JSON, temporal, decimal, arrays | Yes | SQLite-native subset | — |
MySQL support currently means SQL generation only; it does not imply a bundled runtime driver. See Production Readiness for the precise supported scope and limitations.
Quick Start
Installation
Pin the released Git tag:
[]
= { = "https://github.com/A3S-Lab/ORM", = "v0.2.0" }
= { = "1", = ["macros", "rt-multi-thread"] }
SQLite is enabled by default. For a compile-only query builder without a bundled driver:
= { = "https://github.com/A3S-Lab/ORM", = "v0.2.0", = false }
For PostgreSQL:
= { = "https://github.com/A3S-Lab/ORM", = "v0.2.0", = false, = ["postgres"] }
The postgres feature includes UUID, JSON/JSONB, Chrono date/time types,
rust_decimal::Decimal, and SqlArray<T>.
Insert, update, and delete
# use ;
# orm_table!
let insert =
.value
.value
.returning
.compile?;
let update =
.set
.filter
.compile?;
let delete =
.filter
.compile?;
# Ok::
Multi-row inserts use typed InsertRow<T> values. PostgreSQL and SQLite also
support conflict targets, DO NOTHING, bound updates, and values from the
excluded row.
Expressions and PostgreSQL locks
Scalar functions and casts stay inside the typed expression AST. Function and SQL type names are validated; runtime values remain parameters. Typed scalar subqueries and column comparisons can be composed into filters and ordering:
# use ;
# orm_table!
let query =
.select
.filter
.filter
.filter
.order_by_expression
.
.skip_locked
.compile?;
assert!;
# Ok::
for_update, for_no_key_update, for_share, and for_key_share each have
targeted *_of variants and support no_wait or skip_locked. PostgreSQL
table locks use a schema marker instead of a string:
# use ;
# orm_table!
let query =
.no_wait
.compile?;
assert_eq!;
# Ok::
Row and table locks are rejected by unsupported dialects. PostgreSQL
transactions also expose advisory_xact_lock(namespace, key) for
parameterized logical locks whose target row does not exist yet.
Typed results
A selection determines its Rust output type. fetch_all_as, fetch_optional_as,
and fetch_one_as decode that type and enforce the requested cardinality.
Checked integer conversion reports overflow with the result-column index.
For exceptional SQL outside the typed AST, sql_query::<Output> accepts
reviewed static SQL while runtime data enters through bind. Prefer extending
the typed AST when an application needs a reusable missing capability.
Database Drivers
SQLite
use ;
# async
File databases default to WAL journaling, foreign-key enforcement, and a
five-second busy timeout. SqliteExecutor::open_with_options allows each policy
to be changed. In-memory databases use memory journaling.
The driver serializes access to its connection without blocking Tokio. Scoped transactions and nested savepoints retain the connection gate until cancellation cleanup completes.
PostgreSQL
use ;
# async
connect_no_tls is intended for local or separately secured connections.
Production applications can use connect_tls with in-memory
PostgresTlsOptions, then atomically install verified replacement certificate
material through rotate_tls.
PostgresTransactionOptions selects isolation, read-only mode, and
transaction-local statement, lock, and idle timeouts. PostgresPoolOptions
bounds pool acquisition/creation/recycling. Stable label-free snapshots expose
pool saturation, acquisition latency, health, failure classes, and certificate
pool generations. See PostgreSQL HA Controls for the
complete deployment and retry contract.
Migrations
Migrations are ordered by version, checksummed with SHA-256, and recorded in
a3s_orm_migrations. Re-running an unchanged set is a no-op. Modifying or
removing an applied migration is an error.
use ;
# async
SQLite coordinates migrators through its connection gate and
BEGIN IMMEDIATE. PostgreSQL uses a transaction-scoped advisory lock with a
bounded configurable deadline. The migration SQL and history entry commit
atomically. Production rolling deployments should follow the documented
expand/migrate/verify/contract phases.
Architecture
The query API does not depend on a database client:
typed schema + expressions
│
immutable query AST
│
dialect compiler
│
CompiledQuery
│
async Executor / driver
Source is split by responsibility under compiler/, query/, drivers/, and
migration/. See Architecture for module ownership and
extension points.
Development
The integration suite executes SQL against real databases. SQLite tests use actual in-memory and temporary file databases. PostgreSQL tests run against PostgreSQL 17 services and exercise schema creation, prepared queries, typed round trips, migrations, row and advisory locks, transactions, rollback, cancellation cleanup, concurrent serializable writers, pool exhaustion, failover-like disconnects, migration contention, mixed-version expand/contract compatibility, and generated-CA TLS rotation.
CI runs the full feature matrix with cargo llvm-cov and fails when line
coverage falls below 90%.
RUSTDOCFLAGS="-D warnings"
To run PostgreSQL integration tests locally:
A3S_ORM_POSTGRES_URL=postgres://postgres:postgres@127.0.0.1:5432/a3s_orm \
See Roadmap for planned schema builders, plugins, additional codecs, code generation, and the MySQL runtime driver.
License
MIT