Skip to content

feat(core): add direct library ownership to media - #1462

Merged
aaronleopold merged 2 commits into
stumpapp:metadata-based-librariesfrom
ajselzilic:codex/metadata-library-ownership
Oct 6, 2026
Merged

aaronleopold merged 2 commits into
stumpapp:metadata-based-librariesfrom
ajselzilic:codex/metadata-library-ownership

Conversation

@ajselzilic

@ajselzilic ajselzilic commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Add direct library ownership to books

Adds direct library ownership to books and backfills existing ownership from their series. SQLite and PostgreSQL enforce valid ownership and matching library/series relationships. New books receive ownership during scanning.

This is the foundation for metadata-only libraries. Query refactors and the remaining feature work will follow in separate PRs.

AI assistance was used for implementation and review.

Refs #288

Ready?

Please read each item and check the boxes:

  • I read the contributing guidelines
  • I searched for existing issues or pull requests that may be related to my contribution
  • This PR is based into nightly and not main
  • I added tests and/or documentation for my changes if applicable
  • I disclosed any use of LLMs in the creation of this PR (if applicable)

Stump Contributor License Agreement

By contributing to Stump, you agree that your contributions will be licensed under the following licenses (where applicable):

@codecov

codecov Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 22.22222% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
core/src/media/prepare.rs 0.00% 4 Missing ⚠️
crates/models/src/entity/media.rs 0.00% 3 Missing ⚠️
Files with missing lines Coverage Δ
core/src/opds/v2_0/publication.rs 98.81% <100.00%> (+<0.01%) ⬆️
crates/graphql/src/mutation/emailer/sender.rs 93.37% <100.00%> (+<0.01%) ⬆️
crates/models/src/entity/media.rs 77.33% <0.00%> (-0.85%) ⬇️
core/src/media/prepare.rs 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aaronleopold aaronleopold left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, i had a few comments but i think anything of those worth sorting out can be sorted separately. thank you! i'll aim to merge later this evening / tomorrow am

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you test this works on SQLite? To my knowledge, you cannot alter a table and add fks (see here, section 5)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, leaving for posterity (and to showcase my wrong-ness, or at the very least imprecision in my initial understanding): it only works because you've allowed it to default to NULL, right? And you've sorta worked around the previously-linked constraint of:

It is not possible to use the "ALTER TABLE ... ADD COLUMN" syntax to add a column that includes a REFERENCES clause, unless the default value of the new column is NULL. Attempting to do so returns an error.

By doing that dance after where you add constraints/triggers (postgres, sqlite, respectively) after the fact. I think this is largely fine, the one part I'm a little concerned about is the disconnect it causes between postgres and sqlite. The alternative would be that table redefinition, which while it would give a real composite fk does carry a bit more weight to it wrt potential problems. Open to discussion if you have thoughts, this is going to a feature branch so won't block my approval on this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, tested on populated SQLite and Postgres databases, including rollback. The NULL default is what makes it work here.

Comment on lines +14 to +20
.query_one(Statement::from_string(
backend,
"SELECT media.id FROM media
LEFT JOIN series ON series.id = media.series_id
LEFT JOIN libraries ON libraries.id = series.library_id
WHERE libraries.id IS NULL LIMIT 1",
))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I don't necessarily find this scenario likely anyways, I imagine if orphan's exist we'd want to catch them all and not just the first one

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed on reporting all the orphans, I’ll include that in PR 2. I also found a difference when changing a library ID: Postgres cascades it, while SQLite’s triggers reject it. Normal edits don’t change IDs, but I’ll revisit constraint parity alongside the virtual-series migrations in PR 3.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended up addressing both in a small follow-up commit here: it now reports all orphan IDs and allows library ID changes to cascade on SQLite too. Tested on both databases, including rollback. SQLite still uses triggers.

@aaronleopold
aaronleopold merged commit 2ff898f into stumpapp:metadata-based-libraries Oct 6, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants