Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
148 lines
2.9 KiB
Go
148 lines
2.9 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) {
|
|
if _, ok := base.(FlatStore); ok {
|
|
return assignFlat(base, path, val)
|
|
}
|
|
return assignPath(base, path, val)
|
|
}
|
|
|
|
func assignFlat(base TypedValue, key string, val TypedValue) error {
|
|
switch fa := base.(type) {
|
|
case FieldAssigner:
|
|
return fa.AssignFieldValue(key, val)
|
|
case DeepFieldAssigner:
|
|
return fa.AssignFieldValue(&flatPath{key: key}, val)
|
|
default:
|
|
return fmt.Errorf("cannot set on unexpected type: %T", base)
|
|
}
|
|
}
|
|
|
|
// flatPath is a single-segment Pather for flat key assignment — no path splitting.
|
|
type flatPath struct {
|
|
key string
|
|
done bool
|
|
}
|
|
|
|
func (p *flatPath) String() string { return p.key }
|
|
func (p *flatPath) More() bool { return !p.done }
|
|
func (p *flatPath) IsLast() bool { return true }
|
|
func (p *flatPath) Get() string { return p.key }
|
|
func (p *flatPath) Rest() string { return "" }
|
|
func (p *flatPath) Next() error { p.done = true; return nil }
|
|
|
|
func assignPath(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
|
|
}
|