From a6332c353552bc3ebe378d65322507a5fed3b124 Mon Sep 17 00:00:00 2001 From: Tucker Evans Date: Tue, 12 Nov 2019 10:53:41 -0500 Subject: Add update functionality to API --- backend/main.go | 71 ++++++++++++++++++++++++++++++++++- backend/recipe.go | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- backend/todo.txt | 1 - 3 files changed, 174 insertions(+), 6 deletions(-) diff --git a/backend/main.go b/backend/main.go index 856cd80..afe1102 100644 --- a/backend/main.go +++ b/backend/main.go @@ -40,6 +40,7 @@ func RecipeList(w http.ResponseWriter, r *http.Request) { rows, err := db.Query("SELECT id FROM recipes") if err != nil { + fmt.Println(err) } else { for rows.Next() { rows.Scan(&id) @@ -73,6 +74,7 @@ func RecipeList(w http.ResponseWriter, r *http.Request) { err = json.Unmarshal(body, &recipe) if err != nil { + fmt.Println(err) w.WriteHeader(http.StatusUnprocessableEntity) w.Header().Set("Content-Type", "application/json; charset=UTF-8") resp := APIResponseItem{ @@ -89,6 +91,7 @@ func RecipeList(w http.ResponseWriter, r *http.Request) { err = AddRecipeDB(recipe, db) if err != nil { + fmt.Println(err) resp := APIResponseItem{ Status: APIError{Code: http.StatusBadRequest, Msg: "Recipe could not be added"}, @@ -162,9 +165,73 @@ func SingleRecipe(w http.ResponseWriter, r *http.Request) { fmt.Printf("Create recipe \"%d\"...\n", recipe_id) //TODO add error msg response } else if r.Method == "PUT" { - //TODO add Update Recipe - fmt.Printf("Update recipe \"%d\"...\n", recipe_id) + var recipe *Recipe + + body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576)) + if err != nil { + panic(err) + } + + err = r.Body.Close() + if err != nil { + panic(err) + } + + err = json.Unmarshal(body, &recipe) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusUnprocessableEntity) + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + resp := APIResponseItem{ + Status: APIError{ + Code: http.StatusUnprocessableEntity, + Msg: "Invalid Recipe"}, + Data: make([]APIDataRecipe, 0), + } + if err := json.NewEncoder(w).Encode(resp); err != nil { + panic(err) + } + return + } + + recipe.Id = recipe_id + + err = UpdateRecipeDB(recipe, db) + if err != nil { + fmt.Println(err) + resp := APIResponseItem{ + Status: APIError{Code: http.StatusBadRequest, + Msg: "Recipe could not be updated"}, + Data: make([]APIDataRecipe, 0), + } + + resp.Data = append(resp.Data, APIDataRecipe{recipe}) + + w.Header().Set("Content-Type", + "application/json; charset=UTF-8") + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(resp); err != nil { + panic(err) + } + return + } + + resp := APIResponseItem{ + Status: APIError{Code: http.StatusCreated, + Msg: "Recipe added successfully"}, + Data: make([]APIDataRecipe, 0), + } + + resp.Data = append(resp.Data, APIDataRecipe{recipe}) + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusCreated) + if err := json.NewEncoder(w).Encode(resp); err != nil { + panic(err) + } + } else if r.Method == "DELETE" { + res, err := db.Exec(`DELETE FROM recipes where id = $1`, recipe_id) if err != nil { diff --git a/backend/recipe.go b/backend/recipe.go index 89a01df..fed83ca 100644 --- a/backend/recipe.go +++ b/backend/recipe.go @@ -1,6 +1,7 @@ package main import "database/sql" +import "errors" import "strings" type Ingredient struct { @@ -100,7 +101,6 @@ func RecipeFromId(id int, db *sql.DB) *Recipe { id) defer rows_ingr.Close() if err == nil { - var i int for rows_ingr.Next() { rows_ingr.Scan(&name, &amount, &unit) ingr = Ingredient{ @@ -145,8 +145,11 @@ func AddRecipeDB(r *Recipe, db *sql.DB) error { keywords.WriteRune('|') } - tx := db.Begin() - err := tx.QueryRow(`INSERT INTO recipes (title, photo_urls, + tx, err := db.Begin() + if err != nil { + return err + } + err = tx.QueryRow(`INSERT INTO recipes (title, photo_urls, keywords, description, serving_size, cook_time, rating, num_cooked) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) @@ -202,3 +205,102 @@ func AddRecipeDB(r *Recipe, db *sql.DB) error { tx.Commit() return nil } + +func UpdateRecipeDB(r *Recipe, db *sql.DB) error { + var photo_urls, keywords strings.Builder + + for _, u := range r.Photos { + photo_urls.WriteString(u) + photo_urls.WriteRune('|') + } + + for _, k := range r.Keywords { + keywords.WriteString(k) + keywords.WriteRune('|') + } + + tx, err := db.Begin() + if err != nil { + return err + } + _, err = tx.Exec(`UPDATE recipes SET (title, photo_urls, + keywords, description, serving_size, cook_time, + rating, num_cooked) + = ($1, $2, $3, $4, $5, $6, $7, $8) + WHERE id = $9`, + r.Title, //1 + photo_urls.String(), //2 + keywords.String(), //3 + r.Desc, //4 + r.Serving_size, //5 + r.Cook_time, //6 + r.Rating, //7 + r.Num_cooked, //8 + r.Id, //9 + ) + if err != nil { + tx.Rollback() + return err + } + + _, err = tx.Exec("DELETE FROM ingredients WHERE id > $1", + len(r.Ingredients)-1) + if err != nil { + tx.Rollback() + return err + } + + for i, ingr := range r.Ingredients { + _, err := tx.Exec(`INSERT INTO ingredients + (id, name, amount, unit, recipe_id) + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (id, recipe_id) + DO UPDATE SET + (name, amount, unit) + = ($2, $3, $4)`, + + i, + ingr.Name, + ingr.Amount, + ingr.Unit, + r.Id, + ) + if err != nil { + tx.Rollback() + return err + } + } + + _, err = tx.Exec("DELETE FROM steps WHERE step > $1", + len(r.Steps)-1) + if err != nil { + tx.Rollback() + return err + } + + for i, step := range r.Steps { + if step.Num != 0 { + tx.Rollback() + return errors.New("invalid json Recipe") + } + _, err := tx.Exec(`INSERT INTO steps + (step, description, timer, recipe_id) + VALUES ($1, $2, $3, $4) + ON CONFLICT (step,recipe_id) + DO UPDATE SET + (description, timer) + = ($2, $3)`, + i, + step.Desc, + step.Time, + r.Id, + ) + if err != nil { + tx.Rollback() + return err + } + } + + tx.Commit() + return nil +} diff --git a/backend/todo.txt b/backend/todo.txt index 3c911c4..cb074a4 100644 --- a/backend/todo.txt +++ b/backend/todo.txt @@ -1,2 +1 @@ -Add Update method for recipes Add Error responses for incorrect methods -- cgit v1.1