Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Database Client

Provides a set of functions that establish connections, execute queries and manage data transactions.

Independent benchmarks are available at https://github.com/diesel-rs/metrics.

PostgreSQL

Implements a subset of https://www.postgresql.org/docs/16/protocol.html. PostgreSQL is a robust, open-source relational database management system that, among other things, supports several data types and usually also excels in concurrent scenarios.

To use this functionality, it is necessary to activate the postgres feature.

Prepared statements

//! Demonstrates different interactions with a PostgreSQL database.

extern crate tokio;
extern crate wtx;
extern crate wtx_examples;

use wtx::{
  database::{DbClient as _, Record, Records},
  misc::into_rslt,
};

#[tokio::main]
async fn main() -> wtx::Result<()> {
  let uri = "postgres://USER:PASSWORD@localhost/DATABASE";
  let mut executor = wtx_examples::postgres_client(uri).await?;
  executor
    .transaction(|this| async {
      this.execute_ignored("CREATE TABLE IF NOT EXISTS example(id INT, name VARCHAR)").await?;
      this
        .execute_stmt_none("INSERT INTO foo VALUES ($1, $2), ($3, $4)", (1u32, "one", 2u32, "two"))
        .await?;
      Ok(((), this))
    })
    .await?;
  let records = executor
    .execute_stmt_many("SELECT id, name FROM example", (), |_| Ok::<_, wtx::Error>(()))
    .await?;
  let record0 = into_rslt(records.get(0))?;
  let record1 = into_rslt(records.get(1))?;
  assert_eq!((record0.decode::<_, u32>(0)?, record0.decode::<_, &str>("name")?), (1, "one"));
  assert_eq!((record1.decode::<_, u32>("id")?, record1.decode::<_, &str>(1)?), (2, "two"));
  Ok(())
}

Batch

PostgreSQL supports the sending of multiple statements in a single round-trip.

//! Sends multiple commands at once and awaits them.

extern crate tokio;
extern crate wtx;
extern crate wtx_examples;

use wtx::{
  collections::ArrayVectorU8,
  database::{Record, Records},
  misc::into_rslt,
};

const COMMANDS: &[&str] = &["SELECT 0 = $1", "SELECT 1 = $1", "SELECT 2 = $1"];

#[tokio::main]
async fn main() -> wtx::Result<()> {
  let uri = "postgres://USER:PASSWORD@localhost/DATABASE";
  let mut executor = wtx_examples::postgres_client(uri).await?;
  let mut batch = executor.batch();
  let mut idx: u32 = 0;
  let mut records = ArrayVectorU8::<_, { COMMANDS.len() }>::new();
  for cmd in COMMANDS {
    batch.stmt(cmd, (idx,))?;
    idx = idx.wrapping_add(1);
  }
  batch.flush(&mut records, |_| Ok(())).await?;
  for record in records {
    assert!(into_rslt(record.get(0))?.decode::<_, bool>(0)?);
  }
  Ok(())
}

Tests

The #[wtx::db] macro automatically migrates and seeds individual tests in isolation to allow concurrent evaluations. Connected users must have the right to create new databases.

To use this functionality, it is necessary to activate the database-tests feature.

//! The DB isolation provided by `#[wtx::db]` allows the concurrent execution of identical queries
//! without causing conflicts.
//!
//! The `dir` parameter is optional.

fn main() {}

#[cfg(test)]
mod tests {
  use tokio::net::TcpStream;
  use wtx::database::{
    DbClient, Record,
    client::postgres::{ClientBuffer, PostgresClient},
  };

  type LocalPostgresClient = PostgresClient<ClientBuffer, wtx::Error, TcpStream>;

  #[wtx::db(dir("../.test-utils"))]
  async fn first_test(client: LocalPostgresClient) {
    common(client).await;
  }

  #[wtx::db(dir("../.test-utils"))]
  async fn second_test(client: LocalPostgresClient) {
    common(client).await;
  }

  #[wtx::db(dir("../.test-utils"))]
  async fn third_test(client: LocalPostgresClient) {
    common(client).await;
  }

  async fn common(mut client: LocalPostgresClient) {
    client
      .execute_ignored(
        "
          CREATE TABLE foo(id INT PRIMARY KEY, description TEXT NOT NULL);
          INSERT INTO foo VALUES (1, 'BAR!');
        ",
      )
      .await
      .unwrap();
    let id: &str = client.execute_single("SELECT * FROM foo").await.unwrap().decode(0).unwrap();
    assert_eq!(id, "1");
  }
}