diff --git a/internal/store/cake.go b/internal/store/cake.go new file mode 100644 index 0000000..0d40ef1 --- /dev/null +++ b/internal/store/cake.go @@ -0,0 +1,65 @@ +package store + +import ( + "errors" + "strconv" +) + +type Cake struct { + Name string + ID int + Price int + Amount int +} + + +func (s *Store) GetCake(id int) (Cake, error) { + out := Cake{ID: id} + row, err := s.db.Query("select name, price from cake where id = ?;", id) + if err != nil { + return out, err + } + defer row.Close() + row.Next() + err = row.Scan(&out.Name, &out.Price) + return out, err +} + +func (s *Store) GetCakes() ([]Cake, error) { + rows, err := s.db.Query("select id, name, price from cake") + if err != nil { + return nil, err + } + defer rows.Close() + cakes := make([]Cake, 0) + for rows.Next() { + var c Cake + c.Amount = 0 + err = rows.Scan(&c.ID, &c.Name, &c.Price) + if err != nil { + return nil, err + } + cakes = append(cakes, c) + } + return cakes, err +} + +func (s *Store) SaveCake(newCake Cake) (int, error) { + query := "insert into cake(name, price) values (?, ?) returning id;" + if newCake.ID != 0 { + query = "update cake set name = ? , price = ? where id = " + query += strconv.Itoa(newCake.ID) + " returning id;" + } + + row, err := s.db.Query(query, newCake.Name, newCake.Price) + if err != nil { + return 0, err + } + defer row.Close() + + if !row.Next() { + return 0, errors.New("The database didn't respond with an id") + } + err = row.Scan(&newCake.ID) + return newCake.ID, err +} diff --git a/internal/store/schema.sql b/internal/store/migrations/1.sql similarity index 100% rename from internal/store/schema.sql rename to internal/store/migrations/1.sql diff --git a/internal/store/migrations/2.sql b/internal/store/migrations/2.sql new file mode 100644 index 0000000..b8b6b93 --- /dev/null +++ b/internal/store/migrations/2.sql @@ -0,0 +1,8 @@ +create table session ( + token text primary key, + user_name text, + created text, + lastAccess text +); + +PRAGMA user_version = 2; diff --git a/internal/store/model.go b/internal/store/model.go deleted file mode 100644 index 6884bc2..0000000 --- a/internal/store/model.go +++ /dev/null @@ -1,23 +0,0 @@ -package store - -import "time" - -type Cake struct { - Name string - ID int - Price int - Amount int -} - -type Order struct { - ID int - Name string - Surname string - Phone string - Location string - Date time.Time - Accepted time.Time - Status string - Paid int // increments of 0.01 - Cakes []Cake -} diff --git a/internal/store/order.go b/internal/store/order.go new file mode 100644 index 0000000..d60e7d5 --- /dev/null +++ b/internal/store/order.go @@ -0,0 +1,159 @@ +package store + +import ( + "errors" + "strconv" + "time" +) + +type Order struct { + ID int + Name string + Surname string + Phone string + Location string + Date time.Time + Accepted time.Time + Status string + Paid int // increments of 0.01 + Cakes []Cake +} + +func (s *Store) GetOrder(id int) (Order, error) { + var out Order + row, err := s.db.Query("select id, name, surname, phone, location, order_date, delivery_date, status, paid from customer_order where id = ?;", id) + if err != nil { + return out, err + } + defer row.Close() + + var order_date, delivery_date string + row.Next() + err = row.Scan(&out.ID, &out.Name, &out.Surname, &out.Phone, &out.Location, &order_date, &delivery_date, &out.Status, &out.Paid) + if err != nil { + return out, err + } + out.Accepted, _ = time.Parse("2006-01-02 15:04", order_date) + out.Date, _ = time.Parse("2006-01-02 15:04", delivery_date) + + out.Cakes = make([]Cake, 0) + rows, err := s.db.Query("select cake, amount from ordered_cake where customer_order = ?;", id) + if err != nil { + return out, err + } + defer rows.Close() + for rows.Next() { + var newCake Cake + err = rows.Scan(&newCake.ID, &newCake.Amount) + if err != nil { + return out, err + } + cakeData, err := s.GetCake(newCake.ID) + if err != nil { + continue + } + newCake.Name = cakeData.Name + newCake.Price = cakeData.Price + out.Cakes = append(out.Cakes, newCake) + } + + return out, nil +} + +func (s *Store) GetOrders() ([]Order, error) { + var out []Order + rows, err := s.db.Query("select id, name, surname, phone, location, order_date, delivery_date, status, paid from customer_order;") + if err != nil { + return out, err + } + defer rows.Close() + + for rows.Next() { + var o Order + var order_date, delivery_date string + err = rows.Scan(&o.ID, &o.Name, &o.Surname, &o.Phone, &o.Location, &order_date, &delivery_date, &o.Status, &o.Paid) + if err != nil { + return nil, err + } + o.Accepted, _ = time.Parse("2006-01-02 15:04", order_date) + o.Date, _ = time.Parse("2006-01-02 15:04", delivery_date) + + o.Cakes = make([]Cake, 0) + rows, err := s.db.Query("select cake, amount from ordered_cake where customer_order = ?;", o.ID) + + if err != nil { + return out, err + } + defer rows.Close() + for rows.Next() { + var newCake Cake + err = rows.Scan(&newCake.ID, &newCake.Amount) + if err != nil { + return out, err + } + cakeData, err := s.GetCake(newCake.ID) + if err != nil { + continue + } + newCake.Name = cakeData.Name + newCake.Price = cakeData.Price + o.Cakes = append(o.Cakes, newCake) + } + + out = append(out, o) + } + + return out, nil +} + +func (s *Store) SaveOrder(newOrder Order) (int, error) { + query := "insert into customer_order(name, surname, phone, location, order_date, delivery_date, status, paid) values (?, ?, ?, ?, ?, ?, ?, ?) returning id;" + if newOrder.ID != 0 { + query = "update customer_order set name = ?, surname = ?, phone = ?, location = ?, order_date = ?, delivery_date = ?, status = ?, paid = ? where id = " + query += strconv.Itoa(newOrder.ID) + " returning id;" + } + tx, err := s.db.Begin() + if err != nil { + return 0, err + } + + accepted := newOrder.Accepted.Format("2006-01-02 15:04") + date := newOrder.Date.Format("2006-01-02 15:04") + row, err := tx.Query(query, newOrder.Name, newOrder.Surname, newOrder.Phone, newOrder.Location, accepted, date, newOrder.Status, newOrder.Paid) + if err != nil { + _ = tx.Rollback() + return 0, err + } + defer row.Close() + + if !row.Next() { + _ = tx.Rollback() + return 0, errors.New("The database didn't respond with an id") + } + err = row.Scan(&newOrder.ID) + if err != nil { + _ = tx.Rollback() + return newOrder.ID, err + } + + // remove all ordered_cakes associated with this order before inserting + query = "delete from ordered_cake where customer_order = ?;" + _, err = tx.Exec(query, newOrder.ID) + if err != nil { + _ = tx.Rollback() + return newOrder.ID, err + } + + // add all ordered_cakes for this order + query = "insert into ordered_cake(customer_order, cake, amount) values (?,?,?);" + for _, e := range newOrder.Cakes { + _, err := tx.Exec(query, newOrder.ID, e.ID, e.Amount) + if err != nil { + _ = tx.Rollback() + return newOrder.ID, err + } + } + + err = tx.Commit() + return newOrder.ID, err +} diff --git a/internal/store/store.go b/internal/store/store.go index b038ed9..7d02ce5 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -2,17 +2,15 @@ package store import ( "database/sql" + "embed" _ "embed" "errors" "strconv" - "time" + "strings" _ "github.com/mattn/go-sqlite3" ) -//go:embed schema.sql -var schema string - type Store struct { db *sql.DB } @@ -48,205 +46,36 @@ func (s *Store) version() int { return out } +//go:embed migrations/*.sql +var migrations embed.FS + func (s *Store) loadSchema() error { if s.db == nil { return errors.New("database doesn't exist") } - if s.version() == 1 { - return nil - } - - _, err := s.db.Exec(schema) - return err -} - -func (s *Store) GetCake(id int) (Cake, error) { - out := Cake{ID: id} - row, err := s.db.Query("select name, price from cake where id = ?;", id) + migration_files, err := migrations.ReadDir("migrations") if err != nil { - return out, err + return err } - defer row.Close() - row.Next() - err = row.Scan(&out.Name, &out.Price) - return out, err -} - -func (s *Store) GetCakes() ([]Cake, error) { - rows, err := s.db.Query("select id, name, price from cake") - if err != nil { - return nil, err - } - defer rows.Close() - cakes := make([]Cake, 0) - for rows.Next() { - var c Cake - c.Amount = 0 - err = rows.Scan(&c.ID, &c.Name, &c.Price) - if err != nil { - return nil, err - } - cakes = append(cakes, c) - } - return cakes, err -} - -func (s *Store) SaveCake(newCake Cake) (int, error) { - query := "insert into cake(name, price) values (?, ?) returning id;" - if newCake.ID != 0 { - query = "update cake set name = ? , price = ? where id = " - query += strconv.Itoa(newCake.ID) + " returning id;" - } - - row, err := s.db.Query(query, newCake.Name, newCake.Price) - if err != nil { - return 0, err - } - defer row.Close() - - if !row.Next() { - return 0, errors.New("The database didn't respond with an id") - } - err = row.Scan(&newCake.ID) - return newCake.ID, err -} - -func (s *Store) GetOrder(id int) (Order, error) { - var out Order - row, err := s.db.Query("select id, name, surname, phone, location, order_date, delivery_date, status, paid from customer_order where id = ?;", id) - if err != nil { - return out, err - } - defer row.Close() - - var order_date, delivery_date string - row.Next() - err = row.Scan(&out.ID, &out.Name, &out.Surname, &out.Phone, &out.Location, &order_date, &delivery_date, &out.Status, &out.Paid) - if err != nil { - return out, err - } - out.Accepted, _ = time.Parse("2006-01-02 15:04", order_date) - out.Date, _ = time.Parse("2006-01-02 15:04", delivery_date) - - out.Cakes = make([]Cake, 0) - rows, err := s.db.Query("select cake, amount from ordered_cake where customer_order = ?;", id) - if err != nil { - return out, err - } - defer rows.Close() - for rows.Next() { - var newCake Cake - err = rows.Scan(&newCake.ID, &newCake.Amount) - if err != nil { - return out, err - } - cakeData, err := s.GetCake(newCake.ID) + for _, e := range migration_files { + filename := strings.Split(e.Name(), ".") + version, err := strconv.Atoi(filename[0]) if err != nil { continue } - newCake.Name = cakeData.Name - newCake.Price = cakeData.Price - out.Cakes = append(out.Cakes, newCake) - } - - return out, nil -} - -func (s *Store) GetOrders() ([]Order, error) { - var out []Order - rows, err := s.db.Query("select id, name, surname, phone, location, order_date, delivery_date, status, paid from customer_order;") - if err != nil { - return out, err - } - defer rows.Close() - - for rows.Next() { - var o Order - var order_date, delivery_date string - err = rows.Scan(&o.ID, &o.Name, &o.Surname, &o.Phone, &o.Location, &order_date, &delivery_date, &o.Status, &o.Paid) + if version <= s.version() { + continue + } + query, err := migrations.ReadFile("migrations/" + e.Name()) if err != nil { - return nil, err + continue } - o.Accepted, _ = time.Parse("2006-01-02 15:04", order_date) - o.Date, _ = time.Parse("2006-01-02 15:04", delivery_date) - - o.Cakes = make([]Cake, 0) - rows, err := s.db.Query("select cake, amount from ordered_cake where customer_order = ?;", o.ID) - + _, err = s.db.Exec(string(query)) if err != nil { - return out, err + return err } - defer rows.Close() - for rows.Next() { - var newCake Cake - err = rows.Scan(&newCake.ID, &newCake.Amount) - if err != nil { - return out, err - } - cakeData, err := s.GetCake(newCake.ID) - if err != nil { - continue - } - newCake.Name = cakeData.Name - newCake.Price = cakeData.Price - o.Cakes = append(o.Cakes, newCake) - } - - out = append(out, o) } - return out, nil -} - -func (s *Store) SaveOrder(newOrder Order) (int, error) { - query := "insert into customer_order(name, surname, phone, location, order_date, delivery_date, status, paid) values (?, ?, ?, ?, ?, ?, ?, ?) returning id;" - if newOrder.ID != 0 { - query = "update customer_order set name = ?, surname = ?, phone = ?, location = ?, order_date = ?, delivery_date = ?, status = ?, paid = ? where id = " - query += strconv.Itoa(newOrder.ID) + " returning id;" - } - tx, err := s.db.Begin() - if err != nil { - return 0, err - } - - accepted := newOrder.Accepted.Format("2006-01-02 15:04") - date := newOrder.Date.Format("2006-01-02 15:04") - row, err := tx.Query(query, newOrder.Name, newOrder.Surname, newOrder.Phone, newOrder.Location, accepted, date, newOrder.Status, newOrder.Paid) - if err != nil { - _ = tx.Rollback() - return 0, err - } - defer row.Close() - - if !row.Next() { - _ = tx.Rollback() - return 0, errors.New("The database didn't respond with an id") - } - err = row.Scan(&newOrder.ID) - if err != nil { - _ = tx.Rollback() - return newOrder.ID, err - } - - // remove all ordered_cakes associated with this order before inserting - query = "delete from ordered_cake where customer_order = ?;" - _, err = tx.Exec(query, newOrder.ID) - if err != nil { - _ = tx.Rollback() - return newOrder.ID, err - } - - // add all ordered_cakes for this order - query = "insert into ordered_cake(customer_order, cake, amount) values (?,?,?);" - for _, e := range newOrder.Cakes { - _, err := tx.Exec(query, newOrder.ID, e.ID, e.Amount) - if err != nil { - _ = tx.Rollback() - return newOrder.ID, err - } - } - - err = tx.Commit() - return newOrder.ID, err + return nil }