cleanup: strip comments, extract constants, DRY shared helpers across adapters + infra-wiring
- strip all comments except WHY workaround notes (3 remain) - remove all #[allow(dead_code)]; fix via _prefix rename - extract named constants: JWT time units, token types, default config values, jellyfin fallback bitrate - DRY: move serialize_enum_as_string, content_type_str, parse_content_type, parse_genres_blob to adapter-common - sqlite+postgres library.rs use shared helpers instead of local copies - sqlite+postgres channel.rs use shared serialize_enum_as_string - remove dead `let _ = ext` in scanner.rs
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
//! PostgreSQL adapter for activity log (ActivityLogCommand + ActivityLogQuery).
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::Utc;
|
||||
use sqlx::PgPool;
|
||||
@@ -62,7 +60,6 @@ impl ActivityLogQuery for PgActivityLog {
|
||||
|
||||
let mut events = Vec::with_capacity(rows.len());
|
||||
for (id_str, ts_str, event_type, detail, channel_id_str) in rows {
|
||||
// Silently skip rows with bad UUIDs/timestamps (mirrors old behaviour)
|
||||
let Ok(id) = parse_uuid(&id_str, "activity id") else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! PostgreSQL adapter for channel persistence (ChannelCommand + ChannelQuery).
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::{PgPool, Row};
|
||||
@@ -7,7 +5,7 @@ use uuid::Uuid;
|
||||
|
||||
use adapter_common::{
|
||||
map_sqlx_error, parse_dt, parse_enum_or_default, parse_recycle_policy, parse_schedule_config,
|
||||
parse_uuid,
|
||||
parse_uuid, serialize_enum_as_string,
|
||||
};
|
||||
use domain::{
|
||||
ports::channel::{ChannelCommand, ChannelQuery},
|
||||
@@ -25,8 +23,6 @@ impl PgChannelRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Row type ----------------------------------------------------------------
|
||||
|
||||
const SELECT_COLS: &str = "id, owner_id, name, description, timezone, schedule_config, recycle_policy, auto_schedule, access_mode, access_password_hash, logo, logo_position, logo_opacity, webhook_url, webhook_poll_interval_secs, webhook_body_template, webhook_headers, created_at, updated_at";
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
@@ -85,15 +81,6 @@ impl ChannelRow {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Helpers ------------------------------------------------------------------
|
||||
|
||||
fn serialize_enum_as_string<T: serde::Serialize>(v: &T, fallback: &str) -> String {
|
||||
serde_json::to_value(v)
|
||||
.ok()
|
||||
.and_then(|v| v.as_str().map(str::to_owned))
|
||||
.unwrap_or_else(|| fallback.to_owned())
|
||||
}
|
||||
|
||||
fn map_snapshot_row(
|
||||
row: &sqlx::postgres::PgRow,
|
||||
channel_id: ChannelId,
|
||||
@@ -117,8 +104,6 @@ fn map_snapshot_row(
|
||||
))
|
||||
}
|
||||
|
||||
// -- Command -----------------------------------------------------------------
|
||||
|
||||
#[async_trait]
|
||||
impl ChannelCommand for PgChannelRepository {
|
||||
async fn save(&self, channel: &Channel) -> DomainResult<()> {
|
||||
@@ -261,8 +246,6 @@ impl ChannelCommand for PgChannelRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Query -------------------------------------------------------------------
|
||||
|
||||
#[async_trait]
|
||||
impl ChannelQuery for PgChannelRepository {
|
||||
async fn find_by_id(&self, id: ChannelId) -> DomainResult<Option<Channel>> {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
//! PostgreSQL adapter crate — implements all CQRS-split repository port traits
|
||||
//! for PostgreSQL via sqlx.
|
||||
|
||||
pub mod activity;
|
||||
pub mod channel;
|
||||
pub mod library;
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
//! PostgreSQL adapter for library persistence (LibraryCommand + LibraryQuery).
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use adapter_common::{content_type_str, parse_content_type, parse_genres_blob};
|
||||
use domain::{
|
||||
ports::library::{LibraryCommand, LibraryQuery},
|
||||
ContentType, DomainError, DomainResult, LibraryCollection, LibraryItem, LibrarySearchFilter,
|
||||
@@ -21,26 +18,6 @@ impl PgLibraryRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Helpers -----------------------------------------------------------------
|
||||
|
||||
fn content_type_str(ct: &ContentType) -> &'static str {
|
||||
match ct {
|
||||
ContentType::Movie => "movie",
|
||||
ContentType::Episode => "episode",
|
||||
ContentType::Short => "short",
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_content_type(s: &str) -> ContentType {
|
||||
match s {
|
||||
"episode" => ContentType::Episode,
|
||||
"short" => ContentType::Short,
|
||||
_ => ContentType::Movie,
|
||||
}
|
||||
}
|
||||
|
||||
// -- Row types ---------------------------------------------------------------
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
struct LibraryItemRow {
|
||||
id: String,
|
||||
@@ -113,8 +90,6 @@ struct SeasonSummaryRow {
|
||||
thumbnail_url: Option<String>,
|
||||
}
|
||||
|
||||
// -- Command -----------------------------------------------------------------
|
||||
|
||||
#[async_trait]
|
||||
impl LibraryCommand for PgLibraryRepository {
|
||||
async fn upsert_items(&self, _provider_id: &str, items: Vec<LibraryItem>) -> DomainResult<()> {
|
||||
@@ -223,8 +198,6 @@ impl LibraryCommand for PgLibraryRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Query -------------------------------------------------------------------
|
||||
|
||||
#[async_trait]
|
||||
impl LibraryQuery for PgLibraryRepository {
|
||||
async fn search(
|
||||
@@ -505,26 +478,7 @@ impl LibraryQuery for PgLibraryRepository {
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
.map(|r| {
|
||||
let genres: Vec<String> = r
|
||||
.genres_blob
|
||||
.split("],[")
|
||||
.flat_map(|chunk| {
|
||||
let cleaned = chunk.trim_start_matches('[').trim_end_matches(']');
|
||||
cleaned
|
||||
.split(',')
|
||||
.filter_map(|s| {
|
||||
let s = s.trim().trim_matches('"');
|
||||
if s.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(s.to_string())
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<HashSet<_>>()
|
||||
.into_iter()
|
||||
.collect();
|
||||
let genres = parse_genres_blob(&r.genres_blob);
|
||||
ShowSummary::from_persistence(
|
||||
r.series_name,
|
||||
r.episode_count as u32,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! PostgreSQL adapter for provider config (ProviderConfigCommand + ProviderConfigQuery).
|
||||
|
||||
use async_trait::async_trait;
|
||||
use sqlx::PgPool;
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! PostgreSQL adapter for schedule persistence (ScheduleCommand + ScheduleQuery).
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
@@ -22,8 +20,6 @@ impl PgScheduleRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Row types ---------------------------------------------------------------
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
struct ScheduleRow {
|
||||
id: String,
|
||||
@@ -36,8 +32,8 @@ struct ScheduleRow {
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
struct SlotRow {
|
||||
id: String,
|
||||
#[allow(dead_code)]
|
||||
schedule_id: String,
|
||||
#[sqlx(rename = "schedule_id")]
|
||||
_schedule_id: String,
|
||||
start_at: String,
|
||||
end_at: String,
|
||||
item: String,
|
||||
@@ -59,8 +55,6 @@ struct PlaybackRecordRow {
|
||||
generation: i64,
|
||||
}
|
||||
|
||||
// -- Mapping -----------------------------------------------------------------
|
||||
|
||||
fn map_slot_row(row: SlotRow) -> DomainResult<ScheduledSlot> {
|
||||
let id = SlotId::from_uuid(parse_uuid(&row.id, "slot id")?);
|
||||
let source_block_id = BlockId::from_uuid(parse_uuid(&row.source_block_id, "block id")?);
|
||||
@@ -103,8 +97,6 @@ fn map_playback_row(row: PlaybackRecordRow) -> DomainResult<PlaybackRecord> {
|
||||
))
|
||||
}
|
||||
|
||||
// -- Internal helpers --------------------------------------------------------
|
||||
|
||||
impl PgScheduleRepository {
|
||||
async fn fetch_slots(&self, schedule_id: &str) -> DomainResult<Vec<SlotRow>> {
|
||||
sqlx::query_as(
|
||||
@@ -118,8 +110,6 @@ impl PgScheduleRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Command -----------------------------------------------------------------
|
||||
|
||||
#[async_trait]
|
||||
impl ScheduleCommand for PgScheduleRepository {
|
||||
async fn save(&self, schedule: &GeneratedSchedule) -> DomainResult<()> {
|
||||
@@ -142,7 +132,6 @@ impl ScheduleCommand for PgScheduleRepository {
|
||||
.await
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
// Delete-then-insert all slots
|
||||
sqlx::query("DELETE FROM scheduled_slots WHERE schedule_id = $1")
|
||||
.bind(schedule.id().value().to_string())
|
||||
.execute(&self.pool)
|
||||
@@ -216,8 +205,6 @@ impl ScheduleCommand for PgScheduleRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Query -------------------------------------------------------------------
|
||||
|
||||
#[async_trait]
|
||||
impl ScheduleQuery for PgScheduleRepository {
|
||||
async fn find_active(
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! PostgreSQL adapter for app settings (AppSettingsRepository).
|
||||
|
||||
use async_trait::async_trait;
|
||||
use sqlx::PgPool;
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! PostgreSQL adapter for transcode settings (TranscodeSettingsRepository).
|
||||
|
||||
use async_trait::async_trait;
|
||||
use sqlx::PgPool;
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! PostgreSQL adapter for user persistence (UserCommand + UserQuery).
|
||||
|
||||
use async_trait::async_trait;
|
||||
use sqlx::PgPool;
|
||||
|
||||
@@ -19,8 +17,6 @@ impl PgUserRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Row type for query_as --------------------------------------------------
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
struct UserRow {
|
||||
id: String,
|
||||
@@ -49,8 +45,6 @@ impl UserRow {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Command -----------------------------------------------------------------
|
||||
|
||||
#[async_trait]
|
||||
impl UserCommand for PgUserRepository {
|
||||
async fn save(&self, user: &User) -> DomainResult<()> {
|
||||
@@ -98,8 +92,6 @@ impl UserCommand for PgUserRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// -- Query -------------------------------------------------------------------
|
||||
|
||||
#[async_trait]
|
||||
impl UserQuery for PgUserRepository {
|
||||
async fn find_by_id(&self, id: UserId) -> DomainResult<Option<User>> {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
//! Wiring function that instantiates all PostgreSQL repositories and returns them
|
||||
//! as trait-object Arcs.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use sqlx::PgPool;
|
||||
@@ -27,7 +24,6 @@ use crate::{
|
||||
user::PgUserRepository,
|
||||
};
|
||||
|
||||
/// All PostgreSQL adapter outputs, ready to be injected into the application layer.
|
||||
pub struct PostgresWireOutput {
|
||||
pub user_command: Arc<dyn UserCommand>,
|
||||
pub user_query: Arc<dyn UserQuery>,
|
||||
@@ -45,10 +41,6 @@ pub struct PostgresWireOutput {
|
||||
pub transcode_settings: Arc<dyn TranscodeSettingsRepository>,
|
||||
}
|
||||
|
||||
/// Create all PostgreSQL repository implementations from a single pool.
|
||||
///
|
||||
/// Each struct wraps a clone of the same pool. Repositories that implement
|
||||
/// both Command and Query traits share a single `Arc` via `.clone()`.
|
||||
pub fn wire(pool: PgPool) -> PostgresWireOutput {
|
||||
let user = Arc::new(PgUserRepository::new(pool.clone()));
|
||||
let channel = Arc::new(PgChannelRepository::new(pool.clone()));
|
||||
|
||||
Reference in New Issue
Block a user