Skip to content

Commit b762f1e

Browse files
authored
feat: add functio array foreach (#403)
* feat: add function foreach array Signed-off-by: xdlbdy <[email protected]> * feat: add function foreach array Signed-off-by: xdlbdy <[email protected]> * feat: add function foreach array Signed-off-by: xdlbdy <[email protected]> * feat: add function foreach array Signed-off-by: xdlbdy <[email protected]> * feat: add function foreach array Signed-off-by: xdlbdy <[email protected]> * fix: ut error Signed-off-by: xdlbdy <[email protected]> * feat: add function foreach array Signed-off-by: xdlbdy <[email protected]> * feat: add function foreach array Signed-off-by: xdlbdy <[email protected]> * feat: feat: add function array foreach Signed-off-by: xdlbdy <[email protected]> * feat: feat: add function array foreach Signed-off-by: xdlbdy <[email protected]> Signed-off-by: xdlbdy <[email protected]>
1 parent 4a13057 commit b762f1e

File tree

13 files changed

+345
-50
lines changed

13 files changed

+345
-50
lines changed

internal/controller/trigger/validation/suscription_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ import (
1818
"context"
1919
"testing"
2020

21-
"google.golang.org/protobuf/types/known/structpb"
22-
2321
ctrlpb "github.com/linkall-labs/vanus/proto/pkg/controller"
2422
metapb "github.com/linkall-labs/vanus/proto/pkg/meta"
25-
2623
. "github.com/smartystreets/goconvey/convey"
24+
"google.golang.org/protobuf/types/known/structpb"
2725
)
2826

2927
func TestSubscriptionRequestValidator(t *testing.T) {

internal/primitive/transform/action/action.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,18 @@ var (
143143
ErrExist = fmt.Errorf("action have exist")
144144
ErrArgNumber = fmt.Errorf("action arg number invalid")
145145
)
146+
147+
type NestAction interface {
148+
Action
149+
InitAction(actions []Action) error
150+
}
151+
152+
type NestActionImpl struct {
153+
CommonAction
154+
Actions []Action
155+
}
156+
157+
func (c *NestActionImpl) InitAction(actions []Action) error {
158+
c.Actions = actions
159+
return nil
160+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2023 Linkall Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package array
16+
17+
import (
18+
"github.com/linkall-labs/vanus/internal/primitive/transform/action"
19+
"github.com/linkall-labs/vanus/internal/primitive/transform/arg"
20+
"github.com/linkall-labs/vanus/internal/primitive/transform/common"
21+
"github.com/linkall-labs/vanus/internal/primitive/transform/context"
22+
"github.com/pkg/errors"
23+
)
24+
25+
// ["array_foreach","array root", function].
26+
type arrayForeachAction struct {
27+
action.NestActionImpl
28+
}
29+
30+
func NewArrayForeachAction() action.Action {
31+
a := &arrayForeachAction{}
32+
a.CommonAction = action.CommonAction{
33+
ActionName: "ARRAY_FOREACH",
34+
FixedArgs: []arg.TypeList{[]arg.Type{arg.EventData}},
35+
}
36+
return a
37+
}
38+
39+
func (a *arrayForeachAction) Init(args []arg.Arg) error {
40+
a.TargetArg = args[0]
41+
a.Args = args
42+
a.ArgTypes = []common.Type{common.Array}
43+
return nil
44+
}
45+
46+
func (a *arrayForeachAction) Execute(ceCtx *context.EventContext) error {
47+
args, err := a.RunArgs(ceCtx)
48+
if err != nil {
49+
return err
50+
}
51+
arrayValue, _ := args[0].([]interface{})
52+
for i := range arrayValue {
53+
newCtx := &context.EventContext{
54+
Data: arrayValue[i],
55+
}
56+
for i := range a.Actions {
57+
err = a.Actions[i].Execute(newCtx)
58+
if err != nil {
59+
return errors.Wrapf(err, "action %dst execute error", i+1)
60+
}
61+
}
62+
}
63+
return a.TargetArg.SetValue(ceCtx, arrayValue)
64+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2023 Linkall Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package array_test
16+
17+
import (
18+
stdJson "encoding/json"
19+
"testing"
20+
21+
cetest "github.com/cloudevents/sdk-go/v2/test"
22+
"github.com/linkall-labs/vanus/internal/primitive/transform/action/array"
23+
"github.com/linkall-labs/vanus/internal/primitive/transform/context"
24+
"github.com/linkall-labs/vanus/internal/primitive/transform/runtime"
25+
. "github.com/smartystreets/goconvey/convey"
26+
)
27+
28+
func TestReplaceArrayAction(t *testing.T) {
29+
funcName := array.NewArrayForeachAction().Name()
30+
Convey("test replace array valid", t, func() {
31+
jsonStr := `{
32+
"array": [
33+
{
34+
"name": "name1",
35+
"number": 1
36+
},
37+
{
38+
"name": "name2",
39+
"number": "2"
40+
},
41+
{
42+
"name": "name3",
43+
"number": "3"
44+
}
45+
]
46+
}`
47+
Convey("replace valid", func() {
48+
a, err := runtime.NewAction([]interface{}{funcName, "$.data.array", []interface{}{"add_prefix", "@.name", "prefix"}})
49+
So(err, ShouldBeNil)
50+
51+
e := cetest.MinEvent()
52+
var data map[string]interface{}
53+
err = stdJson.Unmarshal([]byte(jsonStr), &data)
54+
So(err, ShouldBeNil)
55+
err = a.Execute(&context.EventContext{
56+
Event: &e,
57+
Data: data,
58+
})
59+
So(err, ShouldBeNil)
60+
value, exist := data["array"]
61+
So(exist, ShouldBeTrue)
62+
So(len(value.([]interface{})), ShouldEqual, 3)
63+
So(value.([]interface{})[0].(map[string]interface{})["name"], ShouldEqual, "prefixname1")
64+
So(value.([]interface{})[1].(map[string]interface{})["name"], ShouldEqual, "prefixname2")
65+
So(value.([]interface{})[2].(map[string]interface{})["name"], ShouldEqual, "prefixname3")
66+
})
67+
})
68+
}

internal/primitive/transform/action/render/array.go renamed to internal/primitive/transform/action/array/render.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package render
15+
package array
1616

1717
import (
1818
"fmt"

internal/primitive/transform/action/render/array_test.go renamed to internal/primitive/transform/action/array/render_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package render_test
15+
package array_test
1616

1717
import (
1818
stdJson "encoding/json"
1919
"testing"
2020

2121
cetest "github.com/cloudevents/sdk-go/v2/test"
22-
"github.com/linkall-labs/vanus/internal/primitive/transform/action/render"
22+
"github.com/linkall-labs/vanus/internal/primitive/transform/action/array"
2323
"github.com/linkall-labs/vanus/internal/primitive/transform/context"
2424
"github.com/linkall-labs/vanus/internal/primitive/transform/runtime"
2525
. "github.com/smartystreets/goconvey/convey"
2626
)
2727

2828
func TestRenderArrayAction(t *testing.T) {
29-
funcName := render.NewRenderArrayAction().Name()
29+
funcName := array.NewRenderArrayAction().Name()
3030
Convey("test render array invalid", t, func() {
3131
jsonStr := `{
3232
"array": [

internal/primitive/transform/arg/arg.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ func NewArg(arg interface{}) (Arg, error) {
8383
if argLen >= 2 && argName[:2] == EventArgPrefix {
8484
return newEventAttribute(argName)
8585
}
86+
if argLen >= 2 && argName[:2] == EventDataSubArgPrefix {
87+
return newEventData(EventDataArgPrefix + "." + argName[2:]), nil
88+
}
8689
if argLen >= 3 && argName[0] == '<' && argName[argLen-1] == '>' && argName[1] != '@' {
8790
return newDefine(argName), nil
8891
}
@@ -91,6 +94,7 @@ func NewArg(arg interface{}) (Arg, error) {
9194
}
9295

9396
const (
94-
EventArgPrefix = "$."
95-
EventDataArgPrefix = EventArgPrefix + "data"
97+
EventArgPrefix = "$."
98+
EventDataArgPrefix = EventArgPrefix + "data"
99+
EventDataSubArgPrefix = "@."
96100
)

internal/primitive/transform/arg/event.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,7 @@ func (arg eventData) Evaluate(ceCtx *context.EventContext) (interface{}, error)
115115
}
116116

117117
func (arg eventData) SetValue(ceCtx *context.EventContext, value interface{}) error {
118-
util.SetData(ceCtx.Data, arg.path, value)
119-
return nil
118+
return util.SetData(ceCtx.Data, arg.path, value)
120119
}
121120

122121
func (arg eventData) DeleteValue(ceCtx *context.EventContext) error {

internal/primitive/transform/runtime/action.go

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
package runtime
1616

1717
import (
18-
"fmt"
19-
stdStrs "strings"
18+
"strings"
2019

2120
"github.com/linkall-labs/vanus/internal/primitive/transform/action"
2221
"github.com/linkall-labs/vanus/internal/primitive/transform/arg"
@@ -29,9 +28,9 @@ var actionMap = map[string]newAction{}
2928

3029
func AddAction(actionFn newAction) error {
3130
a := actionFn()
32-
name := stdStrs.ToUpper(a.Name())
31+
name := strings.ToUpper(a.Name())
3332
if _, exist := actionMap[name]; exist {
34-
return fmt.Errorf("action %s has exist", name)
33+
return errors.Errorf("action %s has exist", name)
3534
}
3635
actionMap[name] = actionFn
3736
return nil
@@ -40,36 +39,64 @@ func AddAction(actionFn newAction) error {
4039
func NewAction(command []interface{}) (action.Action, error) {
4140
funcName, ok := command[0].(string)
4241
if !ok {
43-
return nil, fmt.Errorf("command name must be string")
42+
return nil, errors.Errorf("command name must be string")
4443
}
45-
actionFn, exist := actionMap[stdStrs.ToUpper(funcName)]
44+
actionFn, exist := actionMap[strings.ToUpper(funcName)]
4645
if !exist {
47-
return nil, fmt.Errorf("command %s not exist", funcName)
46+
return nil, errors.Errorf("command %s not exist", funcName)
4847
}
4948
a := actionFn()
5049
argNum := len(command) - 1
5150
if argNum < a.Arity() {
52-
return nil, fmt.Errorf("command %s arg number is not enough, it need %d but only have %d",
51+
return nil, errors.Errorf("command %s arg number is not enough, it need %d but only have %d",
5352
funcName, a.Arity(), argNum)
5453
}
55-
if argNum > a.Arity() && !a.IsVariadic() {
56-
return nil, fmt.Errorf("command %s arg number is too many, it need %d but have %d", funcName, a.Arity(), argNum)
54+
nestAction, isNestAction := a.(action.NestAction)
55+
if !isNestAction {
56+
if argNum > a.Arity() && !a.IsVariadic() {
57+
return nil, errors.Errorf("command %s arg number is too many, it need %d but have %d", funcName, a.Arity(), argNum)
58+
}
59+
} else {
60+
argNum = a.Arity()
5761
}
5862
args := make([]arg.Arg, argNum)
59-
for i := 1; i < len(command); i++ {
60-
_arg, err := arg.NewArg(command[i])
63+
for i := 0; i < len(args); i++ {
64+
index := i + 1
65+
_arg, err := arg.NewArg(command[index])
6166
if err != nil {
62-
return nil, errors.Wrapf(err, "command %s arg %d is invalid", funcName, i)
67+
return nil, errors.Wrapf(err, "command %s arg %d is invalid", funcName, index)
6368
}
64-
argType := a.ArgType(i - 1)
69+
argType := a.ArgType(i)
6570
if !argType.Contains(_arg) {
66-
return nil, fmt.Errorf("command %s arg %d not support type %s", funcName, i, _arg.Type())
71+
return nil, errors.Errorf("command %s arg %d not support type %s", funcName, index, _arg.Type())
6772
}
68-
args[i-1] = _arg
73+
args[i] = _arg
6974
}
7075
err := a.Init(args)
7176
if err != nil {
7277
return nil, errors.Wrapf(err, "command %s init error", funcName)
7378
}
79+
if isNestAction {
80+
actions := make([]action.Action, len(command)-1-argNum)
81+
if len(actions) == 0 {
82+
return nil, errors.Errorf("command %s arg number is not enough, lost function arg", funcName)
83+
}
84+
for i := 0; i < len(actions); i++ {
85+
index := i + 1 + argNum
86+
if arr, ok := command[index].([]interface{}); ok {
87+
_a, err := NewAction(arr)
88+
if err != nil {
89+
return nil, errors.Wrapf(err, "action %s arg %d new action failed", funcName, index)
90+
}
91+
actions[i] = _a
92+
} else {
93+
return nil, errors.Errorf("arg %d is invalid", index)
94+
}
95+
}
96+
err = nestAction.InitAction(actions)
97+
if err != nil {
98+
return nil, errors.Wrapf(err, "command %s init action error", funcName)
99+
}
100+
}
74101
return a, nil
75102
}

internal/primitive/transform/runtime/action_bench_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@ package runtime
1717
import (
1818
"testing"
1919

20-
"github.com/linkall-labs/vanus/internal/primitive/transform/context"
21-
2220
ce "github.com/cloudevents/sdk-go/v2"
2321
cetest "github.com/cloudevents/sdk-go/v2/test"
22+
"github.com/linkall-labs/vanus/internal/primitive/transform/context"
2423
)
2524

2625
func actionBenchmark(command []interface{}) func(b *testing.B) {

0 commit comments

Comments
 (0)