From 1f5561d7ab238bb5b70a7f97cbf5897537b794b9 Mon Sep 17 00:00:00 2001 From: Jon Seager Date: Mon, 2 Feb 2026 15:24:34 +0000 Subject: [PATCH] feat(cli): add Gear CLI commands Implement complete CLI interface for managing gear via brewlog CLI. Commands (presentation/cli/gear.rs): - add-gear: Create gear with --category, --make, --model, --notes flags - list-gear: List all gear with optional --category filter - get-gear: Retrieve single gear by --id - update-gear: Update gear fields (make, model, notes) - delete-gear: Delete gear by --id Uses define_get_command! and define_delete_command! macros for get/delete operations to reduce boilerplate. Command Registration: - Register gear module in presentation/cli/mod.rs - Add commands to Commands enum: AddGear, ListGear, GetGear, UpdateGear, DeleteGear - Wire command execution in main.rs All commands output JSON and use BrewlogClient for HTTP API calls. Examples: brewlog add-gear --category grinder --make Baratza --model Encore brewlog list-gear --category brewer brewlog update-gear --id 1 --notes "Updated notes" --- src/main.rs | 9 ++++- src/presentation/cli/gear.rs | 67 ++++++++++++++++++++++++++++++++++++ src/presentation/cli/mod.rs | 16 +++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/presentation/cli/gear.rs diff --git a/src/main.rs b/src/main.rs index 5990b36..34533be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use anyhow::Result; use brewlog::application::{ServerConfig, serve}; use brewlog::infrastructure::client::BrewlogClient; -use brewlog::presentation::cli::{Cli, Commands, ServeCommand, bags, roasters, roasts, tokens}; +use brewlog::presentation::cli::{Cli, Commands, ServeCommand, bags, gear, roasters, roasts, tokens}; use clap::Parser; use tracing::{Subscriber, subscriber::set_global_default}; @@ -47,6 +47,13 @@ async fn main() -> Result<()> { Commands::UpdateBag(cmd) => bags::update_bag(&client, cmd).await, Commands::DeleteBag(cmd) => bags::delete_bag(&client, cmd).await, + // Gear + Commands::AddGear(cmd) => gear::add_gear(&client, cmd).await, + Commands::ListGear(cmd) => gear::list_gear(&client, cmd).await, + Commands::GetGear(cmd) => gear::get_gear(&client, cmd).await, + Commands::UpdateGear(cmd) => gear::update_gear(&client, cmd).await, + Commands::DeleteGear(cmd) => gear::delete_gear(&client, cmd).await, + Commands::Serve(_) => unreachable!("serve command handled earlier"), } } diff --git a/src/presentation/cli/gear.rs b/src/presentation/cli/gear.rs new file mode 100644 index 0000000..b32afec --- /dev/null +++ b/src/presentation/cli/gear.rs @@ -0,0 +1,67 @@ +use anyhow::Result; +use clap::Args; + +use super::macros::{define_delete_command, define_get_command}; +use super::print_json; +use crate::domain::ids::GearId; +use crate::infrastructure::client::BrewlogClient; + +#[derive(Debug, Args)] +pub struct AddGearCommand { + #[arg(long)] + pub category: String, + #[arg(long)] + 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) + .await?; + print_json(&gear) +} + +#[derive(Debug, Args)] +pub struct ListGearCommand { + #[arg(long)] + pub category: Option, +} + +pub async fn list_gear(client: &BrewlogClient, command: ListGearCommand) -> Result<()> { + let gear = client.gear().list(command.category).await?; + print_json(&gear) +} + +define_get_command!(GetGearCommand, get_gear, GearId, gear); + +#[derive(Debug, Args)] +pub struct UpdateGearCommand { + #[arg(long)] + pub id: i64, + #[arg(long)] + 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, + ) + .await?; + print_json(&gear) +} + +define_delete_command!(DeleteGearCommand, delete_gear, GearId, gear, "gear"); diff --git a/src/presentation/cli/mod.rs b/src/presentation/cli/mod.rs index a9a6460..d296322 100644 --- a/src/presentation/cli/mod.rs +++ b/src/presentation/cli/mod.rs @@ -1,4 +1,5 @@ pub mod bags; +pub mod gear; mod macros; pub mod roasters; pub mod roasts; @@ -8,6 +9,9 @@ use std::net::SocketAddr; use bags::{AddBagCommand, DeleteBagCommand, GetBagCommand, ListBagsCommand, UpdateBagCommand}; use clap::{Args, Parser, Subcommand}; +use gear::{ + AddGearCommand, DeleteGearCommand, GetGearCommand, ListGearCommand, UpdateGearCommand, +}; use roasters::{AddRoasterCommand, DeleteRoasterCommand, GetRoasterCommand, UpdateRoasterCommand}; use roasts::{AddRoastCommand, DeleteRoastCommand, GetRoastCommand, ListRoastsCommand}; use tokens::{CreateTokenCommand, RevokeTokenCommand}; @@ -73,6 +77,18 @@ pub enum Commands { UpdateBag(UpdateBagCommand), #[command(name = "delete-bag")] DeleteBag(DeleteBagCommand), + + // Gear + #[command(name = "add-gear")] + AddGear(AddGearCommand), + #[command(name = "list-gear")] + ListGear(ListGearCommand), + #[command(name = "get-gear")] + GetGear(GetGearCommand), + #[command(name = "update-gear")] + UpdateGear(UpdateGearCommand), + #[command(name = "delete-gear")] + DeleteGear(DeleteGearCommand), } #[derive(Debug, Args)]