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.
195 lines
6.5 KiB
195 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
|
|
ib, _ := s.GetItemByBarcode(i.Barcode, user)
|
|
if 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
|
|
}
|
|
} else {
|
|
i.ID = ib.ID
|
|
}
|
|
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
|
|
}
|