package storage import ( "context" "fmt" "relynolli-server/internal" "relynolli-server/models/catalog" filters2 "relynolli-server/models/filters" "slices" cmap "github.com/orcaman/concurrent-map/v2" "github.com/uptrace/bun" ) type StorageCatalog interface { GetCatalogItem(ctx context.Context, id *int64) (*catalog.DBCatalog, error) GetCatalogItemByCode(ctx context.Context, code string) (*catalog.DBCatalog, error) GetCatalogItems(ctx context.Context, filters cmap.ConcurrentMap[string, []string], limit int, offset int) (int, *[]catalog.DBCatalog, error) GetFilters(ctx context.Context) (int, *[]filters2.DBFilter, error) } func NewStorageCatalog() StorageCatalog { if instance == nil { instance = &storage{ db: internal.InitDatabase().GetInstance(), rdb: internal.InitRedis(), } } return instance } func (s *storage) GetCatalogItemByCode(ctx context.Context, code string) (*catalog.DBCatalog, error) { model := new(catalog.DBCatalog) err := s.db.NewSelect().Model(model).Where("code = ?", code).Where("available_quantity > 0").Where("is_active = 1").Scan(ctx) if err != nil { return nil, err } return model, nil } func (s *storage) GetCatalogItem(ctx context.Context, id *int64) (*catalog.DBCatalog, error) { model := new(catalog.DBCatalog) err := s.db.NewSelect().Model(model).Where("id = ?", id).Where("available_quantity > 0").Where("is_active = 1").Scan(ctx) if err != nil { return nil, err } return model, nil } func (s *storage) buildFilterGroup(ctx context.Context, q *bun.SelectQuery, filters *cmap.ConcurrentMap[string, []string]) *bun.SelectQuery { availableFilters := new([]filters2.DBFilter) //Get filters s.db.NewSelect().Model(availableFilters).Scan(ctx) for _, filter := range filters.Keys() { filter = filter[0 : len(filter)-2] if !slices.ContainsFunc(*availableFilters, func(elem filters2.DBFilter) bool { return elem.Code == filter }) { continue } q = q.WhereGroup(" AND ", func(query *bun.SelectQuery) *bun.SelectQuery { values, _ := filters.Get(filter + "[]") for _, val := range values { query = q.WhereOr(fmt.Sprintf("properties->>'$.%s' = ?", filter), val) } return query }) } return q } func (s *storage) GetCatalogItems(ctx context.Context, filters cmap.ConcurrentMap[string, []string], limit int, offset int) (int, *[]catalog.DBCatalog, error) { model := new([]catalog.DBCatalog) filterQuery := s.db.NewSelect().Model(model).Where("is_active = 1").Where("available_quantity > 0") count, _ := s.buildFilterGroup(ctx, filterQuery, &filters).Limit(limit).Offset(offset).Order("code").ScanAndCount(ctx) return count, model, nil } func (s *storage) GetFilters(ctx context.Context) (int, *[]filters2.DBFilter, error) { models := new([]filters2.DBFilter) count, err := s.db.NewSelect().Model(models).ScanAndCount(ctx) if err != nil { return 0, nil, err } return count, models, nil }