3
0

Add support for expression evaluation

This commit is contained in:
Tomaž Jerman 2020-03-24 12:32:06 +01:00
parent 8e31d43c29
commit d034197092
4 changed files with 68 additions and 3 deletions

2
go.mod
View File

@ -8,7 +8,7 @@ require (
github.com/766b/chi-prometheus v0.0.0-20180509160047-46ac2b31aa30
github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d
github.com/Masterminds/squirrel v1.1.1-0.20191017225151-12f2162c8d8d
github.com/PaesslerAG/gval v1.0.1 // indirect
github.com/PaesslerAG/gval v1.0.1
github.com/PaesslerAG/jsonpath v0.1.1 // indirect
github.com/SentimensRG/ctx v0.0.0-20180729130232-0bfd988c655d
github.com/crusttech/go-oidc v0.0.0-20180918092017-982855dad3e1

View File

@ -171,3 +171,20 @@ The following value mapping maps `sys_status` field's values; the left one into
}
}
----
The system also provides support for arbitrary mathematical expressions.
If you wish to perform an expression, prefix the mapped value with `=EVL=`; for example `=EVL=numFmt(cell, \"%.0f\")`.
Variables:
* current cell -- `cell`.
The following example will remove the decimal point from every `sys_rating` in the given source.
[source,json]
----
{
"sys_rating": {
"*": "=EVL=numFmt(cell, \"%.0f\")"
}
}
----

25
pkg/migrate/types/eval.go Normal file
View File

@ -0,0 +1,25 @@
package types
import (
"fmt"
"strconv"
"github.com/PaesslerAG/gval"
)
// generates a simple gval language to be used within the migration
func exprs() gval.Language {
return gval.NewLanguage(
gval.JSON(),
gval.Arithmetic(),
gval.Function("numFmt", func(number, format string) (string, error) {
nn, err := strconv.ParseFloat(number, 64)
if err != nil {
return "", err
}
return fmt.Sprintf(format, nn), nil
}),
)
}

View File

@ -1,6 +1,7 @@
package types
import (
"context"
"encoding/csv"
"errors"
"fmt"
@ -72,6 +73,10 @@ type (
}
)
const (
evalPrefix = "=EVL="
)
// helper, to determine if the two nodes are equal
func (n *Node) Compare(to *Node) bool {
return n.Name == to.Name && n.spliced == to.spliced
@ -392,6 +397,8 @@ func importNodeSource(n *Node, users map[string]uint64, repo repository.RecordRe
return r
}
lng := exprs()
for {
looper:
record, err := n.Reader.Read()
@ -526,10 +533,26 @@ func importNodeSource(n *Node, users map[string]uint64, repo repository.RecordRe
for i, v := range values {
if fmp, ok := n.ValueMap[h]; ok {
nvl := ""
if mpv, ok := fmp[v]; ok {
v = mpv
nvl = mpv
} else if mpv, ok := fmp["*"]; ok {
v = mpv
nvl = mpv
}
if nvl != "" && strings.HasPrefix(nvl, evalPrefix) {
opp := nvl[len(evalPrefix):len(nvl)]
ev, err := lng.NewEvaluable(opp)
if err != nil {
return nil, err
}
v, err = ev.EvalString(context.Background(), map[string]interface{}{"cell": v})
if err != nil {
return nil, err
}
} else if nvl != "" {
v = nvl
}
}