feat(db): season_releases table and season policy loader

This commit is contained in:
Miguel Palhas
2026-08-23 16:49:42 +01:00
parent 93ccea2de0
commit 42a0895975
6 changed files with 303 additions and 0 deletions
@@ -0,0 +1,98 @@
{
"db_name": "SQLite",
"query": "\n SELECT s.overrides AS \"overrides!: String\",\n r.id AS \"root_id!: i64\",\n r.kind AS \"root_kind!: String\",\n r.audience AS \"root_audience!: String\",\n r.path AS \"root_path!: String\",\n p.id AS \"policy_id!: i64\",\n p.name AS \"policy_name!: String\",\n p.required_audio AS \"required_audio!: String\",\n p.dub_blacklist AS \"dub_blacklist!: String\",\n p.hdr_rules AS \"hdr_rules!: String\",\n p.size_bands AS \"size_bands!: String\",\n p.resolution_pref AS \"resolution_pref!: String\",\n p.source_weights AS \"source_weights!: String\",\n p.score_weights AS \"score_weights!: String\"\n FROM seasons se\n JOIN series s ON s.id = se.series_id\n JOIN roots r ON r.id = s.root_id\n JOIN policies p ON p.id = r.policy_id\n WHERE se.id = ?\n ",
"describe": {
"columns": [
{
"name": "overrides!: String",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "root_id!: i64",
"ordinal": 1,
"type_info": "Integer"
},
{
"name": "root_kind!: String",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "root_audience!: String",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "root_path!: String",
"ordinal": 4,
"type_info": "Text"
},
{
"name": "policy_id!: i64",
"ordinal": 5,
"type_info": "Integer"
},
{
"name": "policy_name!: String",
"ordinal": 6,
"type_info": "Text"
},
{
"name": "required_audio!: String",
"ordinal": 7,
"type_info": "Text"
},
{
"name": "dub_blacklist!: String",
"ordinal": 8,
"type_info": "Text"
},
{
"name": "hdr_rules!: String",
"ordinal": 9,
"type_info": "Text"
},
{
"name": "size_bands!: String",
"ordinal": 10,
"type_info": "Text"
},
{
"name": "resolution_pref!: String",
"ordinal": 11,
"type_info": "Text"
},
{
"name": "source_weights!: String",
"ordinal": 12,
"type_info": "Text"
},
{
"name": "score_weights!: String",
"ordinal": 13,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false
]
},
"hash": "729af2ef365c572428b2ef1edcd0e287a243607735185be7d67fe3f7d7c3c506"
}
@@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "SELECT EXISTS(SELECT 1 FROM season_releases WHERE season_id = ? AND release_id = ?) AS 'exists!: bool'",
"describe": {
"columns": [
{
"name": "exists!: bool",
"ordinal": 0,
"type_info": "Integer"
}
],
"parameters": {
"Right": 2
},
"nullable": [
false
]
},
"hash": "9758f269a51528417e6f75785441ade93fed055b6bcc4b5e7f579be5cc0aa829"
}
@@ -0,0 +1,86 @@
{
"db_name": "SQLite",
"query": "SELECT r.id AS \"id!: i64\", r.indexer_id AS \"indexer_id!: i64\", r.guid AS \"guid!: String\", r.name AS \"name!: String\", r.size AS \"size!: i64\", r.seeders, r.publish_date, r.download_url AS \"download_url!: String\", r.parsed AS \"parsed!: serde_json::Value\", r.score, r.verdict, r.rejected_rule FROM releases r JOIN season_releases sr ON sr.release_id = r.id WHERE sr.season_id = ? ORDER BY CASE r.verdict WHEN 'eligible' THEN 0 WHEN 'waived' THEN 1 ELSE 2 END, r.score DESC, r.id",
"describe": {
"columns": [
{
"name": "id!: i64",
"ordinal": 0,
"type_info": "Integer"
},
{
"name": "indexer_id!: i64",
"ordinal": 1,
"type_info": "Integer"
},
{
"name": "guid!: String",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "name!: String",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "size!: i64",
"ordinal": 4,
"type_info": "Integer"
},
{
"name": "seeders",
"ordinal": 5,
"type_info": "Integer"
},
{
"name": "publish_date",
"ordinal": 6,
"type_info": "Text"
},
{
"name": "download_url!: String",
"ordinal": 7,
"type_info": "Text"
},
{
"name": "parsed!: serde_json::Value",
"ordinal": 8,
"type_info": "Text"
},
{
"name": "score",
"ordinal": 9,
"type_info": "Float"
},
{
"name": "verdict",
"ordinal": 10,
"type_info": "Text"
},
{
"name": "rejected_rule",
"ordinal": 11,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
true,
false,
false,
false,
false,
true,
true,
false,
false,
true,
true,
true
]
},
"hash": "aaf6f4f7243bffa925fa17c9af3afb91c076ae3976b11cf18eb7583b8ce69a7e"
}
@@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "SELECT blocked AS \"blocked!: bool\" FROM series WHERE id = ?",
"describe": {
"columns": [
{
"name": "blocked!: bool",
"ordinal": 0,
"type_info": "Integer"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "f6dae636487a0d5eab2ee45c2ae455e065bfb670ce4c39a5bea04ceaff05780f"
}
@@ -0,0 +1,10 @@
-- The season counterpart of episode_releases (0006). A targeted season search
-- returns packs the operator has not committed to, which is the wrong grain
-- for a table that links a release to one episode (DESIGN.md §9.3, issue 125).
CREATE TABLE season_releases (
season_id INTEGER NOT NULL REFERENCES seasons (id) ON DELETE CASCADE,
release_id INTEGER NOT NULL REFERENCES releases (id) ON DELETE CASCADE,
PRIMARY KEY (season_id, release_id)
) STRICT;
CREATE INDEX season_releases_release ON season_releases (release_id);
+69
View File
@@ -275,6 +275,75 @@ impl Db {
root_path: row.root_path,
}))
}
/// The policy attached to a season's series root, with that series'
/// overrides. Same rule as [`Db::episode_policy`]: overrides sit on the
/// series (§5.1), never on a season.
///
/// `None` when the season does not exist.
///
/// # Errors
///
/// If the query fails, or a policy column does not hold the JSON its
/// migration promises.
pub async fn season_policy(&self, season_id: i64) -> Result<Option<TitlePolicy>, PolicyError> {
let row = sqlx::query!(
r#"
SELECT s.overrides AS "overrides!: String",
r.id AS "root_id!: i64",
r.kind AS "root_kind!: String",
r.audience AS "root_audience!: String",
r.path AS "root_path!: String",
p.id AS "policy_id!: i64",
p.name AS "policy_name!: String",
p.required_audio AS "required_audio!: String",
p.dub_blacklist AS "dub_blacklist!: String",
p.hdr_rules AS "hdr_rules!: String",
p.size_bands AS "size_bands!: String",
p.resolution_pref AS "resolution_pref!: String",
p.source_weights AS "source_weights!: String",
p.score_weights AS "score_weights!: String"
FROM seasons se
JOIN series s ON s.id = se.series_id
JOIN roots r ON r.id = s.root_id
JOIN policies p ON p.id = r.policy_id
WHERE se.id = ?
"#,
season_id
)
.fetch_optional(self.pool())
.await?;
let Some(row) = row else {
return Ok(None);
};
let overrides: OverridesJson = json("overrides", &row.overrides)?;
let policy = PolicyColumns {
id: row.policy_id,
name: row.policy_name,
required_audio: row.required_audio,
dub_blacklist: row.dub_blacklist,
hdr_rules: row.hdr_rules,
size_bands: row.size_bands,
resolution_pref: row.resolution_pref,
source_weights: row.source_weights,
score_weights: row.score_weights,
}
.to_policy()?;
Ok(Some(TitlePolicy {
policy,
overrides: TitleOverrides {
only_4k: overrides.only_4k,
allow_english_audio: overrides.allow_english_audio,
},
root_id: row.root_id,
root_kind: row.root_kind,
root_audience: row.root_audience,
root_path: row.root_path,
}))
}
}
/// A BCP-47 tag as the policy columns write it.