mirror of
https://github.com/MontFerret/ferret.git
synced 2025-11-25 22:01:39 +02:00
Added support of optional ignoring of errors to function calls (#652)
* Added support of optional ignoring of errors to function calls * Added support of handling of source failure to optional chaining * Updated unit tests
This commit is contained in:
@@ -80,6 +80,21 @@ func TestFunctionNSCall(t *testing.T) {
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("T::FAIL()? should return NONE", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
p, err := c.Compile(`
|
||||
RETURN T::FAIL()?
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out), ShouldEqual, `null`)
|
||||
})
|
||||
|
||||
Convey("Should use keywords", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/MontFerret/ferret/pkg/compiler"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/pkg/errors"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"testing"
|
||||
)
|
||||
@@ -83,6 +84,44 @@ func TestFunctionCall(t *testing.T) {
|
||||
|
||||
So(string(out), ShouldEqual, `[2,4,6,8]`)
|
||||
})
|
||||
|
||||
Convey("Should handle errors when ? is used", t, func() {
|
||||
c := compiler.New()
|
||||
c.RegisterFunction("ERROR", func(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
return values.None, errors.New("test error")
|
||||
})
|
||||
|
||||
p, err := c.Compile(`
|
||||
RETURN ERROR()?
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(string(out), ShouldEqual, `null`)
|
||||
})
|
||||
|
||||
Convey("Should return NONE when error is handled", t, func() {
|
||||
c := compiler.New()
|
||||
c.RegisterFunction("ERROR", func(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
return values.NewString("booo"), errors.New("test error")
|
||||
})
|
||||
|
||||
p, err := c.Compile(`
|
||||
RETURN ERROR()?
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(string(out), ShouldEqual, `null`)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkFunctionCallArg1(b *testing.B) {
|
||||
|
||||
@@ -2,8 +2,10 @@ package compiler_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/MontFerret/ferret/pkg/compiler"
|
||||
"github.com/MontFerret/ferret/pkg/runtime"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"testing"
|
||||
)
|
||||
@@ -71,7 +73,43 @@ func TestLogicalOperators(t *testing.T) {
|
||||
So(string(out), ShouldEqual, `"foo"`)
|
||||
})
|
||||
|
||||
Convey("NONE && true should return null", t, func() {
|
||||
Convey("ERROR()? || 'boo' should return 'boo'", t, func() {
|
||||
c := compiler.New()
|
||||
c.RegisterFunction("ERROR", func(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
return nil, errors.New("test")
|
||||
})
|
||||
|
||||
p, err := c.Compile(`
|
||||
RETURN ERROR()? || 'boo'
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out), ShouldEqual, `"boo"`)
|
||||
})
|
||||
|
||||
Convey("!ERROR()? && TRUE should return false", t, func() {
|
||||
c := compiler.New()
|
||||
c.RegisterFunction("ERROR", func(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
return nil, errors.New("test")
|
||||
})
|
||||
|
||||
p, err := c.Compile(`
|
||||
RETURN !ERROR()? && TRUE
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(string(out), ShouldEqual, `true`)
|
||||
})
|
||||
|
||||
Convey("NONE && true should return null", t, func() {
|
||||
c := compiler.New()
|
||||
|
||||
p, err := c.Compile(`
|
||||
|
||||
@@ -3,6 +3,7 @@ package compiler_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"testing"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/compiler"
|
||||
@@ -495,6 +496,25 @@ RETURN o1.first["second"][o2.prop].fourth["fifth"]["bottom"]
|
||||
|
||||
So(string(out), ShouldEqual, `"bar"`)
|
||||
})
|
||||
|
||||
Convey("When function returns error", func() {
|
||||
c := compiler.New()
|
||||
c.RegisterFunction("ERROR", func(ctx context.Context, args ...core.Value) (core.Value, error) {
|
||||
return nil, core.ErrNotImplemented
|
||||
})
|
||||
|
||||
p, err := c.Compile(`
|
||||
RETURN ERROR()?.foo
|
||||
`)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
out, err := p.Run(context.Background())
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(string(out), ShouldEqual, `null`)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -928,8 +928,8 @@ func (v *visitor) doVisitMemberExpressionSource(ctx *fql.MemberExpressionSourceC
|
||||
return v.doVisitParamContext(param.(*fql.ParamContext), scope)
|
||||
}
|
||||
|
||||
if fnCall := ctx.FunctionCallExpression(); fnCall != nil {
|
||||
return v.doVisitFunctionCallExpression(fnCall.(*fql.FunctionCallExpressionContext), scope)
|
||||
if fnCall := ctx.FunctionCall(); fnCall != nil {
|
||||
return v.doVisitFunctionCall(fnCall.(*fql.FunctionCallContext), false, scope)
|
||||
}
|
||||
|
||||
if objectLiteral := ctx.ObjectLiteral(); objectLiteral != nil {
|
||||
@@ -1134,7 +1134,7 @@ func (v *visitor) doVisitRangeOperator(ctx *fql.RangeOperatorContext, scope *sco
|
||||
)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitFunctionCallExpression(context *fql.FunctionCallExpressionContext, scope *scope) (core.Expression, error) {
|
||||
func (v *visitor) doVisitFunctionCall(context *fql.FunctionCallContext, ignoreErrors bool, scope *scope) (core.Expression, error) {
|
||||
args := make([]core.Expression, 0, 5)
|
||||
argsCtx := context.Arguments()
|
||||
|
||||
@@ -1170,10 +1170,19 @@ func (v *visitor) doVisitFunctionCallExpression(context *fql.FunctionCallExpress
|
||||
return expressions.NewFunctionCallExpression(
|
||||
v.getSourceMap(context),
|
||||
fun,
|
||||
ignoreErrors,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitFunctionCallExpression(context *fql.FunctionCallExpressionContext, scope *scope) (core.Expression, error) {
|
||||
return v.doVisitFunctionCall(
|
||||
context.FunctionCall().(*fql.FunctionCallContext),
|
||||
context.QuestionMark() != nil,
|
||||
scope,
|
||||
)
|
||||
}
|
||||
|
||||
func (v *visitor) doVisitParamContext(context *fql.ParamContext, s *scope) (core.Expression, error) {
|
||||
name := context.Identifier().GetText()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user