package config import ( "errors" "strconv" "sync" "time" "gorm.io/gorm" ) type Service struct { repo *Repository // Small in-memory cache to avoid hitting the DB on every request. // Updated on SetString; lazy-filled on first Get. mu sync.RWMutex cache map[string]string } func NewService(r *Repository) *Service { return &Service{repo: r, cache: make(map[string]string)} } func (s *Service) EnsureDefaults() error { for k, v := range DefaultKeyValues() { if err := s.repo.CreateIfMissing(k, v); err != nil { return err } } return nil } func (s *Service) List() ([]ConfigEntry, error) { entries, err := s.repo.List() if err != nil { return nil, err } // refresh cache snapshot s.mu.Lock() for _, e := range entries { s.cache[e.Key] = e.Value } s.mu.Unlock() return entries, nil } func (s *Service) SetString(key, value string) error { if err := s.repo.Upsert(key, value); err != nil { return err } s.mu.Lock() s.cache[key] = value s.mu.Unlock() return nil } func (s *Service) GetStringDefault(key, def string) string { s.mu.RLock() v, ok := s.cache[key] s.mu.RUnlock() if ok { if v == "" { return def } return v } e, err := s.repo.Get(key) if err != nil { return def } s.mu.Lock() s.cache[key] = e.Value s.mu.Unlock() if e.Value == "" { return def } return e.Value } func (s *Service) GetIntDefault(key string, def int) int { v := s.GetStringDefault(key, "") if v == "" { return def } n, err := strconv.Atoi(v) if err != nil { return def } return n } func (s *Service) GetInt64Default(key string, def int64) int64 { v := s.GetStringDefault(key, "") if v == "" { return def } n, err := strconv.ParseInt(v, 10, 64) if err != nil { return def } return n } func (s *Service) GetBoolDefault(key string, def bool) bool { v := s.GetStringDefault(key, "") if v == "" { return def } b, err := strconv.ParseBool(v) if err != nil { return def } return b } func (s *Service) GetDurationSecondsDefault(key string, def time.Duration) time.Duration { v := s.GetStringDefault(key, "") if v == "" { return def } n, err := strconv.Atoi(v) if err != nil { return def } return time.Duration(n) * time.Second } func IsNotFound(err error) bool { return errors.Is(err, gorm.ErrRecordNotFound) }