diff --git a/codec/yaml.go b/codec/yaml.go index 7cfd793..d18d6c8 100644 --- a/codec/yaml.go +++ b/codec/yaml.go @@ -5,8 +5,9 @@ import ( "fmt" "reflect" - "github.com/lukasjarosch/skipper/data" "gopkg.in/yaml.v3" + + "github.com/lukasjarosch/skipper/data" ) type YamlCodec struct{} @@ -15,8 +16,8 @@ func NewYamlCodec() YamlCodec { return YamlCodec{} } -func (codec YamlCodec) Unmarshal(in []byte) (data.Map, error) { - var out data.Map +func (codec YamlCodec) Unmarshal(in []byte) (map[string]interface{}, error) { + var out map[string]interface{} err := codec.UnmarshalTarget(in, &out) if err != nil { return nil, err @@ -48,13 +49,13 @@ func (codec YamlCodec) UnmarshalPath(in []byte, path data.Path, target interface return fmt.Errorf("cannot decode with path: target must be a pointer") } - var out data.Map + var out map[string]interface{} err := yaml.Unmarshal(in, &out) if err != nil { return err } - tree, err := out.Get(path) + tree, err := data.Get(out, path.String()) if err != nil { return err } diff --git a/data/container.go b/data/container.go index 0929304..bbb0f8e 100644 --- a/data/container.go +++ b/data/container.go @@ -18,7 +18,7 @@ var ( // The data can have only one key, which must match the container name. // So a container named 'foo' must have data like 'map[string]interface{"foo": ....}' type Container struct { - name string + Name string data map[string]interface{} } @@ -66,7 +66,7 @@ func NewContainer(name string, data map[string]interface{}) (*Container, error) } c := &Container{ - name: name, + Name: name, data: data, } @@ -88,8 +88,8 @@ func (container *Container) Get(path Path) (Value, error) { } // make sure the path is absolute and contains the container name as first segment (aka root key) - if path.First() != container.name { - path = path.Prepend(container.name) + if path.First() != container.Name { + path = path.Prepend(container.Name) } ret, err := DeepGet(container.data, []string(path)) @@ -121,8 +121,8 @@ func (container *Container) Set(path Path, value interface{}) error { } // ensure path is absolute - if path.First() != container.name { - path = path.Prepend(container.name) + if path.First() != container.Name { + path = path.Prepend(container.Name) } ret, err := DeepSet(container.data, path, value) diff --git a/data/data.go b/data/data.go index 2277899..dca3e61 100644 --- a/data/data.go +++ b/data/data.go @@ -12,7 +12,7 @@ var ( ErrInvalidValue = fmt.Errorf("invalid value") ErrUnsupportedDataType = fmt.Errorf("unsupported data type") ErrNegativeIndex = fmt.Errorf("negative index") - ErrTypeChange = fmt.Errorf("changing types is not supported") + ErrTypeChange = fmt.Errorf("changing data-types is not supported") ) type WalkFunc func(path Path, data interface{}, isLeaf bool) error @@ -28,7 +28,7 @@ func walk(parent interface{}, path Path, walkFn WalkFunc) error { return nil } - var parentValue = reflect.ValueOf(parent) + parentValue := reflect.ValueOf(parent) switch parentValue.Kind() { case reflect.Map: @@ -108,14 +108,14 @@ func DeepGet(data interface{}, path Path) (interface{}, error) { current := ResolveValue(data) for i := 0; i < len(path); i++ { - var pathSegment = path[i] - var curValue = reflect.ValueOf(current) + pathSegment := path[i] + curValue := reflect.ValueOf(current) if !curValue.IsValid() { return nil, ErrInvalidValue } - var curTyp = curValue.Type() + curTyp := curValue.Type() // for pointers and interfaces, get the underlying type switch curValue.Kind() { @@ -308,8 +308,14 @@ func DeepSet(data interface{}, path Path, value interface{}) (interface{}, error // value by evaluating the currentSegment just as above. // But allowing to change scalar types would also mean that // we should allow changing []interface{} to map[string]interface{}. - // Hence we simply don't allow chaning types at the moment. - return nil, ErrTypeChange + // This would introduce even more complexity because there might exist a []interface{1, 2, 3} + // which must then suddenly be mapped to map[string]interface{"0": 1, "1": 2, "2": 3}. + // This will also introduce side-effects which the user most likely does not expect. + // Hence we simply don't allow changing types at the moment. + // + // Additionally, dynamic data-type changes would not work once a user wants to + // use a schema with the data. + return nil, fmt.Errorf("cannot set path segment '%s': %w", path, ErrTypeChange) } } @@ -343,7 +349,7 @@ func Merge(baseData map[string]interface{}, mergeData map[string]interface{}) ma } func Keys(input interface{}) []interface{} { - var keys = make([]interface{}, 0) + keys := make([]interface{}, 0) if input == nil { return keys @@ -370,6 +376,7 @@ type PathSelectorFunc func(data interface{}, path Path, isLeaf bool) bool var SelectAllPaths PathSelectorFunc = func(_ interface{}, path Path, isLeaf bool) bool { return true } + var SelectLeafPaths PathSelectorFunc = func(_ interface{}, path Path, isLeaf bool) bool { if isLeaf { return true diff --git a/data/reflect.go b/data/reflect.go index dd860f6..97641bd 100644 --- a/data/reflect.go +++ b/data/reflect.go @@ -105,7 +105,7 @@ func IsInteger(in interface{}) bool { return false } -// Dectect whether the concrete underlying value of the given input is one or more +// Detect whether the concrete underlying value of the given input is one or more // Kinds of value. func IsKind(in interface{}, kinds ...reflect.Kind) bool { var inT reflect.Type diff --git a/data/value.go b/data/value.go index e63bb90..dc45062 100644 --- a/data/value.go +++ b/data/value.go @@ -5,7 +5,9 @@ import ( "time" ) -// Value represents a generic value that originates fom [Data] +var NilValue = Value{Raw: nil} + +// Value represents a generic value that originates from the underlying data. type Value struct { Raw interface{} }