use chrono::{DateTime, Utc};
use sqlx::types::Json;
use sqlx::{Error, Executor, Postgres, Row};
use dialtone_common::ap::Actor;
use dialtone_common::rest::actors::actor_model::ActorPage;
use dialtone_common::rest::actors::actor_reference::ActorReferenceType;
use crate::db::actor_reference::ActorReferenceDbType;
use crate::db::{bind_params, date_range_condition, make_where_clause, CondParam};
pub async fn page_actors_by_reference(
exec: impl Executor<'_, Database = Postgres>,
prev_date: Option<&DateTime<Utc>>,
next_date: Option<&DateTime<Utc>>,
limit: i32,
subject_actor_id: &str,
reference_type: &ActorReferenceType,
) -> Result<Option<ActorPage>, sqlx::Error> {
let pre_select = r#"
select
min(modified_at),
max(modified_at),
json_agg(activity_pub_json)
from (
select
actor.activity_pub_json,
actor.modified_at
from actor, actor_reference
"#;
let post_select = r#"
and
actor.visibility != 'Banned'
and
actor.id = actor_reference.object_actor_id
order by actor.modified_at asc
limit $1) as actors
"#;
let mut conditions: Vec<String> = Vec::new();
let mut params: Vec<CondParam> = vec![CondParam::String(subject_actor_id)];
conditions.push(format!(
"actor_reference.subject_actor_id = ${}",
params.len() + 1
));
let reference_type_string = ActorReferenceDbType::from(reference_type).to_string();
params.push(CondParam::String(&reference_type_string));
conditions.push(format!(
"actor_reference.reference_type = ${}::actor_reference_type",
params.len() + 1
));
let (conditions, params) = date_range_condition(
prev_date,
next_date,
"actor.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, ¶ms);
let result = query.fetch_optional(exec).await?;
match result {
None => Ok(None),
Some(row) => {
let page_values = row.try_get::<Json<Vec<Actor>>, 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(ActorPage {
min_modified_at,
max_modified_at,
page_values: value.0,
}))
}
Err(err) => match err {
Error::ColumnDecode { .. } => Ok(None),
_ => Err(err),
},
}
}
}
}