Add and apply a models.rs convention for data-model structs
All checks were successful
CI / check (pull_request) Successful in 2m2s
CI / test (pull_request) Successful in 3m15s
CI / audit (pull_request) Successful in 10s

Document in the DoD that data-model structs (domain models, query row
types, DTOs/views) belong in a crate's models.rs rather than the file
that produces/consumes them, once used outside that function -
matching the existing crates/core/src/models.rs pattern. Component-
local structs (Props, Styles, context) are exempt.

Apply it to db: move RankedArticleRow out of articles.rs into a new
crates/db/src/models.rs.
This commit is contained in:
Austin Schaefer 2026-09-03 21:23:34 +02:00
parent f4b7e95d15
commit e70909af47
4 changed files with 21 additions and 11 deletions

View file

@ -14,6 +14,13 @@ A change is done when all of the following hold, not just when it compiles.
- Within `db`, one file per domain concern (`feeds.rs`, `articles.rs`, - Within `db`, one file per domain concern (`feeds.rs`, `articles.rs`,
`reading_events.rs`, `affinities.rs`) — a new table gets its own file, `reading_events.rs`, `affinities.rs`) — a new table gets its own file,
not a growing `queries.rs`. not a growing `queries.rs`.
- Data-model structs (domain models, query row types, DTOs/views) live in
a crate's `models.rs` rather than the file that produces or consumes
them, whenever a struct is used outside the function that builds it —
matching the existing `crates/core/src/models.rs` pattern. This doesn't
apply to structs that are inherently local to one file/component (e.g.
a Dioxus component's `Props`/`Styles`/context struct, or a helper
struct scoped to a single function's internals).
## DRY, but not premature ## DRY, but not premature

View file

@ -1,3 +1,4 @@
use crate::models::RankedArticleRow;
use crate::schema; use crate::schema;
use crate::Db; use crate::Db;
use anyhow::Result; use anyhow::Result;
@ -7,17 +8,6 @@ use diesel_async::RunQueryDsl;
use feedsignal_core::Article; use feedsignal_core::Article;
use uuid::Uuid; use uuid::Uuid;
/// One row of [`Db::list_ranked_articles`].
pub struct RankedArticleRow {
pub id: String,
pub feed_id: String,
pub title: String,
pub url: String,
pub summary: String,
pub topics: Vec<String>,
pub final_score: Option<f32>,
}
impl Db { impl Db {
pub async fn insert_article(&self, article: &Article) -> Result<()> { pub async fn insert_article(&self, article: &Article) -> Result<()> {
use schema::articles::dsl; use schema::articles::dsl;

View file

@ -1,7 +1,10 @@
mod affinities; mod affinities;
mod articles; mod articles;
mod feeds; mod feeds;
mod models;
mod reading_events; mod reading_events;
pub use models::RankedArticleRow;
pub(crate) mod schema; pub(crate) mod schema;
use anyhow::Result; use anyhow::Result;

10
crates/db/src/models.rs Normal file
View file

@ -0,0 +1,10 @@
/// One row of [`crate::Db::list_ranked_articles`].
pub struct RankedArticleRow {
pub id: String,
pub feed_id: String,
pub title: String,
pub url: String,
pub summary: String,
pub topics: Vec<String>,
pub final_score: Option<f32>,
}