Skip to content

Commit

Permalink
refactor sub
Browse files Browse the repository at this point in the history
  • Loading branch information
ktong committed Nov 21, 2024
1 parent 3138d90 commit 76d5ea9
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 36 deletions.
21 changes: 12 additions & 9 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (c *Config) Unmarshal(path string, target any) error {
}
c.nocopy.Check()

value := c.providers.value()
value := c.providers.sub(c.splitPath(path))
if value == nil { // To support zero Config
return nil
}
Expand All @@ -133,7 +133,7 @@ func (c *Config) Unmarshal(path string, target any) error {
if converter == nil { // To support zero Config
converter = defaultConverter
}
if err := converter.Convert(c.sub(value, path), target); err != nil {
if err := converter.Convert(value, target); err != nil {
return fmt.Errorf("decode: %w", err)
}

Expand All @@ -148,12 +148,15 @@ func (c *Config) log(ctx context.Context, level slog.Level, message string, attr
logger.LogAttrs(ctx, level, message, attrs...)
}

func (c *Config) sub(values map[string]any, path string) any {
func (c *Config) splitPath(path string) []string {
if path == "" {
return nil
}
if !c.caseSensitive {
path = defaultKeyMap(path)
}

return maps.Sub(values, path, c.delim())
return strings.Split(path, c.delim())
}

func (c *Config) delim() string {
Expand All @@ -179,13 +182,13 @@ func (c *Config) Explain(path string) string {
}
c.nocopy.Check()

value := c.providers.value()
value := c.providers.sub(c.splitPath(path))
if value == nil { // To support zero Config
return path + " has no configuration.\n\n"
}

explanation := &strings.Builder{}
c.explain(explanation, path, c.sub(value, path))
c.explain(explanation, path, value)

return explanation.String()
}
Expand All @@ -210,7 +213,7 @@ func (c *Config) explain(explanation *strings.Builder, path string, value any) {
}
var loaders []loaderValue
c.providers.traverse(func(provider *provider) {
if v := c.sub(*provider.values.Load(), path); v != nil {
if v := maps.Sub(*provider.values.Load(), c.splitPath(path)); v != nil {
loaders = append(loaders, loaderValue{provider.loader, v})
}
})
Expand Down Expand Up @@ -282,13 +285,13 @@ func (p *providers) traverse(action func(*provider)) {
}
}

func (p *providers) value() map[string]any {
func (p *providers) sub(path []string) any {
val := p.values.Load()
if val == nil {
return nil
}

return *val
return maps.Sub(*val, path)
}

//nolint:gochecknoglobals
Expand Down
14 changes: 7 additions & 7 deletions internal/maps/sub.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@

package maps

import "strings"
import "slices"

func Sub(values map[string]any, path string, delimiter string) any {
if path == "" {
func Sub(values map[string]any, path []string) any {
path = slices.Compact(path)
if len(path) == 0 {
return values
}

key, path, _ := strings.Cut(path, delimiter)
_, value := Unpack(values[key])
if path == "" {
_, value := Unpack(values[path[0]])
if len(path) == 1 {
return value
}

if mp, ok := value.(map[string]any); ok {
return Sub(mp, path, delimiter)
return Sub(mp, path[1:])
}

return nil
Expand Down
22 changes: 10 additions & 12 deletions internal/maps/sub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,67 +16,65 @@ func TestSub(t *testing.T) {
testcases := []struct {
description string
values map[string]any
path string
path []string
expected any
}{
{
description: "nil values",
values: nil,
path: "a.b",
path: []string{"a", "b"},
expected: nil,
},
{
description: "empty values",
values: map[string]any{},
path: "a.b",
path: []string{"a", "b"},
expected: nil,
},
{
description: "empty keys",
values: map[string]any{"a": 1},
path: "",
expected: map[string]any{"a": 1},
},
{
description: "blank keys",
values: map[string]any{"a": 1},
path: "",
expected: map[string]any{"a": 1},
},
{
description: "lower case keys",
values: map[string]any{"a": 1, "b": 2},
path: "a",
path: []string{"a"},
expected: 1,
},
{
description: "upper case keys",
values: map[string]any{"A": 1},
path: "A",
path: []string{"A"},
expected: 1,
},
{
description: "keyvalue",
values: map[string]any{"a": maps.Pack("A", 1)},
path: "a",
path: []string{"a"},
expected: 1,
},
{
description: "value not exist",
values: map[string]any{"a": 1},
path: "a.b",
path: []string{"a", "b"},
expected: nil,
},
{
description: "nest map",
values: map[string]any{"a": map[string]any{"x": 1, "y": 2}},
path: "a.y",
path: []string{"a", "y"},
expected: 2,
},
{
description: "non-map value",
values: map[string]any{"a": map[string]any{"x": 1}},
path: "x.y",
path: []string{"x", "y"},
expected: nil,
},
}
Expand All @@ -85,7 +83,7 @@ func TestSub(t *testing.T) {
t.Run(testcase.description, func(t *testing.T) {
t.Parallel()

actual := maps.Sub(testcase.values, testcase.path, ".")
actual := maps.Sub(testcase.values, testcase.path)
assert.Equal(t, testcase.expected, actual)
})
}
Expand Down
8 changes: 1 addition & 7 deletions provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package konf

import (
"context"
"strings"
)

// Loader is the interface that wraps the Load method.
Expand Down Expand Up @@ -41,10 +40,5 @@ func (c *Config) Exists(path []string) bool {
}
c.nocopy.Check()

value := c.providers.value()
if value == nil {
return false // To support zero Config
}

return c.sub(value, strings.Join(path, c.delim())) != nil
return c.providers.sub(path) != nil
}
6 changes: 5 additions & 1 deletion watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"reflect"
"sync"
"time"

"github.com/nil-go/konf/internal/maps"
)

// Watch watches and updates configuration when it changes.
Expand Down Expand Up @@ -91,7 +93,9 @@ func (c *Config) Watch(ctx context.Context) error { //nolint:cyclop,funlen,gocog
oldValues := *provider.values.Swap(&values)
onChangesChannel <- c.onChanges.get(
func(path string) bool {
return !reflect.DeepEqual(c.sub(oldValues, path), c.sub(values, path))
paths := c.splitPath(path)

return !reflect.DeepEqual(maps.Sub(oldValues, paths), maps.Sub(values, paths))
},
)

Expand Down

0 comments on commit 76d5ea9

Please sign in to comment.