Track food eaten by weight in grams
Logging a meal now opens the dialog (like weigh-ins) with an optional Amount (g) field; existing meals can get an amount via the edit dialog, where clearing the field drops it. The overview's Meals tile shows the day's total grams, and the weekly card gains a Food (grams) chart with a self-scaling axis that stays hidden until any meal has an amount. Events carry a new grams field (REAL column, auto-migrated); addEvent's growing optional parameters are folded into an options object.
This commit is contained in:
+17
-6
@@ -30,6 +30,7 @@ type Event struct {
|
||||
Note string `json:"note"`
|
||||
PhotoID string `json:"photoId,omitempty"`
|
||||
Weight float64 `json:"weight,omitempty"` // kilograms, for "weight" events
|
||||
Grams float64 `json:"grams,omitempty"` // food eaten, for "eat" events
|
||||
ExerciseID string `json:"exerciseId,omitempty"` // for "training" events
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
Deleted bool `json:"deleted,omitempty"`
|
||||
@@ -127,12 +128,12 @@ func (s *Store) sync(userID string, client []Event) ([]Event, error) {
|
||||
// clobber another's row even if a client forges a colliding event ID —
|
||||
// the row stays put and, because reads are scoped, stays invisible to them.
|
||||
stmt, err := tx.Prepare(`
|
||||
INSERT INTO events (id, type, at, note, photo_id, weight, exercise_id, updated, deleted, user_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO events (id, type, at, note, photo_id, weight, grams, exercise_id, updated, deleted, user_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
type = excluded.type, at = excluded.at, note = excluded.note,
|
||||
photo_id = excluded.photo_id, weight = excluded.weight,
|
||||
exercise_id = excluded.exercise_id,
|
||||
grams = excluded.grams, exercise_id = excluded.exercise_id,
|
||||
updated = excluded.updated, deleted = excluded.deleted
|
||||
WHERE excluded.updated > events.updated
|
||||
AND events.user_id = excluded.user_id`)
|
||||
@@ -146,7 +147,7 @@ func (s *Store) sync(userID string, client []Event) ([]Event, error) {
|
||||
continue
|
||||
}
|
||||
if _, err := stmt.Exec(
|
||||
ce.ID, ce.Type, ce.At, ce.Note, ce.PhotoID, ce.Weight, ce.ExerciseID, ce.UpdatedAt, ce.Deleted, userID,
|
||||
ce.ID, ce.Type, ce.At, ce.Note, ce.PhotoID, ce.Weight, ce.Grams, ce.ExerciseID, ce.UpdatedAt, ce.Deleted, userID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -160,7 +161,7 @@ func (s *Store) sync(userID string, client []Event) ([]Event, error) {
|
||||
// all returns one user's events, tombstones included.
|
||||
func (s *Store) all(userID string) ([]Event, error) {
|
||||
rows, err := s.db.Query(
|
||||
`SELECT id, type, at, note, photo_id, weight, exercise_id, updated, deleted
|
||||
`SELECT id, type, at, note, photo_id, weight, grams, exercise_id, updated, deleted
|
||||
FROM events WHERE user_id = ?`, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -170,7 +171,7 @@ func (s *Store) all(userID string) ([]Event, error) {
|
||||
for rows.Next() {
|
||||
var e Event
|
||||
if err := rows.Scan(
|
||||
&e.ID, &e.Type, &e.At, &e.Note, &e.PhotoID, &e.Weight, &e.ExerciseID, &e.UpdatedAt, &e.Deleted,
|
||||
&e.ID, &e.Type, &e.At, &e.Note, &e.PhotoID, &e.Weight, &e.Grams, &e.ExerciseID, &e.UpdatedAt, &e.Deleted,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -277,6 +278,7 @@ func openDB(path string) (*sql.DB, error) {
|
||||
note TEXT NOT NULL DEFAULT '',
|
||||
photo_id TEXT NOT NULL DEFAULT '',
|
||||
weight REAL NOT NULL DEFAULT 0,
|
||||
grams REAL NOT NULL DEFAULT 0,
|
||||
exercise_id TEXT NOT NULL DEFAULT '',
|
||||
updated INTEGER NOT NULL DEFAULT 0,
|
||||
deleted INTEGER NOT NULL DEFAULT 0,
|
||||
@@ -348,6 +350,15 @@ func migrateSchema(db *sql.DB) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
hasGrams, err := columnExists(db, "events", "grams")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !hasGrams {
|
||||
if _, err := db.Exec(`ALTER TABLE events ADD COLUMN grams REAL NOT NULL DEFAULT 0`); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
oldConfig, err := columnExists(db, "config", "id")
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user