Recipes should now compute their equivalent food on save

This commit is contained in:
Alessio 2024-11-10 19:37:03 -08:00
parent 9023f13b19
commit 7d2f47b1a2
6 changed files with 63 additions and 38 deletions

View File

@ -1,2 +1,4 @@
TODO: figure-out-is-hidden TODO: figure-out-is-hidden
- what is it? Check in the existing foods database for items that are hidden i guess - what is it? Check in the existing foods database for items that are hidden i guess
TODO: add-created-at-modified-at-timestamps

View File

@ -18,7 +18,7 @@ type Ingredient struct {
ListOrder int64 `db:"list_order"` ListOrder int64 `db:"list_order"`
IsHidden bool `db:"is_hidden"` IsHidden bool `db:"is_hidden"`
Food *Food Food Food
} }
// Format as string // Format as string
@ -83,6 +83,7 @@ func (db *DB) DeleteIngredient(i Ingredient) {
panic(fmt.Errorf("tried to delete ingredient with ID (%d) but it doesn't exist", i.ID)) panic(fmt.Errorf("tried to delete ingredient with ID (%d) but it doesn't exist", i.ID))
} }
} }
// func (i Ingredient) AddTo(r *Recipe) { // func (i Ingredient) AddTo(r *Recipe) {
// } // }

View File

