Skip to content

Commit

Permalink
feat: add function render_array (#358)
Browse files Browse the repository at this point in the history
* feat: add function render_array

Signed-off-by: delu <[email protected]>

* feat: add function render_array

Signed-off-by: delu <[email protected]>

* fix: golangci init

Signed-off-by: delu <[email protected]>

Signed-off-by: delu <[email protected]>
  • Loading branch information
xdlbdy authored Dec 23, 2022
1 parent 2d5c6dc commit b33fc18
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 4 deletions.
114 changes: 114 additions & 0 deletions internal/primitive/transform/action/render/array.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright 2022 Linkall Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package render

import (
"fmt"
"strings"

"github.com/linkall-labs/vanus/internal/primitive/transform/action"
"github.com/linkall-labs/vanus/internal/primitive/transform/arg"
"github.com/linkall-labs/vanus/internal/primitive/transform/common"
"github.com/linkall-labs/vanus/internal/primitive/transform/context"
)

// ["render_array","targetPath","render root","render template"].
type renderArrayAction struct {
action.CommonAction
paths []string
template string
leftDelim string
rightDelim string
}

func NewRenderArrayAction() action.Action {
a := &renderArrayAction{
leftDelim: "<@",
rightDelim: ">",
}
a.CommonAction = action.CommonAction{
ActionName: "RENDER_ARRAY",
FixedArgs: []arg.TypeList{arg.EventList, []arg.Type{arg.EventData}, []arg.Type{arg.Constant}},
}
return a
}

func (a *renderArrayAction) Init(args []arg.Arg) error {
a.TargetArg = args[0]
jsonPrefix := args[1].Original()
text := args[2].Original()
var pos int
var sb strings.Builder
leftDelimLen := len(a.leftDelim)
for {
x := strings.Index(text[pos:], a.leftDelim)
if x < 0 {
sb.WriteString(text[pos:])
break
}
ldp := pos + x + leftDelimLen
y := strings.Index(text[ldp:], a.rightDelim)
if y < 0 {
sb.WriteString(text[pos:])
break
}
if x > 0 {
sb.WriteString(text[pos : pos+x])
}
a.paths = append(a.paths, text[ldp:ldp+y])

sb.WriteString("%v")
pos = ldp + y + len(a.rightDelim)
if pos == len(text) {
break
}
}
a.template = sb.String()
for _, path := range a.paths {
_arg, err := arg.NewArg(jsonPrefix + "[:]" + path)
if err != nil {
return err
}
a.Args = append(a.Args, _arg)
a.ArgTypes = append(a.ArgTypes, common.Array)
}
return nil
}

func (a *renderArrayAction) Execute(ceCtx *context.EventContext) error {
args, err := a.RunArgs(ceCtx)
if err != nil {
return err
}
if len(args) == 0 {
return a.TargetArg.SetValue(ceCtx, []string{a.template})
}
_len := len(args[0].([]interface{}))
for i := 1; i < len(args); i++ {
if len(args[i].([]interface{})) != _len {
return fmt.Errorf("template %s value length is not same", a.leftDelim+a.paths[i]+a.rightDelim)
}
}

target := make([]string, _len)
for i := 0; i < _len; i++ {
value := make([]interface{}, len(a.paths))
for j := 0; j < len(args); j++ {
value[j] = args[j].([]interface{})[i]
}
target[i] = fmt.Sprintf(a.template, value...)
}
return a.TargetArg.SetValue(ceCtx, target)
}
155 changes: 155 additions & 0 deletions internal/primitive/transform/action/render/array_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright 2022 Linkall Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package render_test

import (
stdJson "encoding/json"
"testing"

cetest "github.com/cloudevents/sdk-go/v2/test"
"github.com/linkall-labs/vanus/internal/primitive/transform/action/render"
"github.com/linkall-labs/vanus/internal/primitive/transform/context"
"github.com/linkall-labs/vanus/internal/primitive/transform/runtime"
. "github.com/smartystreets/goconvey/convey"
)

func TestRenderArrayAction(t *testing.T) {
funcName := render.NewRenderArrayAction().Name()
Convey("test render array invalid", t, func() {
jsonStr := `{
"array": [
{
"name": "name1",
"number": 1
},
{
"name": "name2",
"number": "2"
},
{
"name": "name3"
}
]
}`
Convey("render param not same", func() {
a, err := runtime.NewAction([]interface{}{funcName, "$.data.render", "$.data.array", "begin <@.name> <@.number> end"})
So(err, ShouldBeNil)
e := cetest.MinEvent()
var data map[string]interface{}
err = stdJson.Unmarshal([]byte(jsonStr), &data)
So(err, ShouldBeNil)
err = a.Execute(&context.EventContext{
Event: &e,
Data: data,
})
So(err, ShouldNotBeNil)
})
})
Convey("test render array valid", t, func() {
jsonStr := `{
"array": [
{
"name": "name1",
"number": 1
},
{
"name": "name2",
"number": "2"
},
{
"name": "name3",
"number": "3"
}
]
}`
Convey("render constants", func() {
a, err := runtime.NewAction([]interface{}{funcName, "$.data.render", "$.data.array", "abc"})
So(err, ShouldBeNil)

e := cetest.MinEvent()
var data map[string]interface{}
err = stdJson.Unmarshal([]byte(jsonStr), &data)
So(err, ShouldBeNil)
err = a.Execute(&context.EventContext{
Event: &e,
Data: data,
})
So(err, ShouldBeNil)
render, exist := data["render"]
So(exist, ShouldBeTrue)
So(len(render.([]string)), ShouldEqual, 1)
So(render.([]string)[0], ShouldEqual, "abc")
})
Convey("render variable template", func() {
Convey("render all variable", func() {
a, err := runtime.NewAction([]interface{}{funcName, "$.data.render", "$.data.array", "<@.name><@.number>"})
So(err, ShouldBeNil)
e := cetest.MinEvent()
var data map[string]interface{}
err = stdJson.Unmarshal([]byte(jsonStr), &data)
So(err, ShouldBeNil)
err = a.Execute(&context.EventContext{
Event: &e,
Data: data,
})
So(err, ShouldBeNil)
render, exist := data["render"]
So(exist, ShouldBeTrue)
So(len(render.([]string)), ShouldEqual, 3)
So(render.([]string)[0], ShouldEqual, "name11")
So(render.([]string)[1], ShouldEqual, "name22")
So(render.([]string)[2], ShouldEqual, "name33")
})
Convey("render begin and end", func() {
a, err := runtime.NewAction([]interface{}{funcName, "$.data.render", "$.data.array", "<@.name> and <@.number>"})
So(err, ShouldBeNil)
e := cetest.MinEvent()
var data map[string]interface{}
err = stdJson.Unmarshal([]byte(jsonStr), &data)
So(err, ShouldBeNil)
err = a.Execute(&context.EventContext{
Event: &e,
Data: data,
})
So(err, ShouldBeNil)
render, exist := data["render"]
So(exist, ShouldBeTrue)
So(len(render.([]string)), ShouldEqual, 3)
So(render.([]string)[0], ShouldEqual, "name1 and 1")
So(render.([]string)[1], ShouldEqual, "name2 and 2")
So(render.([]string)[2], ShouldEqual, "name3 and 3")
})
Convey("render other", func() {
a, err := runtime.NewAction([]interface{}{funcName, "$.data.render", "$.data.array", "Name: <@.name> Num: <@.number> <@abc"})
So(err, ShouldBeNil)
e := cetest.MinEvent()
var data map[string]interface{}
err = stdJson.Unmarshal([]byte(jsonStr), &data)
So(err, ShouldBeNil)
err = a.Execute(&context.EventContext{
Event: &e,
Data: data,
})
So(err, ShouldBeNil)
render, exist := data["render"]
So(exist, ShouldBeTrue)
So(len(render.([]string)), ShouldEqual, 3)
So(render.([]string)[0], ShouldEqual, "Name: name1 Num: 1 <@abc")
So(render.([]string)[1], ShouldEqual, "Name: name2 Num: 2 <@abc")
So(render.([]string)[2], ShouldEqual, "Name: name3 Num: 3 <@abc")
})
})
})
}
2 changes: 1 addition & 1 deletion internal/primitive/transform/arg/arg.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func NewArg(arg interface{}) (Arg, error) {
if argLen >= 2 && argName[:2] == EventArgPrefix {
return newEventAttribute(argName)
}
if argLen >= 3 && argName[0] == '<' && argName[argLen-1] == '>' {
if argLen >= 3 && argName[0] == '<' && argName[argLen-1] == '>' && argName[1] != '@' {
return newDefine(argName), nil
}
}
Expand Down
7 changes: 4 additions & 3 deletions internal/primitive/transform/runtime/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
package runtime

import (
"github.com/linkall-labs/vanus/internal/primitive/transform/action/condition"
"github.com/linkall-labs/vanus/internal/primitive/transform/action/datetime"
"github.com/linkall-labs/vanus/internal/primitive/transform/action/math"

"github.com/linkall-labs/vanus/internal/primitive/transform/action/render"
"github.com/linkall-labs/vanus/internal/primitive/transform/action/strings"
"github.com/linkall-labs/vanus/internal/primitive/transform/action/structs"

"github.com/linkall-labs/vanus/internal/primitive/transform/action/condition"
)

func init() {
Expand Down Expand Up @@ -49,6 +48,8 @@ func init() {
strings.NewReplaceWithRegexAction,
// condition
condition.NewConditionIfAction,
// render
render.NewRenderArrayAction,
} {
if err := AddAction(fn); err != nil {
panic(err)
Expand Down

0 comments on commit b33fc18

Please sign in to comment.