refactor: split long functions in tv attention work

This commit is contained in:
Miguel Palhas
2026-08-23 16:51:29 +01:00
parent e8cea4aec5
commit 8ec1506098
2 changed files with 67 additions and 54 deletions
+51 -45
View File
@@ -1342,6 +1342,56 @@ mod tests {
async fn attention_queues_report_tv_series() {
let (_dir, state, base) = application().await;
let pool = state.database().expect("database").pool();
let (series_id, season_id, episode_id) = seed_queued_series(pool).await;
let queues: serde_json::Value = reqwest::get(format!("{base}/api/queues/attention"))
.await
.expect("queues")
.json()
.await
.expect("queues json");
assert_eq!(queues["tv_no_pt_source"][0]["series_id"], series_id);
assert_eq!(
queues["tv_no_pt_source"][0]["episodes"]
.as_array()
.map(Vec::len),
Some(2)
);
assert_eq!(queues["tv_needs_decision"][0]["series_id"], series_id);
assert_eq!(
queues["tv_needs_decision"][0]["episodes"],
serde_json::json!([episode_id])
);
assert_eq!(
queues["tv_needs_decision"][0]["seasons"],
serde_json::json!([season_id])
);
// Blocking the series empties its no-PT-source lane.
sqlx::query("UPDATE series SET blocked = 1 WHERE id = ?")
.bind(series_id)
.execute(pool)
.await
.expect("block series");
let queues: serde_json::Value = reqwest::get(format!("{base}/api/queues/attention"))
.await
.expect("blocked queues")
.json()
.await
.expect("blocked queues json");
assert_eq!(queues["tv_no_pt_source"].as_array().map(Vec::len), Some(0));
assert_eq!(
queues["tv_needs_decision"].as_array().map(Vec::len),
Some(1),
"hard failures queue regardless of blocking"
);
}
/// One series hitting all three §9.5 TV entry conditions: two wanted,
/// searched episodes whose every candidate was rejected for language; a
/// season pack that hard-failed; and an episode two different releases
/// hard-failed on.
async fn seed_queued_series(pool: &sqlx::SqlitePool) -> (i64, i64, i64) {
let root_id: i64 =
sqlx::query_scalar("SELECT id FROM roots WHERE kind = 'tv' AND audience = 'kids'")
.fetch_one(pool)
@@ -1364,8 +1414,6 @@ mod tests {
.await
.expect("season");
// Two wanted episodes whose every candidate was rejected for
// language — the §5.2 no-PT-source queue, TV side.
for number in [1, 2] {
sqlx::query(
"INSERT INTO episodes (season_id, number, title, wanted, state, search_attempts)
@@ -1378,8 +1426,6 @@ mod tests {
.await
.expect("episode");
}
// A season pack that hard-failed, plus an episode two different
// releases hard-failed on — both land in needs_decision.
sqlx::query(
"INSERT INTO episodes (season_id, number, title, wanted, state)
VALUES (?, 3, 'Episode 3', 1, 'missing')",
@@ -1425,46 +1471,6 @@ mod tests {
.expect("failed grab");
}
let queues: serde_json::Value = reqwest::get(format!("{base}/api/queues/attention"))
.await
.expect("queues")
.json()
.await
.expect("queues json");
assert_eq!(queues["tv_no_pt_source"][0]["series_id"], series_id);
assert_eq!(
queues["tv_no_pt_source"][0]["episodes"]
.as_array()
.map(Vec::len),
Some(2)
);
assert_eq!(queues["tv_needs_decision"][0]["series_id"], series_id);
assert_eq!(
queues["tv_needs_decision"][0]["episodes"],
serde_json::json!([episode_id])
);
assert_eq!(
queues["tv_needs_decision"][0]["seasons"],
serde_json::json!([season_id])
);
// Blocking the series empties its no-PT-source lane.
sqlx::query("UPDATE series SET blocked = 1 WHERE id = ?")
.bind(series_id)
.execute(pool)
.await
.expect("block series");
let queues: serde_json::Value = reqwest::get(format!("{base}/api/queues/attention"))
.await
.expect("blocked queues")
.json()
.await
.expect("blocked queues json");
assert_eq!(queues["tv_no_pt_source"].as_array().map(Vec::len), Some(0));
assert_eq!(
queues["tv_needs_decision"].as_array().map(Vec::len),
Some(1),
"hard failures queue regardless of blocking"
);
(series_id, season_id, episode_id)
}
}
+16 -9
View File
@@ -170,9 +170,7 @@ impl AttentionAction {
.fetch_all(database.pool())
.await?;
for row in tv_no_pt_source {
tv.entry(row.series_id)
.or_insert_with(|| (row.title, row.year, TvEntry::default()))
.2
tv_entry(&mut tv, row.series_id, row.title, row.year)
.no_pt_source
.push(row.episode_id);
}
@@ -193,9 +191,7 @@ impl AttentionAction {
.fetch_all(database.pool())
.await?;
for row in episode_hard_fails {
tv.entry(row.series_id)
.or_insert_with(|| (row.title, row.year, TvEntry::default()))
.2
tv_entry(&mut tv, row.series_id, row.title, row.year)
.hard_failed_episodes
.push(row.episode_id);
}
@@ -214,9 +210,7 @@ impl AttentionAction {
.fetch_all(database.pool())
.await?;
for row in season_pack_fails {
tv.entry(row.series_id)
.or_insert_with(|| (row.title, row.year, TvEntry::default()))
.2
tv_entry(&mut tv, row.series_id, row.title, row.year)
.failed_season_packs
.push(row.season_id);
}
@@ -267,6 +261,19 @@ fn title_with_year(title: &str, year: Option<i64>) -> String {
}
}
/// The series' roll-up entry, created empty on first sight.
fn tv_entry<'a>(
tv: &'a mut HashMap<i64, (String, Option<i64>, TvEntry)>,
series_id: i64,
title: String,
year: Option<i64>,
) -> &'a mut TvEntry {
&mut tv
.entry(series_id)
.or_insert_with(|| (title, year, TvEntry::default()))
.2
}
impl Action for AttentionAction {
fn name(&self) -> &'static str {
"attention"