Expand description

High-performance extractors for tokio_postgres.

This crate contains traits and proc macros for creating high-performance extractors for Rust types from Rows.

Examples

Extracting a single row

#[derive(Columns, Extract)]
struct User {
    id: i32,
    name: String,
}

async fn get_user(client: &Client, id: i32) -> Result<User, Error> {
    client
        .query_one("select * from user where id = $1", &[&id])
        .await
        .map(|r| r.extract_once())
}

Extracting a stream of rows

#[derive(Columns, Extract)]
struct User {
    id: i32,
    name: String,
}

async fn get_users(client: &Client) -> Result<Vec<User>, Error> {
    client
        .query_raw("select * from user", None::<i32>)
        .await?
        .extract()
        .try_collect()
        .await
}

Generic types

Generic types are fully supported.

#[derive(Columns, Extract)]
struct User<'a, T: ?Sized> {
    id: i32,
    name: &'a T,
}

fn assert_is_extract<'a, T: Extract<'a>>() { }

assert_is_extract::<User<str>>();

Custom column names

You can specify column names that are different from field names. See the documentation of the Columns proc macro.

Design

A naive mapping function such as

User {
    id: row.get("id"),
    name: row.get("name"),
}

has O(N^2) runtime where N is the number of columns. Each invocation of row.get must walk all columns and compare their name to the name of the requested column. This crate solves this by

  1. Constructing an efficient data structure at compile time that reduces lookup time to O(N).

    This data structure is similar to a perfect hash function but more efficient.

  2. Memorizing the mapping from fields to columns whenever possible.

Modules

Traits

Derive Macros