package validator import ( "errors" "strings" "apskel-pos-be/internal/constants" "apskel-pos-be/internal/contract" ) type CategoryValidator interface { ValidateCreateCategoryRequest(req *contract.CreateCategoryRequest) (error, string) ValidateUpdateCategoryRequest(req *contract.UpdateCategoryRequest) (error, string) ValidateListCategoriesRequest(req *contract.ListCategoriesRequest) (error, string) } type CategoryValidatorImpl struct{} func NewCategoryValidator() *CategoryValidatorImpl { return &CategoryValidatorImpl{} } func (v *CategoryValidatorImpl) ValidateCreateCategoryRequest(req *contract.CreateCategoryRequest) (error, string) { if req == nil { return errors.New("request body is required"), constants.MissingFieldErrorCode } if strings.TrimSpace(req.Name) == "" { return errors.New("name is required"), constants.MissingFieldErrorCode } if len(req.Name) < 1 || len(req.Name) > 255 { return errors.New("name must be between 1 and 255 characters"), constants.MalformedFieldErrorCode } if req.Description != nil && len(*req.Description) > 1000 { return errors.New("description cannot exceed 1000 characters"), constants.MalformedFieldErrorCode } if req.BusinessType != nil && strings.TrimSpace(*req.BusinessType) != "" { validBusinessTypes := map[string]bool{ "restaurant": true, "cafe": true, "bar": true, "fastfood": true, "retail": true, } if !validBusinessTypes[*req.BusinessType] { return errors.New("invalid business_type"), constants.MalformedFieldErrorCode } } return nil, "" } func (v *CategoryValidatorImpl) ValidateUpdateCategoryRequest(req *contract.UpdateCategoryRequest) (error, string) { if req == nil { return errors.New("request body is required"), constants.MissingFieldErrorCode } // At least one field should be provided for update if req.Name == nil && req.Description == nil && req.BusinessType == nil && req.Metadata == nil { return errors.New("at least one field must be provided for update"), constants.MissingFieldErrorCode } if req.Name != nil { if strings.TrimSpace(*req.Name) == "" { return errors.New("name cannot be empty"), constants.MalformedFieldErrorCode } if len(*req.Name) < 1 || len(*req.Name) > 255 { return errors.New("name must be between 1 and 255 characters"), constants.MalformedFieldErrorCode } } if req.Description != nil && len(*req.Description) > 1000 { return errors.New("description cannot exceed 1000 characters"), constants.MalformedFieldErrorCode } if req.BusinessType != nil && strings.TrimSpace(*req.BusinessType) != "" { validBusinessTypes := map[string]bool{ "restaurant": true, "cafe": true, "bar": true, "fastfood": true, "retail": true, } if !validBusinessTypes[*req.BusinessType] { return errors.New("invalid business_type"), constants.MalformedFieldErrorCode } } return nil, "" } func (v *CategoryValidatorImpl) ValidateListCategoriesRequest(req *contract.ListCategoriesRequest) (error, string) { if req == nil { return errors.New("request is required"), constants.MissingFieldErrorCode } if req.Page < 1 { return errors.New("page must be at least 1"), constants.MalformedFieldErrorCode } if req.Limit < 1 || req.Limit > 100 { return errors.New("limit must be between 1 and 100"), constants.MalformedFieldErrorCode } if req.BusinessType != "" { validBusinessTypes := map[string]bool{ "restaurant": true, "cafe": true, "bar": true, "fastfood": true, "retail": true, } if !validBusinessTypes[req.BusinessType] { return errors.New("invalid business_type"), constants.MalformedFieldErrorCode } } return nil, "" }