Documentation
¶
Overview ¶
Package beans is a tiny CRUD store for coffee beans. The user tags a shot with the bag of beans they pulled it with, so later the app can answer "how was my ninja natural last week" and the AI coach can factor origin/roast age into its suggestions.
Index ¶
- Variables
- type Bean
- type Input
- type Store
- func (s *Store) ActiveDefaults(ctx context.Context) (id, grind string, rpm *float64, err error)
- func (s *Store) ActiveID(ctx context.Context) (string, error)
- func (s *Store) Create(ctx context.Context, in Input) (*Bean, error)
- func (s *Store) Delete(ctx context.Context, id string) error
- func (s *Store) Get(ctx context.Context, id string) (*Bean, error)
- func (s *Store) List(ctx context.Context) ([]Bean, error)
- func (s *Store) SetActive(ctx context.Context, id string) error
- func (s *Store) Update(ctx context.Context, id string, in Input) (*Bean, error)
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = errors.New("bean not found")
ErrNotFound is returned by Get/Update/Delete when the id doesn't exist.
Functions ¶
This section is empty.
Types ¶
type Bean ¶
type Bean struct {
ID string `json:"id"`
Name string `json:"name"`
Roaster string `json:"roaster,omitempty"`
Origin string `json:"origin,omitempty"` // country / farm / blend
Process string `json:"process,omitempty"` // washed / natural / honey / etc
RoastLevel string `json:"roast_level,omitempty"` // light / medium / dark / etc
RoastDate string `json:"roast_date,omitempty"` // ISO yyyy-mm-dd
Notes string `json:"notes,omitempty"`
CreatedAtUnix float64 `json:"created_at_unix"`
Archived bool `json:"archived,omitempty"`
// Active marks the "bag currently in use". At most one bean row
// has Active=true at a time; the shots store auto-tags new shots
// with this bean id so users don't have to pick one per shot.
Active bool `json:"active,omitempty"`
// DefaultGrindSize is a free-form grinder label (e.g. "2.8", "12 clicks")
// used as the starting point for new shots pulled with this bag.
// Empty string = no default. The user can override per shot.
DefaultGrindSize string `json:"default_grind_size,omitempty"`
// DefaultGrindRPM is the variable-speed grinder RPM default. Nil
// means "no default / not applicable to this grinder".
DefaultGrindRPM *float64 `json:"default_grind_rpm,omitempty"`
}
Bean is the full record as stored in SQLite.
type Input ¶
type Input struct {
Name string `json:"name"`
Roaster string `json:"roaster"`
Origin string `json:"origin"`
Process string `json:"process"`
RoastLevel string `json:"roast_level"`
RoastDate string `json:"roast_date"`
Notes string `json:"notes"`
Archived *bool `json:"archived,omitempty"`
DefaultGrindSize string `json:"default_grind_size"`
DefaultGrindRPM *float64 `json:"default_grind_rpm"`
}
Input is the writable slice of a Bean (fields the user controls).
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store wraps the shared SQLite handle.
func New ¶
New wires the beans table against an already-open *sql.DB (shared with shots etc.). Idempotent: safe to call on every boot.
func (*Store) ActiveDefaults ¶
ActiveDefaults returns the currently-active bean's id and its default grind settings, so the shots store can seed new shots with both in a single query. Any value may be empty/nil: "" id means no active bag, empty grind means the user hasn't configured a default grind, and a nil rpm means no default RPM. A missing row is not an error.
func (*Store) ActiveID ¶
ActiveID returns the id of the currently-active bean, or "" if none. Never returns an error in the happy path — a missing row is not a failure, the caller just skips auto-tagging. A SQL error (e.g. the db is closed) is still propagated.