dialtone_sqlx 0.1.0

Dialtone SQLx Back-End
Documentation
use chrono::{DateTime, Utc};
use sqlx::types::Json;
use sqlx::{Error, Executor, Postgres, Row};

use dialtone_common::ap::ap_object::ApObject;
use dialtone_common::rest::ap_objects::ap_object_model::ApObjectPage;
use dialtone_common::rest::ap_objects::ap_object_reference::ApObjectReferenceType;

use crate::db::ap_object_reference::ApObjectReferenceDbType;
use crate::db::{bind_params, date_range_condition, make_where_clause, CondParam};

pub async fn page_ap_objects_by_reference(
    exec: impl Executor<'_, Database = Postgres>,
    prev_date: Option<&DateTime<Utc>>,
    next_date: Option<&DateTime<Utc>>,
    limit: i32,
    actor_id: &str,
    reference_type: &ApObjectReferenceType,
) -> Result<Option<ApObjectPage>, sqlx::Error> {
    let pre_select = r#"
        select
            min(modified_at),
            max(modified_at),
            json_agg(activity_pub_json)
        from (
            select
                ap_object.activity_pub_json,
                ap_object.modified_at
            from ap_object, ap_object_reference
    "#;
    let post_select = r#"
        and
        ap_object.visibility = 'Visible' 
        and
        ap_object.id = ap_object_reference.ap_object_id
        order by ap_object.modified_at asc
        limit $1) as ap_object"#;
    let mut conditions: Vec<String> = Vec::new();
    let mut params: Vec<CondParam> = vec![CondParam::String(actor_id)];
    conditions.push(format!(
        "ap_object_reference.actor_id = ${}",
        params.len() + 1
    ));
    let reference_type_string = ApObjectReferenceDbType::from(reference_type).to_string();
    params.push(CondParam::String(&reference_type_string));
    conditions.push(format!(
        "ap_object_reference.reference_type = ${}::ap_object_reference_type",
        params.len() + 1
    ));
    let (conditions, params) = date_range_condition(
        prev_date,
        next_date,
        "ap_object.modified_at",
        conditions,
        params,
    );
    let where_clause = make_where_clause(&conditions);
    let sql = format!("{} {} {}", pre_select, where_clause, post_select);
    let mut query = sqlx::query(&sql).bind(limit);
    query = bind_params(query, &params);
    // left here for future reference
    // println!("sql = {}", query.sql());
    let result = query.fetch_optional(exec).await?;
    match result {
        None => Ok(None),
        Some(row) => {
            let page_values = row.try_get::<Json<Vec<ApObject>>, usize>(2);
            match page_values {
                Ok(value) => {
                    let min_modified_at = row.get::<DateTime<Utc>, usize>(0);
                    let max_modified_at = row.get::<DateTime<Utc>, usize>(1);
                    Ok(Some(ApObjectPage {
                        min_modified_at,
                        max_modified_at,
                        page_values: value.0,
                    }))
                }
                Err(err) => match err {
                    Error::ColumnDecode { .. } => Ok(None),
                    _ => Err(err),
                },
            }
        }
    }
}