118 lines
2.0 KiB
Go
118 lines
2.0 KiB
Go
package expr
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
invalidPathErr = fmt.Errorf("invalid path format")
|
|
)
|
|
|
|
func PathBase(path string) string {
|
|
return strings.Split(path, ".")[0]
|
|
}
|
|
|
|
func Assign(base TypedValue, path string, val TypedValue) (err error) {
|
|
pp := Path(path)
|
|
err = pp.Next()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if !pp.More() {
|
|
panic("setting value with empty path")
|
|
}
|
|
|
|
var (
|
|
key = ""
|
|
)
|
|
|
|
// descend lower by the path but
|
|
// stop before the last part of the path
|
|
|
|
for !pp.IsLast() {
|
|
switch s := base.(type) {
|
|
case DeepFieldAssigner:
|
|
return s.AssignFieldValue(pp, val)
|
|
|
|
case FieldSelector:
|
|
key = pp.Get()
|
|
err = pp.Next()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if base, err = s.Select(key); err != nil {
|
|
return err
|
|
}
|
|
|
|
default:
|
|
return fmt.Errorf("cannot set value on %s with path '%s'", base.Type(), path)
|
|
|
|
}
|
|
}
|
|
|
|
key = pp.Get()
|
|
|
|
// try with field setter first
|
|
// if not a FieldSetter it has to be a Selector
|
|
// that returns TypedValue that we can set
|
|
switch setter := base.(type) {
|
|
case DeepFieldAssigner:
|
|
return setter.AssignFieldValue(pp, val)
|
|
|
|
case FieldAssigner:
|
|
return setter.AssignFieldValue(key, val)
|
|
|
|
case FieldSelector:
|
|
if base, err = setter.Select(key); err != nil {
|
|
return err
|
|
}
|
|
|
|
return base.Assign(val)
|
|
|
|
default:
|
|
return fmt.Errorf("%T does not support value assigning with '%s'", base, path)
|
|
}
|
|
|
|
}
|
|
|
|
func Select(base TypedValue, path string) (out TypedValue, err error) {
|
|
pp := Path(path)
|
|
err = pp.Next()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if !pp.More() {
|
|
panic("setting value with empty path")
|
|
}
|
|
|
|
var (
|
|
failure = fmt.Errorf("cannot get value from %s with path '%s'", base.Type(), path)
|
|
key string
|
|
)
|
|
|
|
// descend lower by the path but
|
|
// stop before the last part of the path
|
|
for pp.More() {
|
|
s, is := base.(FieldSelector)
|
|
if !is {
|
|
return nil, failure
|
|
}
|
|
|
|
key = pp.Get()
|
|
err = pp.Next()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if base, err = s.Select(key); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return base, nil
|
|
}
|