@ -29,7 +29,7 @@ func TestSaveAndLoadIngredient(t *testing.T) {
// Create an ingredient on the recipe // Create an ingredient on the recipe
ingr := Ingredient{ ingr := Ingredient{
FoodID: food.ID, FoodID: food.ID,
Food: &food, Food: food,
Quantity: 1.5, Quantity: 1.5,
Units: 1, // count Units: 1, // count
InRecipeID: recipe.ID, InRecipeID: recipe.ID,

View File

@ -36,16 +36,23 @@ type Recipe struct {
ComputedFoodID FoodID `db:"computed_food_id"` ComputedFoodID FoodID `db:"computed_food_id"`
} }
// Save the recipe. New recipes will have their ID back-filled from the DB.
//
// Automatically updates the computed food, creating one if it's a new recipe and back-filling the
// `computed_food_id` foreign key to it.
func (db *DB) SaveRecipe(r *Recipe) { func (db *DB) SaveRecipe(r *Recipe) {
if r.ID == RecipeID(0) { if r.ID == RecipeID(0) {
// Do create // Do create
// Create the computed food
computed_food := Food{Name: r.Name}
db.SaveFood(&computed_food)
r.ComputedFoodID = computed_food.ID
// Create the recipe
result, err := db.DB.NamedExec(` result, err := db.DB.NamedExec(`
insert into recipes (name, blurb, instructions) insert into recipes (name, blurb, instructions, computed_food_id)
values (:name, :blurb, :instructions) values (:name, :blurb, :instructions, :computed_food_id)
on conflict do update
set name=:name,
blurb=:blurb,
instructions=:instructions
`, r) `, r)
if err != nil { if err != nil {
panic(err) panic(err)
@ -73,12 +80,18 @@ func (db *DB) SaveRecipe(r *Recipe) {
panic(fmt.Errorf("Got recipe with ID (%d), so attempted update, but it doesn't exist", r.ID)) panic(fmt.Errorf("Got recipe with ID (%d), so attempted update, but it doesn't exist", r.ID))
} }
} }
// TODO: recompute the computed_food for i := range r.Ingredients {
r.Ingredients[i].InRecipeID = r.ID
db.SaveIngredient(&r.Ingredients[i])
}
// Update the computed food
computed_food := r.ComputeFood()
db.SaveFood(&computed_food)
} }
func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) { func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) {
err = db.DB.Get(&ret, ` err = db.DB.Get(&ret, `
select rowid, name, blurb, instructions select rowid, name, blurb, instructions, computed_food_id
from recipes from recipes
where rowid = ? where rowid = ?
`, id) `, id)
@ -98,11 +111,9 @@ func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) {
panic(err) panic(err)
} }
for i := range ret.Ingredients { for i := range ret.Ingredients {
var food Food
if ret.Ingredients[i].FoodID != FoodID(0) { if ret.Ingredients[i].FoodID != FoodID(0) {
// ingredient is a food // ingredient is a food
food, err = db.GetFoodByID(ret.Ingredients[i].FoodID) ret.Ingredients[i].Food, err = db.GetFoodByID(ret.Ingredients[i].FoodID)
ret.Ingredients[i].Food = &food
} else { } else {
// ingredient is a food; i.Food is the ComputedFood of the Recipe // ingredient is a food; i.Food is the ComputedFood of the Recipe
var computed_food_id FoodID var computed_food_id FoodID
@ -110,8 +121,7 @@ func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
food, err = db.GetFoodByID(computed_food_id) ret.Ingredients[i].Food, err = db.GetFoodByID(computed_food_id)
ret.Ingredients[i].Food = &food
} }
if err != nil { if err != nil {
panic(err) panic(err)
@ -121,7 +131,8 @@ func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) {
} }
func (r Recipe) ComputeFood() Food { func (r Recipe) ComputeFood() Food {
ret := Food{} // If r.ComputedFoodID is 0, so should be the ID of returned Food
ret := Food{ID: r.ComputedFoodID, Name: r.Name}
for _, ingr := range r.Ingredients { for _, ingr := range r.Ingredients {
ret.Cals += ingr.Quantity * ingr.Food.Cals ret.Cals += ingr.Quantity * ingr.Food.Cals
ret.Carbs += ingr.Quantity * ingr.Food.Carbs ret.Carbs += ingr.Quantity * ingr.Food.Carbs

View File

@ -5,6 +5,7 @@ import (
"github.com/go-test/deep" "github.com/go-test/deep"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
. "recipe_book/pkg/db" . "recipe_book/pkg/db"
) )
@ -21,8 +22,10 @@ func TestRecipeSaveAndLoad(t *testing.T) {
}, },
} }
assert.Equal(recipe.ID, RecipeID(0)) assert.Equal(recipe.ID, RecipeID(0))
assert.Equal(recipe.ComputedFoodID, FoodID(0))
db.SaveRecipe(&recipe) db.SaveRecipe(&recipe)
assert.NotEqual(recipe.ID, RecipeID(0)) assert.NotEqual(recipe.ID, RecipeID(0))
assert.NotEqual(recipe.ComputedFoodID, FoodID(0))
new_recipe, err := db.GetRecipeByID(recipe.ID) new_recipe, err := db.GetRecipeByID(recipe.ID)
assert.NoError(err) assert.NoError(err)
if diff := deep.Equal(recipe, new_recipe); diff != nil { if diff := deep.Equal(recipe, new_recipe); diff != nil {
@ -49,8 +52,8 @@ func TestRecipeComputeFood(t *testing.T) {
f2 := Food{0, "", 16.5, 15.5, 14.5, 13.5, 12.5, 11.5, 10.5, 9.5, 8.5, 7.5, 6.5, 5.5, 4.5, 3.5, 2.5, 1.5, 0, 0} f2 := Food{0, "", 16.5, 15.5, 14.5, 13.5, 12.5, 11.5, 10.5, 9.5, 8.5, 7.5, 6.5, 5.5, 4.5, 3.5, 2.5, 1.5, 0, 0}
recipe := Recipe{Ingredients: []Ingredient{ recipe := Recipe{Ingredients: []Ingredient{
{Quantity: 1, Food: &f1}, {Quantity: 1, Food: f1},
{Quantity: 1, Food: &f2}, {Quantity: 1, Food: f2},
}} }}
computed_food := recipe.ComputeFood() computed_food := recipe.ComputeFood()
assert.Equal(computed_food.Cals, float32(17.5)) assert.Equal(computed_food.Cals, float32(17.5))
@ -71,8 +74,8 @@ func TestRecipeComputeFood(t *testing.T) {
assert.Equal(computed_food.Price, float32(17.5)) assert.Equal(computed_food.Price, float32(17.5))
recipe2 := Recipe{Ingredients: []Ingredient{ recipe2 := Recipe{Ingredients: []Ingredient{
{Quantity: 1.5, Food: &f1}, {Quantity: 1.5, Food: f1},
{Quantity: 0.5, Food: &f2}, {Quantity: 0.5, Food: f2},
}} }}
computed_food2 := recipe2.ComputeFood() computed_food2 := recipe2.ComputeFood()
assert.Equal(computed_food2.Cals, float32(9.75)) assert.Equal(computed_food2.Cals, float32(9.75))
@ -92,3 +95,27 @@ func TestRecipeComputeFood(t *testing.T) {
assert.Equal(computed_food2.Mass, float32(23.75)) assert.Equal(computed_food2.Mass, float32(23.75))
assert.Equal(computed_food2.Price, float32(24.75)) assert.Equal(computed_food2.Price, float32(24.75))
} }
func TestRecipeSaveComputedFood(t *testing.T) {
// assert := assert.New(t)
require := require.New(t)
db := get_test_db()
pasta := get_food(db, 3)
require.Equal(pasta.Name, "pasta")
tomatoes := get_food(db, 105)
require.Equal(tomatoes.Name, "canned tomatoes")
parm := get_food(db, 86)
require.Equal(parm.Name, "parmigiano")
recipe := Recipe{Name: "pasta w/ sauce", Ingredients: []Ingredient{
{Quantity: 2, FoodID: pasta.ID, Food: pasta, ListOrder: 0},
{Quantity: 2.5, FoodID: tomatoes.ID, Food: tomatoes, ListOrder: 1},
{Quantity: 0.5, FoodID: parm.ID, Food: parm, ListOrder: 2},
}}
db.SaveRecipe(&recipe)
computed_food := get_food(db, recipe.ComputedFoodID)
if diff := deep.Equal(recipe.ComputeFood(), computed_food); diff != nil {
t.Error(diff)
}
}

View File

@ -20,9 +20,6 @@ insert into food_types (name) values
create table foods (rowid integer primary key, create table foods (rowid integer primary key,
name text not null check(length(name) != 0), name text not null check(length(name) != 0),
-- created_at integer not null,
-- updated_at integer,
cals real not null, cals real not null,
carbs real not null, carbs real not null,
protein real not null, protein real not null,
@ -68,13 +65,9 @@ insert into units(rowid, name, abbreviation) values
create table ingredients (rowid integer primary key, create table ingredients (rowid integer primary key,
-- created_at integer not null,
-- updated_at integer,
food_id integer references foods(rowid), food_id integer references foods(rowid),
recipe_id integer references recipes(rowid), recipe_id integer references recipes(rowid),
-- Portion size (rational numbers)
quantity real not null default 1, quantity real not null default 1,
units integer not null default 0, -- Display purposes only units integer not null default 0, -- Display purposes only
@ -86,20 +79,14 @@ create table ingredients (rowid integer primary key,
) strict; ) strict;
create table recipes (rowid integer primary key, create table recipes (rowid integer primary key,
-- created_at integer not null,
-- updated_at integer,
name text not null check(length(name) != 0), name text not null check(length(name) != 0),
blurb text not null, blurb text not null,
instructions text not null instructions text not null,
-- computed_food_id integer references foods(rowid) not null computed_food_id integer references foods(rowid) not null
) strict; ) strict;
create table iterations (rowid integer primary key, create table iterations (rowid integer primary key,
-- created_at integer not null,
-- updated_at integer,
original_recipe_id integer references recipes(rowid), original_recipe_id integer references recipes(rowid),
-- original_author integer not null, -- For azimuth integration -- original_author integer not null, -- For azimuth integration
derived_recipe_id integer references recipes(rowid), derived_recipe_id integer references recipes(rowid),
@ -107,9 +94,6 @@ create table iterations (rowid integer primary key,
) strict; ) strict;
create table daily_logs (rowid integer primary key, create table daily_logs (rowid integer primary key,
-- created_at integer not null,
-- updated_at integer,
date integer not null unique, date integer not null unique,
computed_food_id integer references foods(rowid) not null computed_food_id integer references foods(rowid) not null