refactor: extract adapter-common crate — shared sqlx error mapping,
row-to-domain conversions, date/uuid utils Eliminates 39 map_err copies, consolidates parse_uuid/parse_datetime/ datetime_to_str/format_year_month, extracts 7 shared row-to-domain conversion functions (movie, review, watchlist, stats, user_summary). Row structs stay per-adapter (FromRow is db-specific), only conversion logic is shared. Net -281 lines.
This commit is contained in:
@@ -12,6 +12,7 @@ sqlx = { version = "0.8.6", features = [
|
||||
"chrono",
|
||||
] }
|
||||
activitypub = { workspace = true }
|
||||
adapter-common = { workspace = true }
|
||||
k-ap = { version = "0.4.1", registry = "gitea" }
|
||||
domain = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
|
||||
@@ -3,7 +3,8 @@ use async_trait::async_trait;
|
||||
use chrono::Utc;
|
||||
use k_ap::ActivityRepository;
|
||||
|
||||
use super::{PostgresFederationRepository, datetime_to_str};
|
||||
use adapter_common::datetime_to_str;
|
||||
use super::PostgresFederationRepository;
|
||||
|
||||
#[async_trait]
|
||||
impl ActivityRepository for PostgresFederationRepository {
|
||||
|
||||
@@ -4,7 +4,8 @@ use chrono::Utc;
|
||||
use k_ap::{ActorRepository, RemoteActor};
|
||||
use sqlx::Row;
|
||||
|
||||
use super::{PG_ACTOR_COLS, PostgresFederationRepository, datetime_to_str, pg_remote_actor};
|
||||
use adapter_common::datetime_to_str;
|
||||
use super::{PG_ACTOR_COLS, PostgresFederationRepository, pg_remote_actor};
|
||||
|
||||
#[async_trait]
|
||||
impl ActorRepository for PostgresFederationRepository {
|
||||
|
||||
@@ -12,7 +12,6 @@ use domain::{
|
||||
},
|
||||
};
|
||||
use sqlx::{PgPool, Row};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct PostgresApContentQuery {
|
||||
pool: PgPool,
|
||||
@@ -22,24 +21,11 @@ impl PostgresApContentQuery {
|
||||
pub fn new(pool: PgPool) -> Self {
|
||||
Self { pool }
|
||||
}
|
||||
|
||||
fn map_err(e: sqlx::Error) -> DomainError {
|
||||
tracing::error!("Database error: {:?}", e);
|
||||
DomainError::InfrastructureError("Database operation failed".into())
|
||||
}
|
||||
}
|
||||
|
||||
// ── Local row types ──────────────────────────────────────────────────────────
|
||||
|
||||
fn parse_uuid(s: &str) -> Result<Uuid, DomainError> {
|
||||
Uuid::parse_str(s)
|
||||
.map_err(|e| DomainError::InfrastructureError(format!("Invalid UUID '{}': {}", s, e)))
|
||||
}
|
||||
|
||||
fn parse_datetime(s: &str) -> Result<chrono::NaiveDateTime, DomainError> {
|
||||
chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S")
|
||||
.map_err(|e| DomainError::InfrastructureError(format!("Invalid datetime '{}': {}", s, e)))
|
||||
}
|
||||
use adapter_common::{parse_uuid, parse_datetime};
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
struct MovieRow {
|
||||
@@ -181,7 +167,7 @@ impl LocalApContentQuery for PostgresApContentQuery {
|
||||
.bind(&uid)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(Self::map_err)?;
|
||||
.map_err(adapter_common::map_sqlx_error)?;
|
||||
|
||||
rows.into_iter()
|
||||
.map(|row| {
|
||||
@@ -249,7 +235,7 @@ impl LocalApContentQuery for PostgresApContentQuery {
|
||||
.bind(&mid)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(Self::map_err)?;
|
||||
.map_err(adapter_common::map_sqlx_error)?;
|
||||
rows.into_iter().map(DiaryRow::into_domain).collect()
|
||||
}
|
||||
|
||||
@@ -282,7 +268,7 @@ impl LocalApContentQuery for PostgresApContentQuery {
|
||||
.bind(limit_i64)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(Self::map_err)?
|
||||
.map_err(adapter_common::map_sqlx_error)?
|
||||
} else {
|
||||
sqlx::query_as::<_, DiaryRow>(
|
||||
"SELECT m.id, m.external_metadata_id, m.title, m.release_year, m.director, m.poster_path,
|
||||
@@ -301,7 +287,7 @@ impl LocalApContentQuery for PostgresApContentQuery {
|
||||
.bind(limit_i64)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(Self::map_err)?
|
||||
.map_err(adapter_common::map_sqlx_error)?
|
||||
};
|
||||
rows.into_iter().map(DiaryRow::into_domain).collect()
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ use chrono::Utc;
|
||||
use k_ap::{BlockedDomain, BlocklistRepository};
|
||||
use sqlx::Row;
|
||||
|
||||
use super::{PostgresFederationRepository, datetime_to_str};
|
||||
use adapter_common::datetime_to_str;
|
||||
use super::PostgresFederationRepository;
|
||||
|
||||
#[async_trait]
|
||||
impl BlocklistRepository for PostgresFederationRepository {
|
||||
|
||||
@@ -6,8 +6,9 @@ use k_ap::{
|
||||
};
|
||||
use sqlx::Row;
|
||||
|
||||
use adapter_common::datetime_to_str;
|
||||
use super::{
|
||||
PG_ACTOR_COLS, PostgresFederationRepository, datetime_to_str, pg_remote_actor, status_to_str,
|
||||
PG_ACTOR_COLS, PostgresFederationRepository, pg_remote_actor, status_to_str,
|
||||
str_to_status,
|
||||
};
|
||||
|
||||
|
||||
@@ -12,14 +12,9 @@ mod watchlist;
|
||||
pub use ap_content::PostgresApContentQuery;
|
||||
pub use remote_goals::PostgresRemoteGoalRepository;
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
use k_ap::{FollowerStatus, RemoteActor};
|
||||
use sqlx::{PgPool, Row};
|
||||
|
||||
pub(crate) fn datetime_to_str(dt: &NaiveDateTime) -> String {
|
||||
dt.format("%Y-%m-%d %H:%M:%S").to_string()
|
||||
}
|
||||
|
||||
pub(crate) fn status_to_str(status: &FollowerStatus) -> &'static str {
|
||||
match status {
|
||||
FollowerStatus::Pending => "pending",
|
||||
|
||||
@@ -12,10 +12,6 @@ impl PostgresRemoteGoalRepository {
|
||||
Self { pool }
|
||||
}
|
||||
|
||||
fn map_err(e: sqlx::Error) -> DomainError {
|
||||
tracing::error!("Database error: {:?}", e);
|
||||
DomainError::InfrastructureError("Database operation failed".into())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -38,7 +34,7 @@ impl RemoteGoalRepository for PostgresRemoteGoalRepository {
|
||||
.bind(&received)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.map_err(Self::map_err)?;
|
||||
.map_err(adapter_common::map_sqlx_error)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -57,7 +53,7 @@ impl RemoteGoalRepository for PostgresRemoteGoalRepository {
|
||||
.bind(ap_id)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.map_err(Self::map_err)?;
|
||||
.map_err(adapter_common::map_sqlx_error)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -68,7 +64,7 @@ impl RemoteGoalRepository for PostgresRemoteGoalRepository {
|
||||
.bind(actor_url)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.map_err(Self::map_err)?;
|
||||
.map_err(adapter_common::map_sqlx_error)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -78,7 +74,7 @@ impl RemoteGoalRepository for PostgresRemoteGoalRepository {
|
||||
.bind(actor_url)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.map_err(Self::map_err)?;
|
||||
.map_err(adapter_common::map_sqlx_error)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -92,7 +88,7 @@ impl RemoteGoalRepository for PostgresRemoteGoalRepository {
|
||||
.bind(actor_url)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(Self::map_err)?;
|
||||
.map_err(adapter_common::map_sqlx_error)?;
|
||||
|
||||
rows.iter()
|
||||
.map(|r| {
|
||||
|
||||
@@ -3,7 +3,8 @@ use anyhow::{Result, anyhow};
|
||||
use async_trait::async_trait;
|
||||
use domain::models::{Review, ReviewSource};
|
||||
|
||||
use super::{PostgresFederationRepository, datetime_to_str};
|
||||
use adapter_common::datetime_to_str;
|
||||
use super::PostgresFederationRepository;
|
||||
|
||||
#[async_trait]
|
||||
impl RemoteReviewRepository for PostgresFederationRepository {
|
||||
|
||||
Reference in New Issue
Block a user