Skip to content

Commit

Permalink
✨ feat: add new read methods for get config value
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Feb 11, 2023
1 parent 9993ffa commit 884a968
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 33 deletions.
7 changes: 4 additions & 3 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var jsonStr = `{
"name": "app",
"debug": true,
"baseKey": "value",
"tagsStr": "php,go",
"age": 123,
"envKey": "${SHELL}",
"envKey1": "${NotExist|defValue}",
Expand Down Expand Up @@ -245,7 +246,7 @@ func TestJSONDriver(t *testing.T) {
is.Eq(1, c.Int("key"))

c = NewWith("test", func(c *Config) {
err = c.LoadData(map[string]interface{}{"key1": 2})
err = c.LoadData(map[string]any{"key1": 2})
is.NoErr(err)
})
is.Eq(2, c.Int("key1"))
Expand Down Expand Up @@ -342,7 +343,7 @@ func TestDelimiter(t *testing.T) {
c.WithOptions(Delimiter(':'))
is.Eq(byte(':'), c.Options().Delimiter)

err := c.LoadData(map[string]interface{}{
err := c.LoadData(map[string]any{
"top0": 1,
"top1": map[string]int{"sub0": 2},
})
Expand All @@ -354,7 +355,7 @@ func TestDelimiter(t *testing.T) {
c = NewWithOptions("test", Delimiter(0))
is.Eq(byte(0), c.Options().Delimiter)

err = c.LoadData(map[string]interface{}{
err = c.LoadData(map[string]any{
"top0": 1,
"top1": map[string]int{"sub0": 2},
})
Expand Down
8 changes: 7 additions & 1 deletion export.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ func MapOnExists(key string, dst any) error {
}

// MapOnExists mapping data to the dst structure only on key exists.
//
// - Support ParseEnv on mapping
// - Support ParseDefault on mapping
func (c *Config) MapOnExists(key string, dst any) error {
err := c.Structure(key, dst)
if err != nil && err == ErrNotFound {
Expand All @@ -66,12 +69,15 @@ func (c *Config) MapOnExists(key string, dst any) error {

// Structure get config data and binding to the dst structure.
//
// - Support ParseEnv on mapping
// - Support ParseDefault on mapping
//
// Usage:
//
// dbInfo := Db{}
// config.Structure("db", &dbInfo)
func (c *Config) Structure(key string, dst any) error {
var data interface{}
var data any
// binding all data
if key == "" {
data = c.data
Expand Down
49 changes: 39 additions & 10 deletions export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/gookit/goutil/dump"
"github.com/gookit/goutil/jsonutil"
"github.com/gookit/goutil/testutil/assert"
)

Expand Down Expand Up @@ -115,7 +116,7 @@ func TestConfig_Structure(t *testing.T) {

// custom data
cfg = New("test")
err = cfg.LoadData(map[string]interface{}{
err = cfg.LoadData(map[string]any{
"key": "val",
"age": 120,
"tags": []int{12, 34},
Expand Down Expand Up @@ -151,14 +152,12 @@ func TestMapStruct_embedded_struct_squash_false(t *testing.T) {
})
assert.False(t, loader.Options().DecoderConfig.Squash)

err := loader.LoadStrings(JSON, `
{
err := loader.LoadStrings(JSON, `{
"c": "12",
"test1": {
"b": "34"
}
}
`)
}`)
assert.NoErr(t, err)
dump.Println(loader.Data())
assert.Eq(t, 12, loader.Int("c"))
Expand Down Expand Up @@ -187,6 +186,20 @@ func TestMapStruct_embedded_struct_squash_false(t *testing.T) {
assert.NoErr(t, err)
dump.Println(cfg1)
assert.Eq(t, 34, cfg1.Test1.B)

loader.SetData(map[string]any{
"c": 120,
"b": 340,
})
dump.Println(loader.Data())

cfg2 := &Test3{}
err = loader.BindStruct("", cfg2)

cfg3 := &Test3{}
_ = jsonutil.DecodeString(`{"c": 12, "b": 34}`, cfg3)

dump.Println(cfg2, cfg3)
}

func TestMapStruct_embedded_struct_squash_true(t *testing.T) {
Expand All @@ -196,14 +209,12 @@ func TestMapStruct_embedded_struct_squash_true(t *testing.T) {
})
assert.True(t, loader.Options().DecoderConfig.Squash)

err := loader.LoadStrings(JSON, `
{
err := loader.LoadStrings(JSON, `{
"c": "12",
"test1": {
"b": "34"
}
}
`)
}`)
assert.NoErr(t, err)
dump.Println(loader.Data())
assert.Eq(t, 12, loader.Int("c"))
Expand All @@ -212,6 +223,8 @@ func TestMapStruct_embedded_struct_squash_true(t *testing.T) {
type Test1 struct {
B int `json:"b"`
}

// use value - will not set ok
type Test2 struct {
Test1
// Test1 `json:",squash"`
Expand All @@ -224,6 +237,7 @@ func TestMapStruct_embedded_struct_squash_true(t *testing.T) {
dump.Println(cfg)
assert.Eq(t, 0, cfg.Test1.B)

// use pointer
type Test3 struct {
*Test1
C int `json:"c"`
Expand All @@ -232,7 +246,22 @@ func TestMapStruct_embedded_struct_squash_true(t *testing.T) {
err = loader.MapStruct("", cfg1)
assert.NoErr(t, err)
dump.Println(cfg1)
assert.Eq(t, 34, cfg1.B)
assert.Eq(t, 34, cfg1.Test1.B)

loader.SetData(map[string]any{
"c": 120,
"b": 340,
})
dump.Println(loader.Data())

cfg2 := &Test3{}
err = loader.BindStruct("", cfg2)

cfg3 := &Test3{}
_ = jsonutil.DecodeString(`{"c": 12, "b": 34}`, cfg3)

dump.Println(cfg2, cfg3)
}

func TestMapOnExists(t *testing.T) {
Expand Down Expand Up @@ -294,7 +323,7 @@ func TestConfig_BindStruct_default(t *testing.T) {
}

cfg := NewWithOptions("test", ParseEnv, ParseDefault)
// cfg.SetData(map[string]interface{}{
// cfg.SetData(map[string]any{
// "env": "prod",
// "debug": "true",
// })
Expand Down
54 changes: 46 additions & 8 deletions read.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,32 +90,44 @@ func (c *Config) Exists(key string, findByPath ...bool) (ok bool) {
*************************************************************/

// Data return all config data
func Data() map[string]interface{} { return dc.Data() }
func Data() map[string]any { return dc.Data() }

// Data get all config data
func (c *Config) Data() map[string]interface{} {
func (c *Config) Data() map[string]any {
return c.data
}

// Keys return all config data
func Keys() []string { return dc.Keys() }

// Keys get all config data
func (c *Config) Keys() []string {
keys := make([]string, 0, len(c.data))
for key := range c.data {
keys = append(keys, key)
}
return keys
}

// Get config value by key string, support get sub-value by key path(eg. 'map.key'),
//
// - ok is true, find value from config
// - ok is false, not found or error
func Get(key string, findByPath ...bool) interface{} { return dc.Get(key, findByPath...) }
func Get(key string, findByPath ...bool) any { return dc.Get(key, findByPath...) }

// Get config value by key
func (c *Config) Get(key string, findByPath ...bool) interface{} {
func (c *Config) Get(key string, findByPath ...bool) any {
val, _ := c.GetValue(key, findByPath...)
return val
}

// GetValue get value by given key string.
func GetValue(key string, findByPath ...bool) (interface{}, bool) {
func GetValue(key string, findByPath ...bool) (any, bool) {
return dc.GetValue(key, findByPath...)
}

// GetValue get value by given key string.
func (c *Config) GetValue(key string, findByPath ...bool) (value interface{}, ok bool) {
func (c *Config) GetValue(key string, findByPath ...bool) (value any, ok bool) {
sep := c.opts.Delimiter
if key = formatKey(key, string(sep)); key == "" {
c.addError(ErrKeyIsEmpty)
Expand Down Expand Up @@ -235,6 +247,18 @@ func (c *Config) String(key string, defVal ...string) string {
return value
}

// MustString get a string by key, will panic on empty or not exists
func MustString(key string) string { return dc.MustString(key) }

// MustString get a string by key, will panic on empty or not exists
func (c *Config) MustString(key string) string {
value, ok := c.getString(key)
if !ok {
panic("config: string value not found, key: " + key)
}
return value
}

func (c *Config) getString(key string) (value string, ok bool) {
// find from cache
if c.opts.EnableCache && len(c.strCache) > 0 {
Expand All @@ -257,8 +281,11 @@ func (c *Config) getString(key string) (value string, ok bool) {
value = envutil.ParseEnvValue(value)
}
default:
// value = fmt.Sprintf("%v", val)
value, _ = strutil.AnyToString(val, false)
var err error
value, err = strutil.AnyToString(val, false)
if err != nil {
return "", false
}
}

// add cache
Expand Down Expand Up @@ -520,6 +547,17 @@ func (c *Config) Strings(key string) (arr []string) {
return
}

// StringsBySplit get []string by split a string value.
func StringsBySplit(key, sep string) []string { return dc.StringsBySplit(key, sep) }

// StringsBySplit get []string by split a string value.
func (c *Config) StringsBySplit(key, sep string) (ss []string) {
if str, ok := c.getString(key); ok {
ss = strutil.Split(str, sep)
}
return
}

// StringMap get config data as a map[string]string
func StringMap(key string) map[string]string { return dc.StringMap(key) }

Expand Down
27 changes: 16 additions & 11 deletions read_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestConfig_GetValue(t *testing.T) {
is.False(Exists("arr1.notExist"))

// load data for tests
err = c.LoadData(map[string]interface{}{
err = c.LoadData(map[string]any{
"setStrMap": map[string]string{
"k": "v",
},
Expand Down Expand Up @@ -105,6 +105,8 @@ func TestGet(t *testing.T) {
val = Get("name")
is.Eq("app", val)

is.Eq([]string{"php", "go"}, StringsBySplit("tagStr", ","))

// get string array
arr := Strings("notExist")
is.Empty(arr)
Expand Down Expand Up @@ -175,31 +177,31 @@ func TestGet(t *testing.T) {

// like load from yaml content
// c = New("test")
err = c.LoadData(map[string]interface{}{
err = c.LoadData(map[string]any{
"newIArr": []int{2, 3},
"newSArr": []string{"a", "b"},
"newIArr1": []interface{}{12, 23},
"newIArr2": []interface{}{12, "abc"},
"newIArr1": []any{12, 23},
"newIArr2": []any{12, "abc"},
"invalidMap": map[string]int{"k": 1},
"yMap": map[interface{}]interface{}{
"yMap": map[any]any{
"k0": "v0",
"k1": 23,
},
"yMap1": map[interface{}]interface{}{
"yMap1": map[any]any{
"k": "v",
"k1": 23,
"k2": []interface{}{23, 45},
"k2": []any{23, 45},
},
"yMap10": map[string]interface{}{
"yMap10": map[string]any{
"k": "v",
"k1": 23,
"k2": []interface{}{23, 45},
"k2": []any{23, 45},
},
"yMap2": map[interface{}]interface{}{
"yMap2": map[any]any{
"k": 2,
"k1": 23,
},
"yArr": []interface{}{23, 45, "val", map[string]interface{}{"k4": "v4"}},
"yArr": []any{23, 45, "val", map[string]any{"k4": "v4"}},
})
is.Nil(err)

Expand Down Expand Up @@ -348,6 +350,9 @@ func TestString(t *testing.T) {

str := String("notExists")
is.Eq("", str)
is.Panics(func() {
MustString("notExists")
})

str = String("notExists", "defVal")
is.Eq("defVal", str)
Expand Down

0 comments on commit 884a968

Please sign in to comment.