From 0b967cbb14c23d7e1b2989b5b04f8a01e2fa3a21 Mon Sep 17 00:00:00 2001 From: Jon Seager Date: Tue, 3 Feb 2026 10:13:35 +0000 Subject: [PATCH] feat(gear): add filter paper category and optional brew association - Add migration to extend gear CHECK constraint with 'filter_paper' and add nullable filter_paper_id column to brews - Add FilterPaper variant to GearCategory enum - Add filter_paper_id to Brew, NewBrew, and BrewWithDetails - Add filter_paper_id to TimelineBrewData --- migrations/0011_add_filter_paper.sql | 22 ++++++++++++++++++++++ src/domain/brews.rs | 3 +++ src/domain/gear.rs | 5 +++++ src/domain/timeline.rs | 1 + 4 files changed, 31 insertions(+) create mode 100644 migrations/0011_add_filter_paper.sql diff --git a/migrations/0011_add_filter_paper.sql b/migrations/0011_add_filter_paper.sql new file mode 100644 index 0000000..ff7d8e2 --- /dev/null +++ b/migrations/0011_add_filter_paper.sql @@ -0,0 +1,22 @@ +-- Add 'filter_paper' gear category and optional filter_paper_id on brews. +-- +-- SQLite does not support altering CHECK constraints, so we recreate the gear +-- table with the updated constraint. + +CREATE TABLE gear_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + category TEXT NOT NULL CHECK (category IN ('grinder', 'brewer', 'filter_paper')), + make TEXT NOT NULL, + model TEXT NOT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +INSERT INTO gear_new (id, category, make, model, created_at, updated_at) +SELECT id, category, make, model, created_at, updated_at FROM gear; + +DROP TABLE gear; +ALTER TABLE gear_new RENAME TO gear; +CREATE INDEX idx_gear_category ON gear(category); + +ALTER TABLE brews ADD COLUMN filter_paper_id INTEGER REFERENCES gear(id) ON DELETE SET NULL; diff --git a/src/domain/brews.rs b/src/domain/brews.rs index b081531..233d20a 100644 --- a/src/domain/brews.rs +++ b/src/domain/brews.rs @@ -12,6 +12,7 @@ pub struct Brew { pub grinder_id: GearId, pub grind_setting: f64, pub brewer_id: GearId, + pub filter_paper_id: Option, pub water_volume: i32, pub water_temp: f64, pub created_at: DateTime, @@ -28,6 +29,7 @@ pub struct BrewWithDetails { pub roaster_slug: String, pub grinder_name: String, pub brewer_name: String, + pub filter_paper_name: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -37,6 +39,7 @@ pub struct NewBrew { pub grinder_id: GearId, pub grind_setting: f64, pub brewer_id: GearId, + pub filter_paper_id: Option, pub water_volume: i32, pub water_temp: f64, } diff --git a/src/domain/gear.rs b/src/domain/gear.rs index cfd8c2c..0eccb68 100644 --- a/src/domain/gear.rs +++ b/src/domain/gear.rs @@ -11,6 +11,8 @@ use super::listing::{SortDirection, SortKey}; pub enum GearCategory { Grinder, Brewer, + #[serde(rename = "filter_paper")] + FilterPaper, } impl GearCategory { @@ -18,6 +20,7 @@ impl GearCategory { match self { GearCategory::Grinder => "grinder", GearCategory::Brewer => "brewer", + GearCategory::FilterPaper => "filter_paper", } } @@ -25,6 +28,7 @@ impl GearCategory { match self { GearCategory::Grinder => "Grinder", GearCategory::Brewer => "Brewer", + GearCategory::FilterPaper => "Filter Paper", } } } @@ -36,6 +40,7 @@ impl FromStr for GearCategory { match s.to_lowercase().as_str() { "grinder" => Ok(GearCategory::Grinder), "brewer" => Ok(GearCategory::Brewer), + "filter_paper" => Ok(GearCategory::FilterPaper), _ => Err(()), } } diff --git a/src/domain/timeline.rs b/src/domain/timeline.rs index 13647d1..51a5048 100644 --- a/src/domain/timeline.rs +++ b/src/domain/timeline.rs @@ -16,6 +16,7 @@ pub struct TimelineBrewData { pub bag_id: i64, pub grinder_id: i64, pub brewer_id: i64, + pub filter_paper_id: Option, pub coffee_weight: f64, pub grind_setting: f64, pub water_volume: i32,