Workstream C: convert commands/storage to a folder module, extract thumbnail/people/series-prefs commands
- Move commands/storage.rs to commands/storage/mod.rs. - Extract three cohesive, self-contained clusters: - storage/thumbnails.rs: thumbnail cache + image-URL commands. - storage/people.rs: person/cast metadata cache commands. - storage/series_prefs.rs: per-series preferred audio track commands. - Re-exported via pub use so command names stay at commands::storage::*; invoke_handler unchanged. mod.rs shrinks from 1979 to 1500 lines, all tests pass.
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
//! Person/cast metadata cache commands.
|
||||
|
||||
use std::sync::Arc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::State;
|
||||
|
||||
use super::DatabaseWrapper;
|
||||
use crate::storage::db_service::{DatabaseService, Query, QueryParam};
|
||||
|
||||
|
||||
/// Cached person info returned to frontend
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CachedPerson {
|
||||
pub id: String,
|
||||
pub server_id: String,
|
||||
pub name: String,
|
||||
pub overview: Option<String>,
|
||||
pub primary_image_tag: Option<String>,
|
||||
pub premiere_date: Option<String>,
|
||||
pub end_date: Option<String>,
|
||||
}
|
||||
|
||||
/// Item-person association for caching
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CachedItemPerson {
|
||||
pub item_id: String,
|
||||
pub person_id: String,
|
||||
pub server_id: String,
|
||||
pub person_type: String,
|
||||
pub role: Option<String>,
|
||||
pub sort_order: i32,
|
||||
}
|
||||
|
||||
/// Save a person to the cache
|
||||
#[tauri::command]
|
||||
pub async fn storage_save_person(
|
||||
db: State<'_, DatabaseWrapper>,
|
||||
person: CachedPerson,
|
||||
) -> Result<(), String> {
|
||||
let db_service = {
|
||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||
Arc::new(database.service())
|
||||
};
|
||||
|
||||
let query = Query::with_params(
|
||||
"INSERT OR REPLACE INTO people (
|
||||
id, server_id, name, overview, primary_image_tag,
|
||||
premiere_date, end_date, synced_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)",
|
||||
vec![
|
||||
QueryParam::String(person.id),
|
||||
QueryParam::String(person.server_id),
|
||||
QueryParam::String(person.name),
|
||||
person.overview.map(QueryParam::String).unwrap_or(QueryParam::Null),
|
||||
person.primary_image_tag.map(QueryParam::String).unwrap_or(QueryParam::Null),
|
||||
person.premiere_date.map(QueryParam::String).unwrap_or(QueryParam::Null),
|
||||
person.end_date.map(QueryParam::String).unwrap_or(QueryParam::Null),
|
||||
],
|
||||
);
|
||||
|
||||
db_service.execute(query).await.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get a cached person by ID
|
||||
#[tauri::command]
|
||||
pub async fn storage_get_person(
|
||||
db: State<'_, DatabaseWrapper>,
|
||||
person_id: String,
|
||||
) -> Result<Option<CachedPerson>, String> {
|
||||
let db_service = {
|
||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||
Arc::new(database.service())
|
||||
};
|
||||
|
||||
let query = Query::with_params(
|
||||
"SELECT id, server_id, name, overview, primary_image_tag, premiere_date, end_date
|
||||
FROM people WHERE id = ?",
|
||||
vec![QueryParam::String(person_id)],
|
||||
);
|
||||
|
||||
let result = db_service
|
||||
.query_optional(query, |row| {
|
||||
Ok(CachedPerson {
|
||||
id: row.get(0)?,
|
||||
server_id: row.get(1)?,
|
||||
name: row.get(2)?,
|
||||
overview: row.get(3)?,
|
||||
primary_image_tag: row.get(4)?,
|
||||
premiere_date: row.get(5)?,
|
||||
end_date: row.get(6)?,
|
||||
})
|
||||
})
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Save item-person associations (batch)
|
||||
#[tauri::command]
|
||||
pub async fn storage_save_item_people(
|
||||
db: State<'_, DatabaseWrapper>,
|
||||
associations: Vec<CachedItemPerson>,
|
||||
) -> Result<(), String> {
|
||||
let db_service = {
|
||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||
Arc::new(database.service())
|
||||
};
|
||||
|
||||
// Clone associations for the closure
|
||||
let associations_clone = associations.clone();
|
||||
|
||||
// Use transaction for batch insert
|
||||
db_service.transaction(move |tx| {
|
||||
for assoc in &associations_clone {
|
||||
let query = Query::with_params(
|
||||
"INSERT OR REPLACE INTO item_people (
|
||||
item_id, person_id, server_id, person_type, role, sort_order, synced_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)",
|
||||
vec![
|
||||
QueryParam::String(assoc.item_id.clone()),
|
||||
QueryParam::String(assoc.person_id.clone()),
|
||||
QueryParam::String(assoc.server_id.clone()),
|
||||
QueryParam::String(assoc.person_type.clone()),
|
||||
assoc.role.clone().map(QueryParam::String).unwrap_or(QueryParam::Null),
|
||||
QueryParam::Int(assoc.sort_order),
|
||||
],
|
||||
);
|
||||
tx.execute(query)?;
|
||||
}
|
||||
Ok(())
|
||||
}).await.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get people for an item (with person details joined)
|
||||
#[tauri::command]
|
||||
pub async fn storage_get_item_people(
|
||||
db: State<'_, DatabaseWrapper>,
|
||||
item_id: String,
|
||||
) -> Result<Vec<CachedItemPerson>, String> {
|
||||
let db_service = {
|
||||
let database = db.0.lock().map_err(|e| e.to_string())?;
|
||||
Arc::new(database.service())
|
||||
};
|
||||
|
||||
let query = Query::with_params(
|
||||
"SELECT ip.item_id, ip.person_id, ip.server_id, ip.person_type, ip.role, ip.sort_order
|
||||
FROM item_people ip
|
||||
WHERE ip.item_id = ?
|
||||
ORDER BY ip.sort_order ASC",
|
||||
vec![QueryParam::String(item_id)],
|
||||
);
|
||||
|
||||
let people = db_service
|
||||
.query_many(query, |row| {
|
||||
Ok(CachedItemPerson {
|
||||
item_id: row.get(0)?,
|
||||
person_id: row.get(1)?,
|
||||
server_id: row.get(2)?,
|
||||
person_type: row.get(3)?,
|
||||
role: row.get(4)?,
|
||||
sort_order: row.get(5)?,
|
||||
})
|
||||
})
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(people)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user