beans

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 22, 2026 License: MIT Imports: 8 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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

func New(ctx context.Context, db *sql.DB) (*Store, error)

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

func (s *Store) ActiveDefaults(ctx context.Context) (id, grind string, rpm *float64, err error)

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

func (s *Store) ActiveID(ctx context.Context) (string, error)

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.

func (*Store) Create

func (s *Store) Create(ctx context.Context, in Input) (*Bean, error)

Create inserts a new bean with a generated id and returns the full record.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, id string) error

Delete removes a bean by id.

func (*Store) Get

func (s *Store) Get(ctx context.Context, id string) (*Bean, error)

Get fetches a single bean by id.

func (*Store) List

func (s *Store) List(ctx context.Context) ([]Bean, error)

List returns all beans, active first, then archived.

func (*Store) SetActive

func (s *Store) SetActive(ctx context.Context, id string) error

SetActive marks one bean as the "bag currently in use", clearing the flag on every other row. Pass an empty id to just clear any active marker (no bag currently in use). Runs in a single transaction so readers never observe two active rows.

func (*Store) Update

func (s *Store) Update(ctx context.Context, id string, in Input) (*Bean, error)

Update rewrites the mutable fields of an existing bean.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL