feat(db): store poster, backdrop and rating on titles

§9.6 keeps rich detail out of the database except for the three fields
pure-SQL views need. Adds poster_path, backdrop_path and vote_average to
movies and series, written by the daily metadata refresh in both lanes
and filled at add time from the TMDB response the create flows already
fetch.
This commit is contained in:
Miguel Palhas
2026-08-23 22:12:05 +01:00
parent 9bd037d1b6
commit 8478c0f8a9
14 changed files with 484 additions and 78 deletions
+32
View File
@@ -228,6 +228,38 @@ mod tests {
}
}
/// §9.6: the stored artwork columns are nullable, and `REAL` is a valid
/// STRICT type — a rating must not be squeezed into an integer.
#[tokio::test]
async fn title_artwork_columns_are_nullable_and_take_reals() {
let (_dir, db) = fresh().await;
sqlx::query(
"INSERT INTO movies (tmdb_id, title, root_id)
SELECT 1, 'No Artwork Yet', id FROM roots WHERE kind = 'movie' LIMIT 1",
)
.execute(db.pool())
.await
.expect("row without artwork");
sqlx::query(
"UPDATE movies SET poster_path = '/dune.jpg', backdrop_path = '/dune-wide.jpg',
vote_average = 8.152
WHERE tmdb_id = 1",
)
.execute(db.pool())
.await
.expect("artwork write");
let (poster, backdrop, vote): (Option<String>, Option<String>, Option<f64>) =
sqlx::query_as("SELECT poster_path, backdrop_path, vote_average FROM movies")
.fetch_one(db.pool())
.await
.expect("movie row");
assert_eq!(poster.as_deref(), Some("/dune.jpg"));
assert_eq!(backdrop.as_deref(), Some("/dune-wide.jpg"));
assert_eq!(vote, Some(8.152));
}
#[tokio::test]
async fn foreign_keys_are_enforced() {
let (_dir, db) = fresh().await;