feat(db): SQLite schema and movie migrations #48

Merged
naps62-yolo merged 1 commits from issue/4-db into main 2026-08-22 19:36:40 +01:00
Owner

Closes #4.

Movie side of the model in §4: policies, roots, movies, media_files,
releases, grabs, blacklist, owners, title_owners. No series tables —
those are #34.

WAL, foreign_keys on and synchronous = NORMAL are set in
SqliteConnectOptions, not in a migration, since SQLite resets foreign_keys
per connection. Tables are STRICT.

Indices cover the four scans the reconcile loop makes, verified by query plan:

EXPLAIN QUERY PLAN
SELECT id FROM movies WHERE wanted = 1 AND blocked = 0 ORDER BY last_searched_at
`--SCAN movies USING COVERING INDEX movies_pending_search

SELECT id FROM movies WHERE state = 'grabbed'
`--SEARCH movies USING COVERING INDEX movies_state (state=?)

SELECT id FROM media_files WHERE probed IS NULL
`--SCAN media_files USING INDEX media_files_unprobed

SELECT * FROM blacklist WHERE normalised_name = 'x'
`--SEARCH blacklist USING INDEX blacklist_name (normalised_name=?)

just db-reset recreates the development database; just db-prepare refreshes
the committed .sqlx data, which is what keeps CI off a live database. just ci
passes with DATABASE_URL unset and no dev.db present.

Two things worth flagging. The 1080p size band is invented — §5.5 gives numbers
for 4K only, and §14 already marks all of them as placeholders. The state
column is missing | grabbed | imported, which is my reading of §7.3 and §8
rather than something the design spells out; #7 owns the canonical enum and can
tighten the CHECK.

Closes #4. Movie side of the model in §4: `policies`, `roots`, `movies`, `media_files`, `releases`, `grabs`, `blacklist`, `owners`, `title_owners`. No series tables — those are #34. WAL, `foreign_keys` on and `synchronous = NORMAL` are set in `SqliteConnectOptions`, not in a migration, since SQLite resets `foreign_keys` per connection. Tables are `STRICT`. Indices cover the four scans the reconcile loop makes, verified by query plan: <details> <summary>EXPLAIN QUERY PLAN</summary> ``` SELECT id FROM movies WHERE wanted = 1 AND blocked = 0 ORDER BY last_searched_at `--SCAN movies USING COVERING INDEX movies_pending_search SELECT id FROM movies WHERE state = 'grabbed' `--SEARCH movies USING COVERING INDEX movies_state (state=?) SELECT id FROM media_files WHERE probed IS NULL `--SCAN media_files USING INDEX media_files_unprobed SELECT * FROM blacklist WHERE normalised_name = 'x' `--SEARCH blacklist USING INDEX blacklist_name (normalised_name=?) ``` </details> `just db-reset` recreates the development database; `just db-prepare` refreshes the committed `.sqlx` data, which is what keeps CI off a live database. `just ci` passes with `DATABASE_URL` unset and no `dev.db` present. Two things worth flagging. The 1080p size band is invented — §5.5 gives numbers for 4K only, and §14 already marks all of them as placeholders. The `state` column is `missing | grabbed | imported`, which is my reading of §7.3 and §8 rather than something the design spells out; #7 owns the canonical enum and can tighten the CHECK.
naps62-yolo added 1 commit 2026-08-22 19:33:34 +01:00
feat(db): SQLite schema and movie migrations
ci / web (pull_request) Successful in 6s
ci / rust (pull_request) Successful in 1m0s
ac0d2a45e5
Movie side of DESIGN.md §4 only; series, seasons and episodes are #34.
Policies and the two movie roots are seeded from §5.1 because policy
lives in the database, not config (§10).

The committed .sqlx offline data keeps CI off a live database.
naps62-yolo reviewed 2026-08-22 19:35:52 +01:00
naps62-yolo left a comment
Author
Owner

Reviewed ac0d2a45e5b3bb2393407988d7175651fd5c9a0e. No findings.

Reviewed `ac0d2a45e5b3bb2393407988d7175651fd5c9a0e`. No findings. <!-- agent-meta: {"model":"gpt-5.6","session":"01a02abf"} -->
naps62-yolo merged commit 84777169d0 into main 2026-08-22 19:36:40 +01:00
naps62-yolo deleted branch issue/4-db 2026-08-22 19:36:40 +01:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: yolo/arr#48