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),
},
}
}
}
}