From 7d2f47b1a2fc3146f9acda224b4fa0ba10354114 Mon Sep 17 00:00:00 2001 From: Alessio Date: Sun, 10 Nov 2024 19:37:03 -0800 Subject: [PATCH] Recipes should now compute their equivalent food on save --- doc/TODO.txt | 2 ++ pkg/db/ingredient.go | 3 ++- pkg/db/ingredient_test.go | 2 +- pkg/db/recipe.go | 39 +++++++++++++++++++++++++-------------- pkg/db/recipe_test.go | 35 +++++++++++++++++++++++++++++++---- pkg/db/schema.sql | 20 ++------------------ 6 files changed, 63 insertions(+), 38 deletions(-) diff --git a/doc/TODO.txt b/doc/TODO.txt index cc9113f..270a724 100644 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -1,2 +1,4 @@ TODO: figure-out-is-hidden - what is it? Check in the existing foods database for items that are hidden i guess + +TODO: add-created-at-modified-at-timestamps diff --git a/pkg/db/ingredient.go b/pkg/db/ingredient.go index 0975446..49ce1fd 100644 --- a/pkg/db/ingredient.go +++ b/pkg/db/ingredient.go @@ -18,7 +18,7 @@ type Ingredient struct { ListOrder int64 `db:"list_order"` IsHidden bool `db:"is_hidden"` - Food *Food + Food Food } // 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)) } } + // func (i Ingredient) AddTo(r *Recipe) { // } diff --git a/pkg/db/ingredient_test.go b/pkg/db/ingredient_test.go index b0e6be5..9e67b1a 100644 --- a/pkg/db/ingredient_test.go +++ b/pkg/db/ingredient_test.go @@ -29,7 +29,7 @@ func TestSaveAndLoadIngredient(t *testing.T) { // Create an ingredient on the recipe ingr := Ingredient{ FoodID: food.ID, - Food: &food, + Food: food, Quantity: 1.5, Units: 1, // count InRecipeID: recipe.ID, diff --git a/pkg/db/recipe.go b/pkg/db/recipe.go index 9b6d5a7..0dce97c 100644 --- a/pkg/db/recipe.go +++ b/pkg/db/recipe.go @@ -36,16 +36,23 @@ type Recipe struct { 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) { if r.ID == RecipeID(0) { // 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(` - insert into recipes (name, blurb, instructions) - values (:name, :blurb, :instructions) - on conflict do update - set name=:name, - blurb=:blurb, - instructions=:instructions + insert into recipes (name, blurb, instructions, computed_food_id) + values (:name, :blurb, :instructions, :computed_food_id) `, r) if err != nil { 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)) } } - // 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) { err = db.DB.Get(&ret, ` - select rowid, name, blurb, instructions + select rowid, name, blurb, instructions, computed_food_id from recipes where rowid = ? `, id) @@ -98,11 +111,9 @@ func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) { panic(err) } for i := range ret.Ingredients { - var food Food if ret.Ingredients[i].FoodID != FoodID(0) { // ingredient is a food - food, err = db.GetFoodByID(ret.Ingredients[i].FoodID) - ret.Ingredients[i].Food = &food + ret.Ingredients[i].Food, err = db.GetFoodByID(ret.Ingredients[i].FoodID) } else { // ingredient is a food; i.Food is the ComputedFood of the Recipe var computed_food_id FoodID @@ -110,8 +121,7 @@ func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) { if err != nil { panic(err) } - food, err = db.GetFoodByID(computed_food_id) - ret.Ingredients[i].Food = &food + ret.Ingredients[i].Food, err = db.GetFoodByID(computed_food_id) } if err != nil { panic(err) @@ -121,7 +131,8 @@ func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) { } 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 { ret.Cals += ingr.Quantity * ingr.Food.Cals ret.Carbs += ingr.Quantity * ingr.Food.Carbs diff --git a/pkg/db/recipe_test.go b/pkg/db/recipe_test.go index 177303e..7630fe9 100644 --- a/pkg/db/recipe_test.go +++ b/pkg/db/recipe_test.go @@ -5,6 +5,7 @@ import ( "github.com/go-test/deep" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" . "recipe_book/pkg/db" ) @@ -21,8 +22,10 @@ func TestRecipeSaveAndLoad(t *testing.T) { }, } assert.Equal(recipe.ID, RecipeID(0)) + assert.Equal(recipe.ComputedFoodID, FoodID(0)) db.SaveRecipe(&recipe) assert.NotEqual(recipe.ID, RecipeID(0)) + assert.NotEqual(recipe.ComputedFoodID, FoodID(0)) new_recipe, err := db.GetRecipeByID(recipe.ID) assert.NoError(err) 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} recipe := Recipe{Ingredients: []Ingredient{ - {Quantity: 1, Food: &f1}, - {Quantity: 1, Food: &f2}, + {Quantity: 1, Food: f1}, + {Quantity: 1, Food: f2}, }} computed_food := recipe.ComputeFood() 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)) recipe2 := Recipe{Ingredients: []Ingredient{ - {Quantity: 1.5, Food: &f1}, - {Quantity: 0.5, Food: &f2}, + {Quantity: 1.5, Food: f1}, + {Quantity: 0.5, Food: f2}, }} computed_food2 := recipe2.ComputeFood() 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.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) + } +} diff --git a/pkg/db/schema.sql b/pkg/db/schema.sql index 95d5294..1ea49b9 100644 --- a/pkg/db/schema.sql +++ b/pkg/db/schema.sql @@ -20,9 +20,6 @@ insert into food_types (name) values create table foods (rowid integer primary key, name text not null check(length(name) != 0), - -- created_at integer not null, - -- updated_at integer, - cals real not null, carbs 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, - -- created_at integer not null, - -- updated_at integer, - food_id integer references foods(rowid), recipe_id integer references recipes(rowid), - -- Portion size (rational numbers) quantity real not null default 1, units integer not null default 0, -- Display purposes only @@ -86,20 +79,14 @@ create table ingredients (rowid integer primary key, ) strict; create table recipes (rowid integer primary key, - -- created_at integer not null, - -- updated_at integer, - name text not null check(length(name) != 0), 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; create table iterations (rowid integer primary key, - -- created_at integer not null, - -- updated_at integer, - original_recipe_id integer references recipes(rowid), -- original_author integer not null, -- For azimuth integration derived_recipe_id integer references recipes(rowid), @@ -107,9 +94,6 @@ create table iterations (rowid integer primary key, ) strict; create table daily_logs (rowid integer primary key, - -- created_at integer not null, - -- updated_at integer, - date integer not null unique, computed_food_id integer references foods(rowid) not null