use async_trait::async_trait; use chrono::{DateTime, Utc}; use domain::{ errors::DomainError, models::remote_actor::RemoteActor, ports::RemoteActorRepository, }; use sqlx::PgPool; pub struct PgRemoteActorRepository { pool: PgPool, } impl PgRemoteActorRepository { pub fn new(pool: PgPool) -> Self { Self { pool } } } #[async_trait] impl RemoteActorRepository for PgRemoteActorRepository { async fn upsert(&self, a: &RemoteActor) -> Result<(), DomainError> { sqlx::query( "INSERT INTO remote_actors(url,handle,display_name,inbox_url,shared_inbox_url,public_key,last_fetched_at) VALUES($1,$2,$3,$4,$5,$6,$7) ON CONFLICT(url) DO UPDATE SET handle=EXCLUDED.handle,display_name=EXCLUDED.display_name, inbox_url=EXCLUDED.inbox_url,shared_inbox_url=EXCLUDED.shared_inbox_url, public_key=EXCLUDED.public_key,last_fetched_at=EXCLUDED.last_fetched_at" ) .bind(&a.url).bind(&a.handle).bind(&a.display_name).bind(&a.inbox_url) .bind(&a.shared_inbox_url).bind(&a.public_key).bind(a.last_fetched_at) .execute(&self.pool).await.map_err(|e| DomainError::Internal(e.to_string())).map(|_| ()) } async fn find_by_url(&self, url: &str) -> Result, DomainError> { #[derive(sqlx::FromRow)] struct Row { url: String, handle: String, display_name: Option, inbox_url: String, shared_inbox_url: Option, public_key: String, last_fetched_at: DateTime, } sqlx::query_as::<_, Row>( "SELECT url,handle,display_name,inbox_url,shared_inbox_url,public_key,last_fetched_at FROM remote_actors WHERE url=$1" ).bind(url).fetch_optional(&self.pool).await .map_err(|e| DomainError::Internal(e.to_string())) .map(|o| o.map(|r| RemoteActor { url: r.url, handle: r.handle, display_name: r.display_name, inbox_url: r.inbox_url, shared_inbox_url: r.shared_inbox_url, public_key: r.public_key, last_fetched_at: r.last_fetched_at })) } }