From 6bbbafbef42859d44a6f5043a971b4843aa933a3 Mon Sep 17 00:00:00 2001 From: Jon Seager Date: Mon, 2 Feb 2026 16:16:54 +0000 Subject: [PATCH] refactor(gear): remove notes field from Gear entity The notes field was not providing enough value to justify its presence. Simplified the Gear entity by removing notes from: - Domain structs (Gear, NewGear, UpdateGear) - SQL repository queries and GearRecord - HTTP client methods - CLI commands (--notes flag) - Web views and templates - All related tests Added migration 0008_remove_gear_notes.sql to drop the column. --- migrations/0008_remove_gear_notes.sql | 1 + src/application/routes/gear.rs | 2 -- src/domain/gear.rs | 3 -- src/infrastructure/client/gear.rs | 12 ++------ src/infrastructure/repositories/gear.rs | 21 ++++++------- src/presentation/cli/gear.rs | 18 ++---------- src/presentation/web/views.rs | 2 -- templates/gear.html | 9 ------ templates/partials/gear_list.html | 4 --- tests/cli/gear_cli.rs | 39 +------------------------ tests/server/datastar.rs | 2 -- tests/server/gear_api.rs | 7 +---- tests/server/timeline.rs | 3 +- 13 files changed, 17 insertions(+), 106 deletions(-) create mode 100644 migrations/0008_remove_gear_notes.sql diff --git a/migrations/0008_remove_gear_notes.sql b/migrations/0008_remove_gear_notes.sql new file mode 100644 index 0000000..80522c5 --- /dev/null +++ b/migrations/0008_remove_gear_notes.sql @@ -0,0 +1 @@ +ALTER TABLE gear DROP COLUMN notes; diff --git a/src/application/routes/gear.rs b/src/application/routes/gear.rs index fd415dd..33bd2a8 100644 --- a/src/application/routes/gear.rs +++ b/src/application/routes/gear.rs @@ -202,7 +202,6 @@ pub(crate) struct NewGearSubmission { category: String, make: String, model: String, - notes: Option, } impl NewGearSubmission { @@ -222,7 +221,6 @@ impl NewGearSubmission { category, make: self.make, model: self.model, - notes: self.notes.filter(|s| !s.trim().is_empty()), }) } } diff --git a/src/domain/gear.rs b/src/domain/gear.rs index 8bc8a5a..cfd8c2c 100644 --- a/src/domain/gear.rs +++ b/src/domain/gear.rs @@ -47,7 +47,6 @@ pub struct Gear { pub category: GearCategory, pub make: String, pub model: String, - pub notes: Option, pub created_at: DateTime, pub updated_at: DateTime, } @@ -57,14 +56,12 @@ pub struct NewGear { pub category: GearCategory, pub make: String, pub model: String, - pub notes: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UpdateGear { pub make: Option, pub model: Option, - pub notes: Option, } #[derive(Debug, Default, Clone)] diff --git a/src/infrastructure/client/gear.rs b/src/infrastructure/client/gear.rs index b83263f..99c23f5 100644 --- a/src/infrastructure/client/gear.rs +++ b/src/infrastructure/client/gear.rs @@ -14,19 +14,12 @@ impl<'a> GearClient<'a> { Self { inner } } - pub async fn create( - &self, - category: &str, - make: String, - model: String, - notes: Option, - ) -> Result { + pub async fn create(&self, category: &str, make: String, model: String) -> Result { let url = self.inner.endpoint("api/v1/gear")?; let payload = serde_json::json!({ "category": category, "make": make, "model": model, - "notes": notes, }); let response = self @@ -73,10 +66,9 @@ impl<'a> GearClient<'a> { id: GearId, make: Option, model: Option, - notes: Option, ) -> Result { let url = self.inner.endpoint(&format!("api/v1/gear/{id}"))?; - let payload = UpdateGear { make, model, notes }; + let payload = UpdateGear { make, model }; let response = self .inner diff --git a/src/infrastructure/repositories/gear.rs b/src/infrastructure/repositories/gear.rs index 8fd7c70..85cf3a9 100644 --- a/src/infrastructure/repositories/gear.rs +++ b/src/infrastructure/repositories/gear.rs @@ -46,7 +46,6 @@ impl SqlGearRepository { category, make: record.make, model: record.model, - notes: record.notes, created_at: record.created_at, updated_at: record.updated_at, }) @@ -64,16 +63,15 @@ impl SqlGearRepository { impl GearRepository for SqlGearRepository { async fn insert(&self, gear: NewGear) -> Result { let query = r#" - INSERT INTO gear (category, make, model, notes) - VALUES (?, ?, ?, ?) - RETURNING id, category, make, model, notes, created_at, updated_at + INSERT INTO gear (category, make, model) + VALUES (?, ?, ?) + RETURNING id, category, make, model, created_at, updated_at "#; let record = query_as::<_, GearRecord>(query) .bind(gear.category.as_str()) .bind(&gear.make) .bind(&gear.model) - .bind(&gear.notes) .fetch_one(&self.pool) .await .map_err(|err| RepositoryError::unexpected(err.to_string()))?; @@ -83,7 +81,7 @@ impl GearRepository for SqlGearRepository { async fn get(&self, id: GearId) -> Result { let query = r#" - SELECT id, category, make, model, notes, created_at, updated_at + SELECT id, category, make, model, created_at, updated_at FROM gear WHERE id = ? "#; @@ -108,11 +106,12 @@ impl GearRepository for SqlGearRepository { let base_query = match &where_clause { Some(w) => format!( - "SELECT id, category, make, model, notes, created_at, updated_at FROM gear WHERE {}", + "SELECT id, category, make, model, created_at, updated_at FROM gear WHERE {}", w ), - None => "SELECT id, category, make, model, notes, created_at, updated_at FROM gear" - .to_string(), + None => { + "SELECT id, category, make, model, created_at, updated_at FROM gear".to_string() + } }; let count_query = match &where_clause { @@ -137,12 +136,11 @@ impl GearRepository for SqlGearRepository { push_update_field!(builder, sep, "make", changes.make); push_update_field!(builder, sep, "model", changes.model); - push_update_field!(builder, sep, "notes", changes.notes); let _ = sep; // Suppress unused_assignments warning builder.push(" WHERE id = "); builder.push_bind(id.into_inner()); - builder.push(" RETURNING id, category, make, model, notes, created_at, updated_at"); + builder.push(" RETURNING id, category, make, model, created_at, updated_at"); let record = builder .build_query_as::() @@ -177,7 +175,6 @@ struct GearRecord { category: String, make: String, model: String, - notes: Option, created_at: DateTime, updated_at: DateTime, } diff --git a/src/presentation/cli/gear.rs b/src/presentation/cli/gear.rs index 8f574aa..922b96b 100644 --- a/src/presentation/cli/gear.rs +++ b/src/presentation/cli/gear.rs @@ -14,19 +14,12 @@ pub struct AddGearCommand { pub make: String, #[arg(long)] pub model: String, - #[arg(long)] - pub notes: Option, } pub async fn add_gear(client: &BrewlogClient, command: AddGearCommand) -> Result<()> { let gear = client .gear() - .create( - &command.category, - command.make, - command.model, - command.notes, - ) + .create(&command.category, command.make, command.model) .await?; print_json(&gear) } @@ -52,19 +45,12 @@ pub struct UpdateGearCommand { pub make: Option, #[arg(long)] pub model: Option, - #[arg(long)] - pub notes: Option, } pub async fn update_gear(client: &BrewlogClient, command: UpdateGearCommand) -> Result<()> { let gear = client .gear() - .update( - GearId::new(command.id), - command.make, - command.model, - command.notes, - ) + .update(GearId::new(command.id), command.make, command.model) .await?; print_json(&gear) } diff --git a/src/presentation/web/views.rs b/src/presentation/web/views.rs index dac8949..b3f305b 100644 --- a/src/presentation/web/views.rs +++ b/src/presentation/web/views.rs @@ -565,7 +565,6 @@ pub struct GearView { pub make: String, pub model: String, pub full_name: String, - pub notes: String, pub created_at: String, } @@ -578,7 +577,6 @@ impl GearView { make: gear.make.clone(), model: gear.model.clone(), full_name: format!("{} {}", gear.make, gear.model), - notes: gear.notes.unwrap_or_else(|| "No notes.".to_string()), created_at: gear.created_at.format("%Y-%m-%d").to_string(), } } diff --git a/templates/gear.html b/templates/gear.html index d1cbefb..b0c6c86 100644 --- a/templates/gear.html +++ b/templates/gear.html @@ -69,15 +69,6 @@ placeholder="Encore" /> -
diff --git a/templates/partials/gear_list.html b/templates/partials/gear_list.html index e444770..9a90b49 100644 --- a/templates/partials/gear_list.html +++ b/templates/partials/gear_list.html @@ -19,7 +19,6 @@ {% call table::sortable_header("Category", "category", navigator, "#gear-list") %} {% call table::sortable_header("Make", "make", navigator, "#gear-list") %} {% call table::sortable_header("Model", "model", navigator, "#gear-list") %} - Notes {% call table::sortable_header("Added", "created-at", navigator, "#gear-list") %} {% if is_authenticated %} @@ -42,9 +41,6 @@ {{ item.model }} - -
{{ item.notes }}
- {{ item.created_at }} diff --git a/tests/cli/gear_cli.rs b/tests/cli/gear_cli.rs index 0051bd8..a6d948e 100644 --- a/tests/cli/gear_cli.rs +++ b/tests/cli/gear_cli.rs @@ -50,34 +50,6 @@ fn test_add_gear_with_authentication() { assert!(gear["id"].is_i64()); } -#[test] -fn test_add_gear_with_notes() { - let token = create_token("test-add-gear-notes"); - - let output = run_brewlog( - &[ - "add-gear", - "--category", - "brewer", - "--make", - "Hario", - "--model", - "V60", - "--notes", - "Size 02 plastic", - ], - &[("BREWLOG_TOKEN", &token)], - ); - - assert!(output.status.success()); - let gear: Value = serde_json::from_slice(&output.stdout).unwrap(); - - assert_eq!(gear["make"], "Hario"); - assert_eq!(gear["model"], "V60"); - assert_eq!(gear["category"], "brewer"); - assert_eq!(gear["notes"], "Size 02 plastic"); -} - #[test] fn test_list_gear_works_without_authentication() { let _ = server_info(); @@ -235,15 +207,7 @@ fn test_update_gear_with_authentication() { // Update gear let output = run_brewlog( - &[ - "update-gear", - "--id", - &gear_id, - "--model", - "Mini II", - "--notes", - "Upgraded version", - ], + &["update-gear", "--id", &gear_id, "--model", "Mini II"], &[("BREWLOG_TOKEN", &token)], ); @@ -251,7 +215,6 @@ fn test_update_gear_with_authentication() { let updated_gear: Value = serde_json::from_slice(&output.stdout).unwrap(); assert_eq!(updated_gear["make"], "Porlex"); assert_eq!(updated_gear["model"], "Mini II"); - assert_eq!(updated_gear["notes"], "Upgraded version"); } #[test] diff --git a/tests/server/datastar.rs b/tests/server/datastar.rs index 23132b8..824cc57 100644 --- a/tests/server/datastar.rs +++ b/tests/server/datastar.rs @@ -655,7 +655,6 @@ async fn gear_update_with_datastar_header_returns_fragment() { let update = brewlog::domain::gear::UpdateGear { make: Some("Updated Make".to_string()), model: None, - notes: Some("Test notes".to_string()), }; let response = client @@ -700,7 +699,6 @@ async fn gear_update_without_datastar_header_returns_json() { let update = brewlog::domain::gear::UpdateGear { make: Some("JSON Updated".to_string()), model: None, - notes: None, }; let response = client diff --git a/tests/server/gear_api.rs b/tests/server/gear_api.rs index e00abfb..d32e714 100644 --- a/tests/server/gear_api.rs +++ b/tests/server/gear_api.rs @@ -10,8 +10,7 @@ async fn creating_gear_returns_201_for_valid_data() { let new_gear = serde_json::json!({ "category": "grinder", "make": "Baratza", - "model": "Encore", - "notes": "Daily driver" + "model": "Encore" }); // Act @@ -29,7 +28,6 @@ async fn creating_gear_returns_201_for_valid_data() { let gear: Gear = response.json().await.expect("Failed to parse response"); assert_eq!(gear.make, "Baratza"); assert_eq!(gear.model, "Encore"); - assert_eq!(gear.notes, Some("Daily driver".to_string())); } #[tokio::test] @@ -284,7 +282,6 @@ async fn updating_gear_returns_updated_data() { let update = UpdateGear { make: Some("Comandante".to_string()), model: Some("C40".to_string()), - notes: Some("Upgraded grinder".to_string()), }; let response = client @@ -302,7 +299,6 @@ async fn updating_gear_returns_updated_data() { assert_eq!(updated_gear.id, created_gear.id); assert_eq!(updated_gear.make, "Comandante"); assert_eq!(updated_gear.model, "C40"); - assert_eq!(updated_gear.notes, Some("Upgraded grinder".to_string())); } #[tokio::test] @@ -314,7 +310,6 @@ async fn updating_gear_without_auth_returns_401() { let update = UpdateGear { make: Some("Updated".to_string()), model: None, - notes: None, }; // Act diff --git a/tests/server/timeline.rs b/tests/server/timeline.rs index a413b9c..71f092f 100644 --- a/tests/server/timeline.rs +++ b/tests/server/timeline.rs @@ -421,8 +421,7 @@ async fn creating_gear_surfaces_on_the_timeline() { let gear_submission = serde_json::json!({ "category": "grinder", "make": "Baratza", - "model": "Encore", - "notes": "Timeline test grinder" + "model": "Encore" }); let response = client