You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
quartermaster/internal/postgres/items.go

192 lines
6.5 KiB

package postgres
import (
"database/sql"
"log"
"github.com/dustinpianalto/errors"
"github.com/dustinpianalto/quartermaster"
"github.com/dustinpianalto/quartermaster/internal/utils"
)
type itemService struct {
db *sql.DB
}
func (s itemService) Item(id int, user *quartermaster.User) (*quartermaster.Item, error) {
var method errors.Method = "postgres/Items"
var i quartermaster.Item
queryString := "SELECT id, name, description, size, unit, barcode, nutrition_id FROM items WHERE id = $1 AND owner_id = $2"
row := s.db.QueryRow(queryString, id, user.ID)
var nutrition_id sql.NullInt32
var unit string
err := row.Scan(&i.ID, &i.Name, &i.Description, &i.Size, &unit, &i.Barcode, &nutrition_id)
if err != nil {
return nil, errors.E(method, errors.Internal, "error getting item data", err)
}
i.Unit, err = utils.UnitFromString(unit)
if err != nil {
return nil, errors.E(method, err)
}
if nutrition_id.Valid {
n, err := NutritionService.Nutrition(int(nutrition_id.Int32))
if err != nil {
return nil, errors.E(method, "error getting nutrition data", err)
}
i.Nutrition = n
} else {
i.Nutrition = nil
}
return &i, nil
}
func (s itemService) AddItem(i *quartermaster.Item, l *quartermaster.Location, user *quartermaster.User) (*quartermaster.Item, error) {
var err error
if ib, _ := s.GetItemByBarcode(i.Barcode, user); ib == nil {
if i.Nutrition != nil {
i.Nutrition, err = NutritionService.AddNutrition(i.Nutrition)
if err != nil {
log.Println(err)
}
queryString := "INSERT INTO items (name, description, size, unit, barcode, nutrition_id, owner_id) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id"
err = s.db.QueryRow(queryString, i.Name, i.Description, i.Size, i.Unit.String(), i.Barcode, i.Nutrition.ID, user.ID).Scan(&i.ID)
} else {
queryString := "INSERT INTO items (name, description, size, unit, barcode, nutrition_id, owner_id) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id"
err = s.db.QueryRow(queryString, i.Name, i.Description, i.Size, i.Unit.String(), i.Barcode, nil, user.ID).Scan(&i.ID)
}
if err != nil {
return nil, err
}
}
queryString := "INSERT INTO x_items_locations (item_id, location_id, count) VALUES ($1, $2, 1) ON CONFLICT (item_id, location_id) DO UPDATE SET count = x_items_locations.count + 1"
_, err = s.db.Exec(queryString, i.ID, l.ID)
return i, err
}
func (s itemService) AddCategory(i *quartermaster.Item, c *quartermaster.Category) error {
queryString := "INSERT INTO x_items_categories (item_id, category_id) VALUES ($1, $2) ON DUPLICATE KEY DO NOTHING"
_, err := s.db.Exec(queryString, i.ID, c.ID)
return err
}
func (s itemService) AddGroup(i *quartermaster.Item, g *quartermaster.Group) error {
queryString := "INSERT INTO x_items_groups (item_id, group_id) VALUES ($1, $2) ON DUPLICATE KEY DO NOTHING"
_, err := s.db.Exec(queryString, i.ID, g.ID)
return err
}
func (s itemService) RemoveCategory(i *quartermaster.Item, c *quartermaster.Category) error {
queryString := "DELETE FROM x_items_categories WHERE item_id = $1 AND category_id = $2"
_, err := s.db.Exec(queryString, i.ID, c.ID)
return err
}
func (s itemService) RemoveGroup(i *quartermaster.Item, g *quartermaster.Group) error {
queryString := "DELETE FROM x_items_groups WHERE item_id = $1 AND group_id = $2"
_, err := s.db.Exec(queryString, i.ID, g.ID)
return err
}
func (s itemService) DeleteItem(i *quartermaster.Item, user *quartermaster.User) error {
queryString := "DELETE FROM items WHERE id = $1 AND owner_id = $2"
_, err := s.db.Exec(queryString, i.ID, user.ID)
return err
}
func (s itemService) GetItemByBarcode(b string, user *quartermaster.User) (*quartermaster.Item, error) {
queryString := "SELECT id FROM items WHERE barcode = $1 AND owner_id = $2"
row := s.db.QueryRow(queryString, b, user.ID)
var id int
err := row.Scan(&id)
if err != nil {
return nil, err
}
return s.Item(id, user)
}
func (s itemService) RemoveItem(i *quartermaster.Item, l *quartermaster.Location, u *quartermaster.User) error {
const method errors.Method = "itemService/RemoveItem"
if ok, err := s.IsOwner(i, u); !ok {
return errors.E(method, err)
}
queryString := "UPDATE x_items_locations SET count = count - 1 WHERE item_id = $1 AND location_id = $2 RETURNING count"
var count int
err := s.db.QueryRow(queryString, i.ID, l.ID).Scan(&count)
if err != nil {
return err
}
if count <= 0 {
queryString = "DELETE FROM x_items_locations WHERE item_id = $1 AND location_id = $2"
_, err := s.db.Exec(queryString, i.ID, l.ID)
return err
}
return nil
}
func (s itemService) MoveItem(i *quartermaster.Item, old, new *quartermaster.Location, user *quartermaster.User) error {
err := s.RemoveItem(i, old, user)
if err != nil {
return err
}
_, err = s.AddItem(i, new, user)
return err
}
func (s itemService) UpdateItem(i *quartermaster.Item, user *quartermaster.User) error {
var err error
if i.Nutrition != nil {
if i.Nutrition.ID == 0 {
i.Nutrition, err = NutritionService.AddNutrition(i.Nutrition)
if err != nil {
return err
}
} else {
err = NutritionService.UpdateNutrition(i.Nutrition)
if err != nil {
return err
}
}
}
queryString := "UPDATE items SET name = $2, description = $3, size = $4, unit = $5, barcode = $6, nutrition_id = $7, WHERE id = $1 AND owner_id = $8"
_, err = s.db.Exec(queryString, i.ID, i.Name, i.Description, i.Size, i.Unit, i.Barcode, i.Nutrition.ID, user.ID)
return err
}
func (s itemService) IsOwner(i *quartermaster.Item, u *quartermaster.User) (bool, error) {
const method errors.Method = "itemService/IsOwner"
var ownerID int
queryString := "SELECT owner_id FROM items WHERE id = $1"
row := s.db.QueryRow(queryString, i.ID)
err := row.Scan(&ownerID)
if err != nil {
return false, errors.E(method, errors.Internal, "error getting owner", err)
}
if ownerID == u.ID {
return true, nil
}
return false, nil
}
func (s itemService) GetItemLocations(i *quartermaster.Item, u *quartermaster.User) (map[int]int, error) {
const method errors.Method = "itemService/GetItemLocations"
if ok, err := s.IsOwner(i, u); !ok {
return nil, errors.E(method, err)
}
queryString := "SELECT location_id, count FROM x_items_locations WHERE item_id = $1"
rows, err := s.db.Query(queryString, i.ID)
if err != nil {
return nil, errors.E(method, errors.Internal, "error getting locations", err)
}
out := make(map[int]int)
for rows.Next() {
var lID int
var count int
err := rows.Scan(&lID, &count)
if err != nil {
log.Println(errors.E(method, errors.Internal, err))
}
out[lID] = count
}
return out, nil
}