diff --git a/internal/entities/reward.go b/internal/entities/reward.go index 2254ff0..f05e417 100644 --- a/internal/entities/reward.go +++ b/internal/entities/reward.go @@ -1,6 +1,9 @@ package entities import ( + "database/sql/driver" + "encoding/json" + "fmt" "time" "github.com/google/uuid" @@ -16,11 +19,67 @@ const ( RewardTypeBalance RewardType = "BALANCE" ) +// StringSlice is a custom type for []string that implements sql.Scanner and driver.Valuer +type StringSlice []string + +// Scan implements the sql.Scanner interface for StringSlice +func (s *StringSlice) Scan(value interface{}) error { + if value == nil { + *s = StringSlice{} + return nil + } + + var bytes []byte + switch v := value.(type) { + case []byte: + bytes = v + case string: + bytes = []byte(v) + default: + return fmt.Errorf("cannot scan %T into StringSlice", value) + } + + return json.Unmarshal(bytes, s) +} + +// Value implements the driver.Valuer interface for StringSlice +func (s StringSlice) Value() (driver.Value, error) { + if s == nil { + return nil, nil + } + return json.Marshal(s) +} + type TermsAndConditions struct { Sections []TncSection `json:"sections"` ExpiryDays int `json:"expiry_days"` } +// Scan implements the sql.Scanner interface for TermsAndConditions +func (t *TermsAndConditions) Scan(value interface{}) error { + if value == nil { + *t = TermsAndConditions{} + return nil + } + + var bytes []byte + switch v := value.(type) { + case []byte: + bytes = v + case string: + bytes = []byte(v) + default: + return fmt.Errorf("cannot scan %T into TermsAndConditions", value) + } + + return json.Unmarshal(bytes, t) +} + +// Value implements the driver.Valuer interface for TermsAndConditions +func (t TermsAndConditions) Value() (driver.Value, error) { + return json.Marshal(t) +} + type TncSection struct { Title string `json:"title"` Rules []string `json:"rules"` @@ -35,7 +94,7 @@ type Reward struct { MaxPerCustomer int `gorm:"type:int;default:1" json:"max_per_customer"` Tnc *TermsAndConditions `gorm:"type:jsonb" json:"tnc,omitempty"` Metadata *map[string]interface{} `gorm:"type:jsonb" json:"metadata,omitempty"` - Images *[]string `gorm:"type:jsonb" json:"images,omitempty"` + Images *StringSlice `gorm:"type:jsonb" json:"images,omitempty"` CreatedAt time.Time `gorm:"type:timestamp;default:now()" json:"created_at"` UpdatedAt time.Time `gorm:"type:timestamp;default:now()" json:"updated_at"` } diff --git a/internal/mappers/reward_mapper.go b/internal/mappers/reward_mapper.go index 72c01f0..d908ab7 100644 --- a/internal/mappers/reward_mapper.go +++ b/internal/mappers/reward_mapper.go @@ -28,7 +28,8 @@ func ToRewardResponse(entity *entities.Reward) *models.RewardResponse { var images *[]string if entity.Images != nil { - images = entity.Images + imagesSlice := []string(*entity.Images) + images = &imagesSlice } return &models.RewardResponse{ @@ -66,9 +67,10 @@ func ToRewardEntity(request *contract.CreateRewardRequest) *entities.Reward { } } - var images *[]string + var images *entities.StringSlice if request.Images != nil { - images = request.Images + stringSlice := entities.StringSlice(*request.Images) + images = &stringSlice } return &entities.Reward{ @@ -103,9 +105,10 @@ func ToRewardEntityFromUpdate(request *contract.UpdateRewardRequest) *entities.R } } - var images *[]string + var images *entities.StringSlice if request.Images != nil { - images = request.Images + stringSlice := entities.StringSlice(*request.Images) + images = &stringSlice } return &entities.Reward{