dialtone_sqlx 0.1.0

Dialtone SQLx Back-End
Documentation
use serde::Deserialize;
use std::env;

use sqlx::postgres::{PgArguments, PgRow};
use sqlx::query::Query;
use sqlx::types::chrono::{DateTime, Utc};
use sqlx::types::Json;
use sqlx::{Connection, Error, PgConnection, PgPool, Pool, Postgres, Row};

pub mod actor;
pub mod actor_owner;
pub mod actor_reference;
pub mod ap_object;
pub mod ap_object_reference;
pub mod persistent_queue;
pub mod site_info;
pub mod system_role;
pub mod user_principal;

pub fn get_database_url() -> String {
    env::var("DATABASE_URL").expect("DATABASE_URL must be set")
}

pub async fn get_connection() -> Result<PgConnection, Error> {
    let db_url = get_database_url();
    PgConnection::connect(&db_url).await
}

pub async fn get_pooled_connection() -> Result<Pool<Postgres>, Error> {
    let db_url = get_database_url();
    PgPool::connect(&db_url).await
}

#[derive(Debug)]
pub enum CondParam<'a> {
    Date(&'a DateTime<Utc>),
    String(&'a str),
}

pub fn date_range_condition<'a>(
    prev_date: Option<&'a DateTime<Utc>>,
    next_date: Option<&'a DateTime<Utc>>,
    column_name: &str,
    mut conditions: Vec<String>,
    mut params: Vec<CondParam<'a>>,
) -> (Vec<String>, Vec<CondParam<'a>>) {
    if let Some(date_param) = prev_date {
        params.push(CondParam::Date(date_param));
        conditions.push(format!("{} < ${}", column_name, params.len() + 1));
    }
    if let Some(date_param) = next_date {
        params.push(CondParam::Date(date_param));
        conditions.push(format!("{} > ${}", column_name, params.len() + 1));
    }
    (conditions, params)
}

pub fn make_where_clause(conditions: &[String]) -> String {
    if !conditions.is_empty() {
        let anded_conditions: String =
            itertools::Itertools::intersperse(conditions.iter().cloned(), " and ".to_string())
                .collect::<String>();
        format!(" where {} ", anded_conditions)
    } else {
        "".to_string()
    }
}

pub fn bind_params<'a>(
    mut query: Query<'a, Postgres, PgArguments>,
    params: &'a [CondParam<'a>],
) -> Query<'a, Postgres, PgArguments> {
    for x in params {
        match x {
            CondParam::Date(date) => query = query.bind(date),
            CondParam::String(string) => query = query.bind(string),
        }
    }
    query
}

pub fn return_optional<'a, T: 'a + Deserialize<'a>>(
    result: &'a Option<PgRow>,
) -> Result<Option<T>, sqlx::Error> {
    match result {
        None => Ok(None),
        Some(row) => {
            let data = row
                .try_get::<Json<T>, usize>(0)
                .map(|json| Option::from(json.0));
            match data {
                Ok(value) => Ok(value),
                Err(err) => match err {
                    Error::ColumnDecode { .. } => Ok(None),
                    _ => Err(err),
                },
            }
        }
    }
}