Skip to content

Commit

Permalink
feat: decouple function caller from interpreter
Browse files Browse the repository at this point in the history
Signed-off-by: Charles-Edouard Brétéché <[email protected]>
  • Loading branch information
eddycharly committed Nov 22, 2023
1 parent aa8d53e commit 6b7caef
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 72 deletions.
7 changes: 7 additions & 0 deletions jp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package jmespath
import (
"github.com/jmespath-community/go-jmespath/pkg/api"
"github.com/jmespath-community/go-jmespath/pkg/functions"
"github.com/jmespath-community/go-jmespath/pkg/interpreter"
"github.com/jmespath-community/go-jmespath/pkg/parsing"
)

Expand All @@ -16,6 +17,12 @@ var (
Search = api.Search
)

// interpreter types

type Option = interpreter.Option

var WithFunctionCaller = interpreter.WithFunctionCaller

// parsing types

type SyntaxError = parsing.SyntaxError
Expand Down
34 changes: 14 additions & 20 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,59 @@ package api
import (
"strconv"

"github.com/jmespath-community/go-jmespath/pkg/functions"
"github.com/jmespath-community/go-jmespath/pkg/interpreter"
"github.com/jmespath-community/go-jmespath/pkg/parsing"
)

// JMESPath is the representation of a compiled JMES path query. A JMESPath is
// safe for concurrent use by multiple goroutines.
type JMESPath interface {
Search(interface{}) (interface{}, error)
Search(interface{}, ...interpreter.Option) (interface{}, error)
}

type jmesPath struct {
node parsing.ASTNode
caller interpreter.FunctionCaller
node parsing.ASTNode
}

func newJMESPath(node parsing.ASTNode, funcs ...functions.FunctionEntry) JMESPath {
func newJMESPath(node parsing.ASTNode) JMESPath {
return jmesPath{
node: node,
caller: interpreter.NewFunctionCaller(funcs...),
node: node,
}
}

// Compile parses a JMESPath expression and returns, if successful, a JMESPath
// object that can be used to match against data.
func Compile(expression string, funcs ...functions.FunctionEntry) (JMESPath, error) {
func Compile(expression string) (JMESPath, error) {
parser := parsing.NewParser()
ast, err := parser.Parse(expression)
if err != nil {
return nil, err
}
var f []functions.FunctionEntry
f = append(f, functions.GetDefaultFunctions()...)
f = append(f, funcs...)
return newJMESPath(ast, f...), nil
return newJMESPath(ast), nil
}

// MustCompile is like Compile but panics if the expression cannot be parsed.
// It simplifies safe initialization of global variables holding compiled
// JMESPaths.
func MustCompile(expression string, funcs ...functions.FunctionEntry) JMESPath {
jmespath, err := Compile(expression, funcs...)
func MustCompile(expression string) JMESPath {
jmespath, err := Compile(expression)
if err != nil {
panic(`jmespath: Compile(` + strconv.Quote(expression) + `): ` + err.Error())
}
return jmespath
}

// Search evaluates a JMESPath expression against input data and returns the result.
func (jp jmesPath) Search(data interface{}) (interface{}, error) {
intr := interpreter.NewInterpreter(data, jp.caller, nil)
return intr.Execute(jp.node, data)
func (jp jmesPath) Search(data interface{}, opts ...interpreter.Option) (interface{}, error) {
intr := interpreter.NewInterpreter(data, nil)
return intr.Execute(jp.node, data, opts...)
}

// Search evaluates a JMESPath expression against input data and returns the result.
func Search(expression string, data interface{}, funcs ...functions.FunctionEntry) (interface{}, error) {
compiled, err := Compile(expression, funcs...)
func Search(expression string, data interface{}, opts ...interpreter.Option) (interface{}, error) {
compiled, err := Compile(expression)
if err != nil {
return nil, err
}
return compiled.Search(data)
return compiled.Search(data, opts...)
}
11 changes: 10 additions & 1 deletion pkg/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/jmespath-community/go-jmespath/pkg/functions"
"github.com/jmespath-community/go-jmespath/pkg/interpreter"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -142,7 +143,15 @@ func TestSearch(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
got, err := Search(tt.args.expression, tt.args.data, tt.args.funcs...)
var opts []interpreter.Option
if len(tt.args.funcs) != 0 {
var f []functions.FunctionEntry
f = append(f, functions.GetDefaultFunctions()...)
f = append(f, tt.args.funcs...)
caller := interpreter.NewFunctionCaller(f...)
opts = append(opts, interpreter.WithFunctionCaller(caller))
}
got, err := Search(tt.args.expression, tt.args.data, opts...)
assert.Equal(tt.wantErr, err != nil)
assert.Equal(tt.want, got)
})
Expand Down
Loading

0 comments on commit 6b7caef

Please sign in to comment.