Skip to main content

Crate resolute

Crate resolute 

Source
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::Value for json / jsonb.
  • uuid (default): uuid::Uuid.
  • test-utils (off by default): exposes the test_db module 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 DATABASE against a maintenance connection. Useful for test scaffolding and dev tooling where you don’t want a separate psql dependency.
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_URL env 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§

BytesMut
A unique reference to a contiguous slice of memory.
CancelToken
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.
CheckedQuery
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.
ExclusivePool
A pool of typed database connections.
Notification
A notification received from PostgreSQL LISTEN/NOTIFY.
PgListener
A LISTEN/NOTIFY listener on a dedicated connection.
PooledClient
A typed client checked out from the pool.
PooledTransaction
A transaction scoped to a pooled connection checkout.
QueryBuilder
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.
SharedClient
A typed client over a shared AsyncConn. Cheap to clone (one Arc bump).
SharedPool
A shared (multiplexed) pool of typed database connections.
Transaction
A transaction guard.
TypeInfo
Metadata about a PostgreSQL type.
UncheckedQuery
An unchecked query (no compile-time validation). Generated by query_unchecked!().

Enums§

IsolationLevel
Transaction isolation level for begin_with().
ListenerEvent
An event yielded from PgListener::recv_event.
PipelineResult
Result from a single pipeline step.
TypeOid
Known PostgreSQL type OIDs.
TypedError
Top-level error type returned by the typed query layer.

Traits§

Decode
Trait for types that can be decoded from PostgreSQL binary format.
DecodeText
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: Encode and for Option<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. Derive FromRow for structs with named fields.
PgComposite
Derive macro for PostgreSQL composite types. Derive Encode, Decode, DecodeText, and PgType for a Rust struct representing a PostgreSQL composite type.
PgDomain
Derive macro for PostgreSQL domain types (newtypes over a base type). Derive Encode, Decode, DecodeText, and PgType for a newtype struct representing a PostgreSQL domain type.
PgEnum
Derive macro for PostgreSQL enum types. Derive Encode, Decode, DecodeText, and PgType for a Rust enum representing a PostgreSQL enum type.