package request import ( "enaklo-pos-be/internal/entity" "github.com/gin-gonic/gin" "github.com/pkg/errors" "strconv" "time" ) type QueryParser struct { defaultLimit int maxLimit int } func NewQueryParser() *QueryParser { return &QueryParser{ defaultLimit: 20, maxLimit: 100, } } func (p *QueryParser) ParseSearchRequest(c *gin.Context) (*entity.SearchRequest, error) { req := &entity.SearchRequest{} if status := c.Query("status"); status != "" { req.Status = status } limit, err := p.parseLimit(c.Query("limit")) if err != nil { return nil, errors.Wrap(err, "invalid limit parameter") } req.Limit = limit offset, err := p.parseOffset(c.Query("offset")) if err != nil { return nil, errors.Wrap(err, "invalid offset parameter") } req.Offset = offset if err := p.parseDateRange(c, req); err != nil { return nil, errors.Wrap(err, "invalid date parameters") } return req, nil } func (p *QueryParser) parseLimit(limitStr string) (int, error) { if limitStr == "" { return p.defaultLimit, nil } limit, err := strconv.Atoi(limitStr) if err != nil { return 0, errors.New("limit must be a valid integer") } if limit <= 0 { return p.defaultLimit, nil } if limit > p.maxLimit { limit = p.maxLimit } return limit, nil } func (p *QueryParser) parseOffset(offsetStr string) (int, error) { if offsetStr == "" { return 0, nil } offset, err := strconv.Atoi(offsetStr) if err != nil { return 0, errors.New("offset must be a valid integer") } if offset < 0 { return 0, nil } return offset, nil } func (p *QueryParser) parseDateRange(c *gin.Context, req *entity.SearchRequest) error { if startDateStr := c.Query("start_date"); startDateStr != "" { startDate, err := p.parseDate(startDateStr) if err != nil { return errors.Wrap(err, "invalid start_date format") } req.Start = startDate } if endDateStr := c.Query("end_date"); endDateStr != "" { endDate, err := p.parseDate(endDateStr) if err != nil { return errors.Wrap(err, "invalid end_date format") } req.End = endDate } if !req.Start.IsZero() && !req.End.IsZero() && req.Start.After(req.End) { return errors.New("start_date cannot be after end_date") } return nil } func (p *QueryParser) parseDate(dateStr string) (time.Time, error) { formats := []string{ time.RFC3339, "2006-01-02T15:04:05", "2006-01-02", "2006-01-02 15:04:05", } for _, format := range formats { if date, err := time.Parse(format, dateStr); err == nil { return date, nil } } return time.Time{}, errors.New("unsupported date format") }