sqlstr 0.1.0

Sql string builder
Documentation
use std::convert::Infallible;
use std::time::Duration;

use sqlstr::{expr, ArgumentBuffer, SqlCommand};
use sqlx::postgres::PgArguments;
use sqlx::{Arguments, Encode, Postgres, Type};

#[derive(Default)]
struct PostgresArg {
    arg: PgArguments,
    count: u32,
}

impl<T> ArgumentBuffer<T> for PostgresArg
where
    T: for<'q> Encode<'q, Postgres> + Type<Postgres> + Send,
{
    type Error = Infallible;

    fn push(&mut self, value: T) -> Result<(), Self::Error> {
        self.count += 1;
        self.arg.add(value);
        Ok(())
    }

    fn count(&self) -> u32 {
        self.count
    }
}

const DEFAULT_DATABASE_URL: &str = "postgres://root:root@localhost:5432/sqlstr_example";

fn main() -> Result<(), Box<dyn std::error::Error>> {
    use sqlx::postgres::PgPoolOptions;
    use sqlx::Row;
    use tokio::runtime;

    let database_url: String = match std::env::args().nth(1) {
        None => DEFAULT_DATABASE_URL.into(),
        Some(arg) => arg
            .as_str()
            .strip_prefix("--database-url=")
            .unwrap_or(DEFAULT_DATABASE_URL)
            .into(),
    };

    let rt = runtime::Builder::new_current_thread()
        .enable_io()
        .enable_time()
        .build()?;

    let query = rt.block_on(async {
        println!("connecting to database at '{}'", database_url);
        let pool = PgPoolOptions::new()
            .max_connections(1)
            .acquire_timeout(Duration::from_secs(3))
            .connect(&database_url)
            .await
            .expect("connect to database");
        println!("database connected!");

        let query = make_sql_command().expect("create an SQL command as an infallible operation");

        println!("executing query '{}'", query.as_command());
        sqlx::query_with(&query.command, query.arguments.arg)
            .fetch_one(&pool)
            .await
            .expect("execute the SQL command in the connected database")
    });

    println!("query returned!\nextracting values from the query result");

    let num: i32 = query.get(0);
    let list: Vec<String> = query.get(1);
    let boolean: bool = query.get(2);
    let strr: &str = query.get(3);

    println!("asserting returned values ...");
    assert_eq!(num, -1);
    assert_eq!(list, vec!["array", "of", "str"]);
    assert!(!boolean);
    assert_eq!(strr, "sqlstr");

    println!("all values are correct, exiting!");

    Ok(())
}

fn make_sql_command() -> Result<SqlCommand<PostgresArg>, Infallible> {
    let mut sql: SqlCommand<PostgresArg> = SqlCommand::default();

    expr::select(&mut sql);
    expr::separator(&mut sql);
    sql.push_value(-1_i32)?;
    expr::item_separator(&mut sql);
    sql.push_value(["array", "of", "str"])?;
    expr::item_separator(&mut sql);
    sql.push_value(false)?;
    expr::item_separator(&mut sql);
    sql.push_value("sqlstr")?;

    Ok(sql)
}