Expand description
Compile-time checked PostgreSQL queries with binary-format performance.
resolute validates SQL against a live database at compile time (or offline via cached metadata), generates typed result structs, and executes queries using PostgreSQL’s binary wire format for zero-overhead type mapping.
§Quick start
use resolute::{Client, query};
let url = std::env::var("DATABASE_URL")?;
let client = Client::connect_from_str(&url).await?;
// Compile-time checked with positional params:
let row = query!("SELECT id, name FROM users WHERE id = $1", user_id)
.fetch_one(&client)
.await?;
println!("{}: {}", row.id, row.name);
// Named parameters (unique to resolute, not available in sqlx):
let row = query!("SELECT id, name FROM users WHERE id = :id", id = user_id)
.fetch_one(&client)
.await?;§Named parameters
Both compile-time macros and runtime methods support :name syntax.
Named params are rewritten to $1, $2, ... before hitting PostgreSQL.
Duplicate names reuse the same positional slot. :: casts, string
literals, and comments are handled correctly.
// Compile-time:
query!("SELECT :val::int4 WHERE :val > 0", val = my_var)
// Runtime:
client.query_named(
"SELECT :id::int4 AS n",
&[("id", &42i32)],
).await?;§Executor trait — generic over connection types
Write functions once with &impl Executor. Unlike sqlx (which consumes self),
resolute’s Executor uses &self — multi-query reuse just works.
async fn create_user(db: &impl Executor, name: &str) -> Result<i32, TypedError> {
let rows = db.query("INSERT INTO users (name) VALUES ($1) RETURNING id", &[&name.to_string()]).await?;
rows[0].get(0)
}
create_user(&client, "Alice").await?; // Client
create_user(&txn, "Alice").await?; // Transaction
create_user(&pooled, "Alice").await?; // Pool§Context-aware atomicity
db.atomic(|db| ...) does BEGIN/COMMIT on Client, SAVEPOINT/RELEASE on
Transaction. Same function, correct behavior in any context.
async fn transfer(db: &impl Executor, from: i32, to: i32) -> Result<(), TypedError> {
db.atomic(|db| Box::pin(async move {
db.execute("UPDATE accounts SET balance = balance - 100 WHERE id = $1", &[&from]).await?;
db.execute("UPDATE accounts SET balance = balance + 100 WHERE id = $1", &[&to]).await?;
Ok(())
})).await
}§Custom PostgreSQL types
use resolute::{PgComposite, PgDomain, PgEnum};
// String-based enum (PostgreSQL CREATE TYPE ... AS ENUM):
#[derive(PgEnum)]
#[pg_type(rename_all = "snake_case")]
enum Mood { Happy, Sad }
// Integer-backed enum (stored as int4 in PostgreSQL):
#[derive(PgEnum)]
#[repr(i32)]
enum Status { Active = 1, Inactive = 2, Deleted = 3 }
#[derive(PgComposite)]
struct Address { street: String, city: String, zip: Option<String> }
// Domain type: inherits array OID from inner type.
#[derive(PgDomain)]
struct Email(String); // ARRAY_OID = 1009 (text[])§FromRow derive
use resolute::FromRow;
#[derive(FromRow)]
struct User {
id: i32,
#[from_row(rename = "email_address")]
email: String,
#[from_row(skip)]
computed: String, // Default::default()
#[from_row(default)]
retries: i32, // 0 if missing or NULL
#[from_row(json)]
metadata: MyStruct, // deserialized from jsonb
#[from_row(try_from = "i32")]
status: MyStatus, // decoded as i32, then TryFrom
#[from_row(flatten)]
address: Address, // nested FromRow, shares the row
}§Query type overrides
// Override inferred types in query! macros:
let row = query!(r#"SELECT id as "id: UserId" FROM users"#)
.fetch_one(&client).await?;
// row.id is UserId, not i32§Performance over sqlx
- Binary format: PG sends raw bytes, no text-to-number parsing
- Message coalescing: multiple queries batched into one write() syscall
- Statement caching: Parse once, Bind+Execute on reuse
- Generic array encode/decode for all types via
Vec<T>
§Cargo features
chrono(default):chrono::NaiveDate,NaiveTime,NaiveDateTime,DateTime<Utc>.json(default):serde_json::Valueforjson/jsonb.uuid(default):uuid::Uuid.test-utils(off by default): exposes thetest_dbmodule with ephemeral test-database helpers and env-driven connection settings (RESOLUTE_TEST_ADDR,RESOLUTE_TEST_USER,RESOLUTE_TEST_PASSWORD,RESOLUTE_TEST_DB). Enabled automatically by the#[resolute::test]attribute macro.
Re-exports§
pub use newtypes::PgDate;pub use newtypes::PgInet;pub use newtypes::PgNumeric;pub use newtypes::PgTimestamp;pub use pg_type::PgType;pub use range::PgRange;
Modules§
- admin
- Database lifecycle helpers:
CREATE DATABASE/DROP DATABASEagainst a maintenance connection. Useful for test scaffolding and dev tooling where you don’t want a separatepsqldependency. - metrics
- Optional Prometheus metrics for resolute.
- migrate
- Migration runner for use in applications, build scripts, and tooling.
- named_
params - Named parameter rewriting:
:name→$1, $2, ... - newtypes
- Newtype wrappers for PostgreSQL types that don’t map to native Rust types.
- pg_type
- PostgreSQL type metadata trait.
- range
- PostgreSQL range type support.
- reconnect
- Auto-reconnecting client wrapper.
- retry
- Automatic retry for transient database errors.
- test_db
- Test database helper: creates a temporary database for isolated testing.
Macros§
- query
- Compile-time checked query macro. Requires
DATABASE_URLenv var.query!("SQL", param1, param2, ...)— compile-time checked SQL query. - query_
as - Compile-time checked query mapped to an existing struct via FromRow.
query_as!(Type, "SQL", param1, param2, ...)— compile-time checked query mapped to an existing struct via FromRow. - query_
file - Like query! but reads SQL from a file.
query_file!("path/to/query.sql", param1, param2, ...)— like query! but reads SQL from a file. - query_
file_ as - Like query_as! but reads SQL from a file.
query_file_as!(Type, "path/to/query.sql", param1, ...)— like query_as! but reads SQL from a file. - query_
file_ scalar - Like query_scalar! but reads SQL from a file.
query_file_scalar!("path/to/query.sql", param1, ...)— file-based scalar query. - query_
scalar - Compile-time checked single-scalar query.
query_scalar!("SQL", param1, ...)— compile-time checked single-value query. - query_
unchecked - Skip compile-time checking (no DATABASE_URL or cache needed).
query_unchecked!("SQL", param1, ...)— skip compile-time validation. Useful when DATABASE_URL is unavailable and no cache exists. Params are passed as-is; no type or count checking.
Structs§
- Bytes
Mut - A unique reference to a contiguous slice of memory.
- Cancel
Token - A token that can cancel a running query on a specific backend. Cloneable and Send, can be passed to another task or stored for timeout handling.
- Checked
Query - A compile-time checked query ready for execution.
Generated by the
query!()macro. - Client
- A typed query client wrapping an AsyncConn. Sends parameters in binary format and requests binary results.
- Exclusive
Pool - A pool of typed database connections.
- Notification
- A notification received from PostgreSQL LISTEN/NOTIFY.
- PgListener
- A LISTEN/NOTIFY listener on a dedicated connection.
- Pooled
Client - A typed client checked out from the pool.
- Pooled
Transaction - A transaction scoped to a pooled connection checkout.
- Query
Builder - Fluent builder for a runtime SQL query.
- RawRow
- Row
- A row from a query result with typed column access.
- RowStream
- A stream of rows from a query result.
- Shared
Client - A typed client over a shared
AsyncConn. Cheap to clone (one Arc bump). - Shared
Pool - A shared (multiplexed) pool of typed database connections.
- Transaction
- A transaction guard.
- Type
Info - Metadata about a PostgreSQL type.
- Unchecked
Query - An unchecked query (no compile-time validation).
Generated by
query_unchecked!().
Enums§
- Isolation
Level - Transaction isolation level for
begin_with(). - Listener
Event - An event yielded from
PgListener::recv_event. - Pipeline
Result - Result from a single pipeline step.
- TypeOid
- Known PostgreSQL type OIDs.
- Typed
Error - Top-level error type returned by the typed query layer.
Traits§
- Decode
- Trait for types that can be decoded from PostgreSQL binary format.
- Decode
Text - Decode from PostgreSQL text format (for backwards compat and mixed-mode queries).
- Encode
- Trait for types that can be encoded into PostgreSQL binary format.
- Executor
- Trait for types that can execute PostgreSQL queries.
- FromRow
- Trait for types that can be constructed from a Row.
- SqlParam
- Trait for values that can be used as query parameters.
Implemented for all
T: Encodeand forOption<T>(NULL).
Functions§
- sql
- Start a new runtime query builder.
Attribute Macros§
- test
- Attribute macro for database-backed tests. Auto-creates a temp DB,
runs migrations, injects a
Client, and drops the DB on completion. Attribute macro for database-backed tests.
Derive Macros§
- FromRow
- Derive macro for
FromRow. Use#[derive(resolute::FromRow)]on structs. DeriveFromRowfor structs with named fields. - PgComposite
- Derive macro for PostgreSQL composite types.
Derive
Encode,Decode,DecodeText, andPgTypefor a Rust struct representing a PostgreSQL composite type. - PgDomain
- Derive macro for PostgreSQL domain types (newtypes over a base type).
Derive
Encode,Decode,DecodeText, andPgTypefor a newtype struct representing a PostgreSQL domain type. - PgEnum
- Derive macro for PostgreSQL enum types.
Derive
Encode,Decode,DecodeText, andPgTypefor a Rust enum representing a PostgreSQL enum type.