#postgresql #sql #async #proc-macro #column-name

tokio-postgres-extractor

High-performance extractors for tokio_postgres

1 unstable release

0.7.0 Apr 29, 2023

#1850 in Database interfaces

Download history 146/week @ 2024-01-17 77/week @ 2024-01-24 33/week @ 2024-01-31 118/week @ 2024-02-07 147/week @ 2024-02-14 63/week @ 2024-02-21 328/week @ 2024-02-28 95/week @ 2024-03-06 96/week @ 2024-03-13 64/week @ 2024-03-20 103/week @ 2024-03-27

500 downloads per month

MIT/Apache

35KB
506 lines

tokio-postgres-extractor

crates.io docs.rs

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

License

This project is licensed under either of

  • Apache License, Version 2.0
  • MIT License

at your option.


lib.rs:

High-performance extractors for [tokio_postgres].

This crate contains traits and proc macros for creating high-performance extractors for Rust types from [Row]s.

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][macro@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.

Dependencies

~8–19MB
~320K SLoC