Files
jety/getters.go
Tai Groot 9ff1fdc5ee fix!: SetEnvPrefix now re-reads env vars with prefix stripping
SetEnvPrefix was broken: it set the prefix string but never re-read
environment variables. This meant collapse() and SetDefault() couldn't
match prefixed env vars to their unprefixed config keys, so defaults
always won over env vars.

The fix makes SetEnvPrefix behave identically to WithEnvPrefix: it
re-reads os.Environ(), strips the prefix from matching keys, and
stores the stripped keys in envConfig. The envPrefix field is removed
entirely since keys are always pre-stripped.

BREAKING CHANGE: SetEnvPrefix now filters env vars to only those
matching the prefix (previously all env vars were accessible).
This matches the documented and expected behavior.
2026-03-01 20:42:30 +00:00

229 lines
3.9 KiB
Go

package jety
import (
"fmt"
"strconv"
"strings"
"time"
)
func (c *ConfigManager) Get(key string) any {
c.mutex.RLock()
defer c.mutex.RUnlock()
v, ok := c.combinedConfig[strings.ToLower(key)]
if !ok {
v, ok = c.envConfig[strings.ToLower(key)]
if !ok {
return nil
}
}
return v.Value
}
func (c *ConfigManager) GetBool(key string) bool {
c.mutex.RLock()
defer c.mutex.RUnlock()
v, ok := c.combinedConfig[strings.ToLower(key)]
if !ok {
v, ok = c.envConfig[strings.ToLower(key)]
if !ok {
return false
}
}
val := v.Value
switch val := val.(type) {
case bool:
return val
case string:
return strings.EqualFold(val, "true")
case int:
return val != 0
case float32:
return val != 0
case float64:
return val != 0
case time.Duration:
return val > 0
case nil:
return false
default:
return false
}
}
func (c *ConfigManager) GetDuration(key string) time.Duration {
c.mutex.RLock()
defer c.mutex.RUnlock()
v, ok := c.combinedConfig[strings.ToLower(key)]
if !ok {
v, ok = c.envConfig[strings.ToLower(key)]
if !ok {
return 0
}
}
val := v.Value
switch val := val.(type) {
case time.Duration:
return val
case string:
d, err := time.ParseDuration(val)
if err != nil {
return 0
}
return d
case int:
return time.Duration(val)
case int64:
return time.Duration(val)
case float32:
return time.Duration(val)
case float64:
return time.Duration(val)
case nil:
return 0
default:
return 0
}
}
func (c *ConfigManager) GetString(key string) string {
c.mutex.RLock()
defer c.mutex.RUnlock()
v, ok := c.combinedConfig[strings.ToLower(key)]
if !ok {
v, ok = c.envConfig[strings.ToLower(key)]
if !ok {
return ""
}
}
switch val := v.Value.(type) {
case string:
return val
default:
return fmt.Sprintf("%v", v.Value)
}
}
func (c *ConfigManager) GetStringMap(key string) map[string]any {
c.mutex.RLock()
defer c.mutex.RUnlock()
v, ok := c.combinedConfig[strings.ToLower(key)]
if !ok {
v, ok = c.envConfig[strings.ToLower(key)]
if !ok {
return nil
}
}
switch val := v.Value.(type) {
case map[string]any:
return val
default:
return nil
}
}
func (c *ConfigManager) GetStringSlice(key string) []string {
c.mutex.RLock()
defer c.mutex.RUnlock()
v, ok := c.combinedConfig[strings.ToLower(key)]
if !ok {
v, ok = c.envConfig[strings.ToLower(key)]
if !ok {
return nil
}
}
switch val := v.Value.(type) {
case []string:
return val
case []any:
var ret []string
for _, v := range val {
switch v := v.(type) {
case string:
ret = append(ret, v)
default:
ret = append(ret, fmt.Sprintf("%v", v))
}
}
return ret
default:
return nil
}
}
func (c *ConfigManager) GetInt(key string) int {
c.mutex.RLock()
defer c.mutex.RUnlock()
v, ok := c.combinedConfig[strings.ToLower(key)]
if !ok {
v, ok = c.envConfig[strings.ToLower(key)]
if !ok {
return 0
}
}
switch val := v.Value.(type) {
case int:
return val
case int64:
return int(val)
case string:
i, err := strconv.Atoi(val)
if err != nil {
return 0
}
return i
case float32:
return int(val)
case float64:
return int(val)
case nil:
return 0
default:
return 0
}
}
func (c *ConfigManager) GetIntSlice(key string) []int {
c.mutex.RLock()
defer c.mutex.RUnlock()
v, ok := c.combinedConfig[strings.ToLower(key)]
if !ok {
v, ok = c.envConfig[strings.ToLower(key)]
if !ok {
return nil
}
}
switch val := v.Value.(type) {
case []int:
return val
case []any:
var ret []int
for _, v := range val {
switch v := v.(type) {
case int:
ret = append(ret, v)
case int64:
ret = append(ret, int(v))
case string:
i, err := strconv.Atoi(v)
if err != nil {
continue
}
ret = append(ret, i)
case float32:
ret = append(ret, int(v))
case float64:
ret = append(ret, int(v))
case nil:
continue
default:
continue
}
}
return ret
default:
return nil
}
}