Skip to content

Commit 590d6e8

Browse files
authored
chore: support $eval (#9)
* chore: support * chore: bump go version * chore: replace reflect.PtrTo with PointerTo * chore: add tests for $eval
1 parent 417b49a commit 590d6e8

File tree

9 files changed

+67
-8
lines changed

9 files changed

+67
-8
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ jobs:
44
test:
55
strategy:
66
matrix:
7-
go-version: [1.20.3]
7+
go-version: [1.22.6]
88
os: [ubuntu-latest]
99
runs-on: ${{ matrix.os }}
1010
steps:

callable.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func newGoCallableParam(typ reflect.Type) goCallableParam {
4848
t: typ,
4949
}
5050

51-
isOpt := reflect.PtrTo(typ).Implements(jtypes.TypeOptional)
51+
isOpt := reflect.PointerTo(typ).Implements(jtypes.TypeOptional)
5252
if isOpt {
5353
o := reflect.New(typ).Interface().(jtypes.Optional)
5454
p := newGoCallableParam(o.Type())
@@ -294,7 +294,7 @@ func (c *goCallable) validateArgTypes(argv []reflect.Value) ([]reflect.Value, er
294294
// This is fine for most types but we need to restore
295295
// pointer type Callables.
296296
if v.Kind() == reflect.Struct &&
297-
reflect.PtrTo(v.Type()).Implements(jtypes.TypeCallable) {
297+
reflect.PointerTo(v.Type()).Implements(jtypes.TypeCallable) {
298298
if v.CanAddr() {
299299
v = v.Addr()
300300
}

env.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ var standardFunctions = map[string]Extension{
179179
UndefinedHandler: defaultUndefinedHandler,
180180
EvalContextHandler: defaultContextHandler,
181181
},
182+
"eval": {
183+
Func: DoEval,
184+
UndefinedHandler: nil,
185+
EvalContextHandler: func([]reflect.Value) bool { return true },
186+
},
182187

183188
// Number functions
184189

eval.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,7 @@ func (s sequence) valueAt(idx int) reflect.Value {
13611361

13621362
var (
13631363
typeSequence = reflect.TypeOf((*sequence)(nil)).Elem()
1364-
typeSequencePtr = reflect.PtrTo(typeSequence)
1364+
typeSequencePtr = reflect.PointerTo(typeSequence)
13651365
)
13661366

13671367
func asSequence(v reflect.Value) (*sequence, bool) {

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/stepzen-dev/jsonata-go
22

3-
go 1.20
3+
go 1.22
44

55
require (
66
github.com/stretchr/testify v1.8.4

jlib/string_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestMain(m *testing.M) {
2828
os.Exit(1)
2929
}
3030

31-
if !reflect.PtrTo(typeMatchCallable).Implements(typeCallable) {
31+
if !reflect.PointerTo(typeMatchCallable).Implements(typeCallable) {
3232
fmt.Fprintln(os.Stderr, "*matchCallable is not a Callable. Aborting...")
3333
os.Exit(1)
3434
}

jsonata.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,3 +381,29 @@ func isLetter(r rune) bool {
381381
func isDigit(r rune) bool {
382382
return (r >= '0' && r <= '9') || unicode.IsDigit(r)
383383
}
384+
385+
type (
386+
// need this indirection to avoid an initialization cycle with DoEval.
387+
evali interface {
388+
doEval(reflect.Value, string) (any, error)
389+
}
390+
evalc struct{}
391+
)
392+
393+
// DoEval supports $eval(script, [context])
394+
func DoEval(ctx reflect.Value, s string, sub jtypes.OptionalValue) (any, error) {
395+
// replace the context if the optional second argument is provided.
396+
if sub.IsSet() {
397+
ctx = sub.Value
398+
}
399+
var e evali = evalc{}
400+
return e.doEval(ctx, s)
401+
}
402+
403+
func (evalc) doEval(ctx reflect.Value, s string) (any, error) {
404+
expr, err := Compile(s)
405+
if err != nil {
406+
return nil, err
407+
}
408+
return expr.Eval(ctx)
409+
}

jsonata_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8168,3 +8168,31 @@ func TestFuncType(t *testing.T) {
81688168
},
81698169
})
81708170
}
8171+
8172+
func TestFuncEval(t *testing.T) {
8173+
runTestCases(t, testdata.account, []*testCase{
8174+
{
8175+
Expression: `$eval("[1,2,3]")`,
8176+
Output: []any{1.0, 2.0, 3.0},
8177+
},
8178+
{
8179+
Expression: `$eval("10 + 32")`,
8180+
Output: 42.0,
8181+
},
8182+
{
8183+
// ensure default context is picked up
8184+
Expression: `$eval("Account.Order.OrderID")`,
8185+
Output: []any{"order103", "order104"},
8186+
},
8187+
{
8188+
// ensure context can be overridden
8189+
Expression: `$eval("Order.OrderID", Account)`,
8190+
Output: []any{"order103", "order104"},
8191+
},
8192+
{
8193+
// ensure context can be overridden
8194+
Expression: `$eval("a+b", {"a":8.4, "b": 33.6})`,
8195+
Output: 42.0,
8196+
},
8197+
})
8198+
}

jtypes/funcs.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func IsNumber(v reflect.Value) bool {
4444
func IsCallable(v reflect.Value) bool {
4545
v = Resolve(v)
4646
return v.IsValid() &&
47-
(v.Type().Implements(TypeCallable) || reflect.PtrTo(v.Type()).Implements(TypeCallable))
47+
(v.Type().Implements(TypeCallable) || reflect.PointerTo(v.Type()).Implements(TypeCallable))
4848
}
4949

5050
// IsArray (golint)
@@ -128,7 +128,7 @@ func AsCallable(v reflect.Value) (Callable, bool) {
128128
return v.Interface().(Callable), true
129129
}
130130

131-
if v.IsValid() && reflect.PtrTo(v.Type()).Implements(TypeCallable) && v.CanAddr() && v.Addr().CanInterface() {
131+
if v.IsValid() && reflect.PointerTo(v.Type()).Implements(TypeCallable) && v.CanAddr() && v.Addr().CanInterface() {
132132
return v.Addr().Interface().(Callable), true
133133
}
134134

0 commit comments

Comments
 (0)