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:
2026-07-10 05:44:42 +02:00
parent 6a9b4e5c00
commit c224cc6bd2
66 changed files with 924 additions and 971 deletions

View File

@@ -3,7 +3,8 @@ use async_trait::async_trait;
use chrono::Utc;
use k_ap::ActivityRepository;
use super::{SqliteFederationRepository, datetime_to_str};
use adapter_common::datetime_to_str;
use super::SqliteFederationRepository;
#[async_trait]
impl ActivityRepository for SqliteFederationRepository {

View File

@@ -4,7 +4,8 @@ use chrono::Utc;
use k_ap::{ActorRepository, RemoteActor};
use sqlx::Row;
use super::{SqliteFederationRepository, datetime_to_str, remote_actor_from_row};
use adapter_common::datetime_to_str;
use super::{SqliteFederationRepository, remote_actor_from_row};
#[async_trait]
impl ActorRepository for SqliteFederationRepository {

View File

@@ -12,7 +12,6 @@ use domain::{
},
};
use sqlx::SqlitePool;
use uuid::Uuid;
pub struct SqliteApContentQuery {
pool: SqlitePool,
@@ -23,23 +22,11 @@ impl SqliteApContentQuery {
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 {
@@ -215,7 +202,7 @@ impl LocalApContentQuery for SqliteApContentQuery {
.bind(&uid)
.fetch_all(&self.pool)
.await
.map_err(Self::map_err)?;
.map_err(adapter_common::map_sqlx_error)?;
rows.into_iter().map(WatchlistRow::into_domain).collect()
}
@@ -235,7 +222,7 @@ impl LocalApContentQuery for SqliteApContentQuery {
.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()
}
@@ -264,7 +251,7 @@ impl LocalApContentQuery for SqliteApContentQuery {
.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,
@@ -279,7 +266,7 @@ impl LocalApContentQuery for SqliteApContentQuery {
.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()
}

View File

@@ -4,7 +4,8 @@ use chrono::Utc;
use k_ap::{BlockedDomain, BlocklistRepository};
use sqlx::Row;
use super::{SqliteFederationRepository, datetime_to_str};
use adapter_common::datetime_to_str;
use super::SqliteFederationRepository;
#[async_trait]
impl BlocklistRepository for SqliteFederationRepository {

View File

@@ -6,8 +6,9 @@ use k_ap::{
};
use sqlx::Row;
use adapter_common::datetime_to_str;
use super::{
SqliteFederationRepository, datetime_to_str, remote_actor_from_row, status_to_str,
SqliteFederationRepository, remote_actor_from_row, status_to_str,
str_to_status,
};

View File

@@ -13,14 +13,9 @@ pub mod remote_goals;
pub use ap_content::SqliteApContentQuery;
pub use remote_goals::SqliteRemoteGoalRepository;
use chrono::NaiveDateTime;
use k_ap::{FollowerStatus, RemoteActor};
use sqlx::SqlitePool;
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",

View File

@@ -12,10 +12,6 @@ impl SqliteRemoteGoalRepository {
Self { pool }
}
fn map_err(e: sqlx::Error) -> DomainError {
tracing::error!("Database error: {:?}", e);
DomainError::InfrastructureError("Database operation failed".into())
}
}
#[async_trait]
@@ -36,7 +32,7 @@ impl RemoteGoalRepository for SqliteRemoteGoalRepository {
.bind(&received)
.execute(&self.pool)
.await
.map_err(Self::map_err)?;
.map_err(adapter_common::map_sqlx_error)?;
Ok(())
}
@@ -53,7 +49,7 @@ impl RemoteGoalRepository for SqliteRemoteGoalRepository {
.bind(ap_id)
.execute(&self.pool)
.await
.map_err(Self::map_err)?;
.map_err(adapter_common::map_sqlx_error)?;
Ok(())
}
@@ -64,7 +60,7 @@ impl RemoteGoalRepository for SqliteRemoteGoalRepository {
.bind(actor_url)
.execute(&self.pool)
.await
.map_err(Self::map_err)?;
.map_err(adapter_common::map_sqlx_error)?;
Ok(())
}
@@ -74,7 +70,7 @@ impl RemoteGoalRepository for SqliteRemoteGoalRepository {
.bind(actor_url)
.execute(&self.pool)
.await
.map_err(Self::map_err)?;
.map_err(adapter_common::map_sqlx_error)?;
Ok(())
}
@@ -87,7 +83,7 @@ impl RemoteGoalRepository for SqliteRemoteGoalRepository {
.bind(actor_url)
.fetch_all(&self.pool)
.await
.map_err(Self::map_err)?;
.map_err(adapter_common::map_sqlx_error)?;
rows.iter()
.map(|r| {

View File

@@ -3,7 +3,8 @@ use anyhow::{Result, anyhow};
use async_trait::async_trait;
use domain::models::{Review, ReviewSource};
use super::{SqliteFederationRepository, datetime_to_str};
use adapter_common::datetime_to_str;
use super::SqliteFederationRepository;
#[async_trait]
impl RemoteReviewRepository for SqliteFederationRepository {