From 7e03e15b3b6b2376c1b96b0bb2abf8706c923408 Mon Sep 17 00:00:00 2001 From: Alessio Date: Sat, 9 Nov 2024 23:02:18 -0800 Subject: [PATCH] Add ingredient methods --- doc/TODO.txt | 2 + pkg/db/ingredient.go | 69 +++++++++++++++++++++++++++++++++-- pkg/db/ingredient_test.go | 77 +++++++++++++++++++++++++++++++++++++++ pkg/db/recipe.go | 11 ++---- pkg/db/schema.sql | 22 +++++------ 5 files changed, 158 insertions(+), 23 deletions(-) create mode 100644 doc/TODO.txt create mode 100644 pkg/db/ingredient_test.go diff --git a/doc/TODO.txt b/doc/TODO.txt new file mode 100644 index 0000000..cc9113f --- /dev/null +++ b/doc/TODO.txt @@ -0,0 +1,2 @@ +TODO: figure-out-is-hidden +- what is it? Check in the existing foods database for items that are hidden i guess diff --git a/pkg/db/ingredient.go b/pkg/db/ingredient.go index febfcb0..769c276 100644 --- a/pkg/db/ingredient.go +++ b/pkg/db/ingredient.go @@ -1,7 +1,7 @@ package db import ( -// "fmt" + "fmt" ) type IngredientID uint64 @@ -11,9 +11,9 @@ type Ingredient struct { FoodID FoodID `db:"food_id"` RecipeID RecipeID `db:"recipe_id"` - QuantityNumerator int64 `db:"quantity_numerator"` - QuantityDenominator int64 `db:"quantity_denominator"` - Units Units `db:"units"` + QuantityNumerator int64 `db:"quantity_numerator"` + QuantityDenominator int64 `db:"quantity_denominator"` + Units UnitsID `db:"units"` InRecipeID RecipeID `db:"in_recipe_id"` ListOrder int64 `db:"list_order"` @@ -24,3 +24,64 @@ type Ingredient struct { // func (i Ingredient) String() string { // return fmt.Sprintf("%s(%d)", f.Name, f.ID) // } + +func (db *DB) SaveIngredient(i *Ingredient) { + if i.ID == IngredientID(0) { + println("creating---------") + // Do create + result, err := db.DB.NamedExec(` + insert into ingredients + (food_id, recipe_id, quantity_numerator, quantity_denominator, units, in_recipe_id, list_order, is_hidden) + values (nullif(:food_id, 0), nullif(:recipe_id, 0), :quantity_numerator, :quantity_denominator, :units, :in_recipe_id, + :list_order, :is_hidden) + `, i) + if err != nil { + panic(err) + } + + // Update the ID + id, err := result.LastInsertId() + if err != nil { + panic(err) + } + i.ID = IngredientID(id) + } else { + println("updating---------") + // Do update + result, err := db.DB.NamedExec(` + update ingredients + set food_id=nullif(:food_id, 0), + recipe_id=nullif(:recipe_id, 0), + quantity_numerator=:quantity_numerator, + quantity_denominator=:quantity_denominator, + units=:units, + list_order=:list_order, + is_hidden=:is_hidden + where rowid = :rowid + `, i) + if err != nil { + panic(err) + } + count, err := result.RowsAffected() + if err != nil { + panic(err) + } + if count != 1 { + panic(fmt.Errorf("Got ingredient with ID (%d), so attempted update, but it doesn't exist", i.ID)) + } + } +} + +func (db *DB) DeleteIngredient(i Ingredient) { + result, err := db.DB.Exec(`delete from ingredients where rowid = ?`, i.ID) + if err != nil { + panic(err) + } + count, err := result.RowsAffected() + if err != nil { + panic(err) + } + if count != 1 { + panic(fmt.Errorf("tried to delete ingredient with ID (%d) but it doesn't exist", i.ID)) + } +} diff --git a/pkg/db/ingredient_test.go b/pkg/db/ingredient_test.go new file mode 100644 index 0000000..a14edbb --- /dev/null +++ b/pkg/db/ingredient_test.go @@ -0,0 +1,77 @@ +package db_test + +import ( + "testing" + + "github.com/go-test/deep" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + . "recipe_book/pkg/db" +) + +func TestSaveAndLoadIngredient(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + db := get_test_db() + + // Setup + recipe := Recipe{ + Name: "some Recipe", + Blurb: "Lorem Ispum dolor sit amet consquiter id blah blabh albha blahbla blahblahblh", + Instructions: RecipeInstructions{ + "instr 1", "isntr 2", "instr3", "ins32gjkifw", + }, + } + db.SaveRecipe(&recipe) + food := Food{ + Name: "a food", + Cals: 10, + Carbs: 1, + Protein: 2, + } + db.SaveFood(&food) + + // Create an ingredient on the recipe + ingr := Ingredient{ + FoodID: food.ID, + QuantityNumerator: 3, + QuantityDenominator: 2, + Units: 1, // count + InRecipeID: recipe.ID, + ListOrder: 0, + } + assert.Equal(ingr.ID, IngredientID(0)) + db.SaveIngredient(&ingr) + assert.NotEqual(ingr.ID, IngredientID(0)) + + // It should be added to the recipe at position 0 + new_recipe, err := db.GetRecipeByID(recipe.ID) + assert.NoError(err) + require.Len(new_recipe.Ingredients, 1) + new_ingr := new_recipe.Ingredients[0] + if diff := deep.Equal(ingr, new_ingr); diff != nil { + t.Error(diff) + } + + // Modify the ingredient + ingr.QuantityNumerator = 5 + ingr.QuantityDenominator = 4 + ingr.Units = 2 + + // Save it and reload the recipe + db.SaveIngredient(&ingr) + new_recipe, err = db.GetRecipeByID(recipe.ID) + assert.NoError(err) + require.Len(new_recipe.Ingredients, 1) + new_ingr = new_recipe.Ingredients[0] + if diff := deep.Equal(ingr, new_ingr); diff != nil { + t.Error(diff) + } + + // Delete and reload-- should be gone + db.DeleteIngredient(ingr) + new_recipe, err = db.GetRecipeByID(recipe.ID) + assert.NoError(err) + require.Len(new_recipe.Ingredients, 0) +} diff --git a/pkg/db/recipe.go b/pkg/db/recipe.go index 31f2af9..ebea6cb 100644 --- a/pkg/db/recipe.go +++ b/pkg/db/recipe.go @@ -76,12 +76,6 @@ func (db *DB) SaveRecipe(r *Recipe) { // TODO: recompute the computed_food } -// func (db *DB) AddIngredientToRecipe(r Recipe, i *Ingredient) { -// result, err := db.DB.NamedExec(` -// insert into ingredients -// `, ingr) -// } - func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) { err = db.DB.Get(&ret, ` select rowid, name, blurb, instructions @@ -89,12 +83,13 @@ func (db *DB) GetRecipeByID(id RecipeID) (ret Recipe, err error) { where rowid = ? `, id) if err != nil { - return Recipe{}, err + return Recipe{}, fmt.Errorf("fetching recipe with ID %d: %w", id, err) } // Load the ingredients err = db.DB.Select(&ret.Ingredients, ` - select food_id, recipe_id, quantity_numerator, quantity_denominator, units, list_order, is_hidden + select rowid, ifnull(food_id, 0) food_id, ifnull(recipe_id, 0) recipe_id, quantity_numerator, quantity_denominator, units, + in_recipe_id, list_order, is_hidden from ingredients where in_recipe_id = ? order by list_order asc diff --git a/pkg/db/schema.sql b/pkg/db/schema.sql index 341ce12..c0942c3 100644 --- a/pkg/db/schema.sql +++ b/pkg/db/schema.sql @@ -52,19 +52,19 @@ create table units (rowid integer primary key, abbreviation text not null unique check(length(abbreviation) != 0) -- is_metric integer not null check(is_metric in (0, 1)) ); -insert into units(name, abbreviation) values +insert into units(rowid, name, abbreviation) values -- Count - ('count', 'ct'), + (1, 'count', 'ct'), -- Mass - ('grams', 'g'), - ('pounds', 'lbs'), - ('ounces', 'oz'), + (2, 'grams', 'g'), + (3, 'pounds', 'lbs'), + (4, 'ounces', 'oz'), -- Volume - ('milliliters', 'mL'), - ('cups', 'cups'), - ('teaspoons', 'tsp'), - ('tablespoons', 'tbsp'), - ('fluid ounces', 'fl-oz'); + (5, 'milliliters', 'mL'), + (6, 'cups', 'cups'), + (7, 'teaspoons', 'tsp'), + (8, 'tablespoons', 'tbsp'), + (9, 'fluid ounces', 'fl-oz'); create table ingredients (rowid integer primary key, @@ -82,7 +82,7 @@ create table ingredients (rowid integer primary key, in_recipe_id integer references recipes(rowid) on delete cascade not null, list_order integer not null, is_hidden integer not null default false, - unique (recipe_id, list_order) + unique (in_recipe_id, list_order) check((food_id is null) + (recipe_id is null) = 1) -- Exactly one should be active ) strict;