IngredientCreate(core.Ingredient) (core.Ingredient, error)
IngredientUpdate(core.Ingredient) error
IngredientDeactivate(int) error
+
IngredientGet(int) (*core.Ingredient, error)
IngredientGetByName(name string) (*core.Ingredient, error)
- // TODO: add search params
- IngredientList() ([]core.Ingredient, error)
+
+ IngredientCount(core.IngredientSearch) (int, error)
+ IngredientList(core.IngredientSearch) ([]core.Ingredient, error)
}
import (
"errors"
+ "fmt"
+ "math"
+ "regexp"
"time"
+ "jsdaj.tq/pf/persistence"
"jsdaj.tq/pf/pkg/core"
"jsdaj.tq/pf/pkg/util"
)
}
now := time.Now()
- p.ingredients[id-1].DeletedAt = &now
+ p.ingredients[id-1].DeletedAt = &now
return nil
}
return nil, nil
}
-func (p *InmemoryPersistence) IngredientList() ([]core.Ingredient, error) {
- filtered := util.Filter(p.ingredients, func(i core.Ingredient) bool { return i.DeletedAt == nil })
+func (p *InmemoryPersistence) IngredientCount(search core.IngredientSearch) (int, error) {
+ not_deleted := util.Filter(p.ingredients, filterByDeleted())
+ filtered := util.Filter(not_deleted, filterBySearch(search))
- return filtered, nil
+ return len(filtered), nil
+}
+
+func (p *InmemoryPersistence) IngredientList(search core.IngredientSearch) ([]core.Ingredient, error) {
+ not_deleted := util.Filter(p.ingredients, filterByDeleted())
+ filtered := util.Filter(not_deleted, filterBySearch(search))
+
+ if search.Skip > len(filtered) {
+ return []core.Ingredient{}, nil
+ }
+
+ highBound := persistence.DEFAULT_MAX_PAGE_SIZE + search.Skip
+ highBound = int(math.Min(float64(highBound), float64(len(filtered))))
+
+ return filtered[search.Skip:highBound], nil
+}
+
+func filterByDeleted() util.FilterFunc[core.Ingredient] {
+ return func(i core.Ingredient) bool {
+ return i.DeletedAt == nil
+ }
+}
+
+func filterBySearch(search core.IngredientSearch) util.FilterFunc[core.Ingredient] {
+ return func(i core.Ingredient) bool {
+ if !search.ShowNotAvailable && *i.Quantity == 0 {
+ return false
+ }
+
+ if len(search.NameLike) > 0 {
+ re := regexp.MustCompile(fmt.Sprintf("(?i).*%s.*", search.NameLike))
+
+ if !re.Match([]byte(i.Name)) {
+ return false
+ }
+ }
+ return true
+ }
}
package persistence
+const DEFAULT_MAX_PAGE_SIZE int = 10
+
type Persistence interface {
IngredientRepository
}
type Ingredient struct {
Id int `json:"id,omitempty"`
Name string `json:"name"`
- Quantity *int `json:"quantity"`
+ Quantity *int `json:"quantity"`
Description string `json:"description"`
CreatedAt *time.Time `json:"-"`
DeletedAt *time.Time `json:"-"`
return nil
}
+
+type IngredientSearch struct {
+ NameLike string
+ ShowNotAvailable bool
+ Skip int
+}
import (
shttp "net/http"
+ "strconv"
"jsdaj.tq/pf/pkg/core"
"jsdaj.tq/pf/pkg/http/util"
}
func (s *Server) ingredientHandleList(w shttp.ResponseWriter, r *shttp.Request) {
- ingredients, err := s.ingredients.List()
+ queryParams := r.URL.Query()
+
+ skip, err := strconv.Atoi(queryParams.Get("skip"))
+ if err != nil {
+ skip = 0
+ }
+
+ search := core.IngredientSearch{
+ NameLike: queryParams.Get("name"),
+ ShowNotAvailable: queryParams.Get("showNotAvailable") == "true",
+ Skip: skip,
+ }
+
+ ingredients, err := s.ingredients.List(search)
if err != nil {
util.HandleError(w, r, shttp.StatusInternalServerError, err.Error())
return
return nil
}
-func (s *Ingredient) List() ([]core.Ingredient, error) {
- ingredients, err := s.repository.IngredientList()
- if err != nil {
- return []core.Ingredient{}, errors.MapError(err)
- }
- return ingredients, nil
-}
-
func (s *Ingredient) Delete(id int) error {
in, err := s.repository.IngredientGet(id)
if err != nil {
return in, nil
}
+type IngredientList struct {
+ NextPageSkip int `json:"nextPageSkip"`
+ IsLastPage bool `json:"isLastPage"`
+ Data []core.Ingredient `json:"data"`
+}
+
+func (s *Ingredient) List(search core.IngredientSearch) (*IngredientList, error) {
+ total, err := s.repository.IngredientCount(search)
+ if err != nil {
+ return nil, errors.MapError(err)
+ }
+
+ ingredients, err := s.repository.IngredientList(search)
+ if err != nil {
+ return nil, errors.MapError(err)
+ }
+ nextPageSkip := search.Skip + len(ingredients)
+ isLastPage := nextPageSkip >= total
+
+ if isLastPage {
+ nextPageSkip = 0
+ }
+
+ return &IngredientList{
+ NextPageSkip: nextPageSkip,
+ IsLastPage: isLastPage,
+ Data: ingredients,
+ }, nil
+}
+
func InitIngredientService(repository persistence.IngredientRepository) Ingredient {
return Ingredient{
repository,