summaryrefslogtreecommitdiff
path: root/model
diff options
context:
space:
mode:
Diffstat (limited to 'model')
-rw-r--r--model/recipe.go106
-rw-r--r--model/recipe_test.go2
-rw-r--r--model/sql/migrate.sql2
-rw-r--r--model/step.go96
4 files changed, 157 insertions, 49 deletions
diff --git a/model/recipe.go b/model/recipe.go
index b1ad781..c4f0d47 100644
--- a/model/recipe.go
+++ b/model/recipe.go
@@ -24,6 +24,10 @@ func (r Recipe) String() string {
}
func (r *Recipe) Create(tx *sql.Tx) error {
+ if r.Id != "" {
+ return fmt.Errorf("Cannot create recipe if ID is given")
+ }
+
cmd := `
INSERT INTO recipes
(title, portions, url, notes, created, last_changed)
@@ -44,19 +48,60 @@ VALUES
r.Id = fmt.Sprint(id)
- err = r.CreateSteps(tx)
- if err != nil {
- return err
+ for i := range r.Steps {
+ r.Steps[i].Recipe = r.Id
+ r.Steps[i].Index = fmt.Sprint(i)
+ err = r.Steps[i].Create(tx)
+ if err != nil {
+ return err
+ }
}
return nil
}
+func (r *Recipe) getStepIds(tx *sql.Tx) ([]Step, error) {
+ retval := make([]Step, 0)
+
+ cmd := `
+SELECT
+ id
+FROM
+ steps
+WHERE
+ recipe = ?
+ORDER BY
+ 'index' ASC
+`
+
+ rows, err := tx.Query(cmd, r.Id)
+ if err != nil {
+ return retval, err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ s := Step{}
+
+ err = rows.Scan(&s.Id)
+ if err != nil {
+ return retval, err
+ }
+
+ retval = append(retval, s)
+ }
+
+ return retval, nil
+}
+
func (r *Recipe) Read(tx *sql.Tx) error {
cmd := `
-SELECT id, title, portions, url, notes, created, last_changed
-FROM recipes
-WHERE id = ?
+SELECT
+ title, portions, url, notes, created, last_changed
+FROM
+ recipes
+WHERE
+ id = ?
`
rows, err := tx.Query(cmd, r.Id)
@@ -70,7 +115,6 @@ WHERE id = ?
}
err = rows.Scan(
- &r.Id,
&r.Title,
&r.Portions,
&r.Url,
@@ -82,32 +126,57 @@ WHERE id = ?
return err
}
- err = r.ReadSteps(tx)
+ r.Steps, err = r.getStepIds(tx)
if err != nil {
return err
}
+ for i := range r.Steps {
+ err = r.Steps[i].Read(tx)
+ if err != nil {
+ return err
+ }
+ }
+
return nil
}
func (r *Recipe) Update(tx *sql.Tx) error {
- err := r.UpdateSteps(tx)
+ oldSteps, err := r.getStepIds(tx)
if err != nil {
return err
}
- query := `UPDATE
+ for i := range oldSteps {
+ err = oldSteps[i].Delete(tx)
+ if err != nil {
+ return err
+ }
+ }
+
+ for i := range r.Steps {
+ r.Steps[i].Index = fmt.Sprint(i)
+ r.Steps[i].Recipe = r.Id
+ r.Steps[i].Create(tx)
+ if err != nil {
+ return err
+ }
+ }
+
+ cmd := `
+UPDATE
recipes
SET
title = ?,
portions = ?,
url = ?,
notes = ?,
+ created = ?,
last_changed = ?
WHERE
id = ?`
- res, err := tx.Exec(query, r.Title, r.Portions, r.Url, r.Notes,
+ res, err := tx.Exec(cmd, r.Title, r.Portions, r.Url, r.Notes, r.Created,
r.LastChanged, r.Id)
if err != nil {
return err
@@ -125,19 +194,26 @@ WHERE
}
func (r *Recipe) Delete(tx *sql.Tx) error {
- err := r.DeleteSteps(tx)
+ oldSteps, err := r.getStepIds(tx)
if err != nil {
return err
}
- query := `
+ for i := range oldSteps {
+ err = oldSteps[i].Delete(tx)
+ if err != nil {
+ return err
+ }
+ }
+
+ cmd := `
DELETE FROM
recipes
WHERE
id = ?
`
- result, err := tx.Exec(query, r.Id)
+ result, err := tx.Exec(cmd, r.Id)
if err != nil {
return err
}
@@ -153,7 +229,6 @@ WHERE
func RecipeTestData() []Recipe {
return []Recipe{
{
- Id: "1",
Title: "Pancakes",
Portions: "4",
Url: "https://example.org",
@@ -167,7 +242,6 @@ func RecipeTestData() []Recipe {
},
},
{
- Id: "2",
Title: "Burger",
Portions: "2",
Url: "https://xengineering.eu/git/ceres",
diff --git a/model/recipe_test.go b/model/recipe_test.go
index b9a44e1..508cf53 100644
--- a/model/recipe_test.go
+++ b/model/recipe_test.go
@@ -31,7 +31,7 @@ func TestRecipeCrud(t *testing.T) {
readback.Id = original.Id
err = readback.Read(tx)
if err != nil {
- t.Fatalf("Failed to create test recipe in DB: %v\n", err)
+ t.Fatalf("Failed to read test recipe from DB: %v\n", err)
}
if !reflect.DeepEqual(original, readback) {
diff --git a/model/sql/migrate.sql b/model/sql/migrate.sql
index 9577dab..f931af6 100644
--- a/model/sql/migrate.sql
+++ b/model/sql/migrate.sql
@@ -12,8 +12,8 @@ CREATE TABLE recipes (
CREATE TABLE steps (
id INTEGER PRIMARY KEY,
- recipe INTEGER NOT NULL,
'index' INTEGER NOT NULL,
text TEXT NOT NULL,
+ recipe INTEGER NOT NULL,
FOREIGN KEY(recipe) REFERENCES recipes(id)
);
diff --git a/model/step.go b/model/step.go
index 24a11f4..f689fb9 100644
--- a/model/step.go
+++ b/model/step.go
@@ -1,89 +1,123 @@
package model
import (
+ "errors"
+ "encoding/json"
"database/sql"
+ "fmt"
)
type Step struct {
+ Id string `json:"id"`
+ Index string `json:"index"`
Text string `json:"text"`
+ Recipe string `json:"recipe"`
}
-func (r *Recipe) CreateSteps(tx *sql.Tx) error {
- err := r.DeleteSteps(tx)
- if err != nil {
- return err
+func (s Step) String() string {
+ b, _ := json.MarshalIndent(s, "", " ")
+ return string(b)
+}
+
+func (s *Step) Create(tx *sql.Tx) error {
+ if s.Id != "" {
+ return fmt.Errorf("Cannot create step if ID is given")
}
cmd := `
INSERT INTO steps
- (recipe, 'index', text)
+ ('index', text, recipe)
VALUES
(?, ?, ?)
`
- for i, s := range r.Steps {
- _, err := tx.Exec(cmd, r.Id, i, s.Text)
- if err != nil {
- return err
- }
+ result, err := tx.Exec(cmd, s.Index, s.Text, s.Recipe)
+ if err != nil {
+ return err
}
+ id, err := result.LastInsertId()
+ if err != nil {
+ return err
+ }
+
+ s.Id = fmt.Sprint(id)
+
return nil
}
-func (r *Recipe) ReadSteps(tx *sql.Tx) error {
+func (s *Step) Read(tx *sql.Tx) error {
cmd := `
SELECT
- text
+ "index", text, recipe
FROM
steps
WHERE
- recipe = ?
-ORDER BY
- 'index' ASC
+ id = ?
`
- rows, err := tx.Query(cmd, r.Id)
+ rows, err := tx.Query(cmd, s.Id)
if err != nil {
return err
}
+ defer rows.Close()
- r.Steps = make([]Step, 0)
- for rows.Next() {
- s := Step{}
-
- err = rows.Scan(&s.Text)
- if err != nil {
- return err
- }
+ if !rows.Next() {
+ return sql.ErrNoRows
+ }
- r.Steps = append(r.Steps, s)
+ err = rows.Scan(&s.Index, &s.Text, &s.Recipe)
+ if err != nil {
+ return err
}
return nil
}
-func (r *Recipe) UpdateSteps(tx *sql.Tx) error {
- err := r.DeleteSteps(tx)
+func (s *Step) Update(tx *sql.Tx) error {
+ cmd := `
+UPDATE
+ steps
+SET
+ index = ?,
+ text = ?,
+ recipe = ?
+WHERE
+ id = ?`
+
+ res, err := tx.Exec(cmd, s.Index, s.Text, s.Recipe, s.Id)
if err != nil {
return err
}
- return r.CreateSteps(tx)
+ affected, err := res.RowsAffected()
+ if err != nil {
+ return err
+ }
+ if affected != 1 {
+ return fmt.Errorf("Recipe update affected %d rows instead of 1", affected)
+ }
+
+ return nil
}
-func (r *Recipe) DeleteSteps(tx *sql.Tx) error {
+func (s *Step) Delete(tx *sql.Tx) error {
cmd := `
DELETE FROM
steps
WHERE
- recipe = ?
+ id = ?
`
- _, err := tx.Exec(cmd, r.Id)
+ result, err := tx.Exec(cmd, s.Id)
if err != nil {
return err
}
+ rows, err := result.RowsAffected()
+ if rows != 1 {
+ return errors.New("Recipe deletion did not affect exactly one row")
+ }
+
return nil
}