From ae12b2237d7dd5f91ae3636af9bf3af3200e876d Mon Sep 17 00:00:00 2001 From: Allen Date: Sat, 25 Feb 2023 22:42:52 +0600 Subject: [PATCH 1/7] feat: create files split_from_start.go and split_from_start_test.go --- internal/primitive/transform/action/strings/split_from_start.go | 1 + .../primitive/transform/action/strings/split_from_start_test.go | 1 + 2 files changed, 2 insertions(+) create mode 100644 internal/primitive/transform/action/strings/split_from_start.go create mode 100644 internal/primitive/transform/action/strings/split_from_start_test.go diff --git a/internal/primitive/transform/action/strings/split_from_start.go b/internal/primitive/transform/action/strings/split_from_start.go new file mode 100644 index 000000000..e152b4b83 --- /dev/null +++ b/internal/primitive/transform/action/strings/split_from_start.go @@ -0,0 +1 @@ +package strings diff --git a/internal/primitive/transform/action/strings/split_from_start_test.go b/internal/primitive/transform/action/strings/split_from_start_test.go new file mode 100644 index 000000000..9c53d25e9 --- /dev/null +++ b/internal/primitive/transform/action/strings/split_from_start_test.go @@ -0,0 +1 @@ +package strings_test From 54df2426ac3ac898b89cea0fa866610c3b7ffc8c Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 27 Feb 2023 20:36:42 +0600 Subject: [PATCH 2/7] feat: add constructor NewSplitFromStartAction, register it in runtime.Init --- .../action/strings/split_from_start.go | 31 +++++++++++++++++++ internal/primitive/transform/runtime/init.go | 1 + 2 files changed, 32 insertions(+) diff --git a/internal/primitive/transform/action/strings/split_from_start.go b/internal/primitive/transform/action/strings/split_from_start.go index e152b4b83..70e7909a0 100644 --- a/internal/primitive/transform/action/strings/split_from_start.go +++ b/internal/primitive/transform/action/strings/split_from_start.go @@ -1 +1,32 @@ +// Copyright 2023 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 strings + +import ( + "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/function" +) + +// NewSplitFromStartAction ["split_from_start", "key"]. +func NewSplitFromStartAction() action.Action { + a := &action.SourceTargetSameAction{} + a.CommonAction = action.CommonAction{ + ActionName: "SPLIT_FROM_START", + FixedArgs: []arg.TypeList{arg.EventList, arg.All}, + Fn: function.SplitFromStart, + } + return a +} diff --git a/internal/primitive/transform/runtime/init.go b/internal/primitive/transform/runtime/init.go index 390cd8511..42e41360f 100644 --- a/internal/primitive/transform/runtime/init.go +++ b/internal/primitive/transform/runtime/init.go @@ -55,6 +55,7 @@ func init() { strings.NewCheckCustomValuesAction, strings.NewCapitalizeWordAction, strings.NewSplitWithDelimiterAction, + strings.NewSplitFromStartAction, // condition condition.NewConditionIfAction, // array From 29e6a9121a9bddd7edd946773197a170aa66046f Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 27 Feb 2023 21:34:04 +0600 Subject: [PATCH 3/7] feat: add SplitFromStart, initial code --- .../transform/function/strings_functions.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/internal/primitive/transform/function/strings_functions.go b/internal/primitive/transform/function/strings_functions.go index 2846d2760..f69942b6b 100644 --- a/internal/primitive/transform/function/strings_functions.go +++ b/internal/primitive/transform/function/strings_functions.go @@ -140,3 +140,22 @@ var CapitalizeWord = function{ return string(rs), nil }, } + +var SplitFromStart = function{ + name: "SPLIT_FROM_START", + fixedArgs: []common.Type{common.String, common.Int}, + fn: func(args []interface{}) (interface{}, error) { + value, _ := args[0].(string) + splitPosition, _ := args[1].(int) + if len(value) < 2 { + return []string{value}, nil + } + if splitPosition < 1 { + return nil, fmt.Errorf("split position must be more than zero") + } + if splitPosition >= len(value) { + return nil, fmt.Errorf("split position must be less than the length of the string") + } + return []string{value[:splitPosition], value[splitPosition:]}, nil + }, +} From 9948fe4488ba14f87e65b6c989e8a65d2e705353 Mon Sep 17 00:00:00 2001 From: Allen Date: Fri, 3 Mar 2023 20:48:05 +0600 Subject: [PATCH 4/7] feat: SplitFromStart with constructor redefining Execute, add main tests --- .../action/strings/split_from_start.go | 18 +++- .../action/strings/split_from_start_test.go | 92 +++++++++++++++++++ .../transform/function/strings_functions.go | 3 +- 3 files changed, 109 insertions(+), 4 deletions(-) diff --git a/internal/primitive/transform/action/strings/split_from_start.go b/internal/primitive/transform/action/strings/split_from_start.go index 70e7909a0..99c345828 100644 --- a/internal/primitive/transform/action/strings/split_from_start.go +++ b/internal/primitive/transform/action/strings/split_from_start.go @@ -17,16 +17,28 @@ package strings import ( "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/function" ) -// NewSplitFromStartAction ["split_from_start", "key"]. +type splitFromStartAction struct { + action.FunctionAction +} + +// NewSplitFromStartAction ["split_from_start", "sourceJsonPath", "position", "targetJsonPath"]. func NewSplitFromStartAction() action.Action { - a := &action.SourceTargetSameAction{} + a := &splitFromStartAction{} a.CommonAction = action.CommonAction{ ActionName: "SPLIT_FROM_START", - FixedArgs: []arg.TypeList{arg.EventList, arg.All}, + FixedArgs: []arg.TypeList{arg.EventList, []arg.Type{arg.Constant}, []arg.Type{arg.EventData}}, Fn: function.SplitFromStart, } return a } + +func (a *splitFromStartAction) Init(args []arg.Arg) error { + a.TargetArg = args[2] + a.Args = args[:2] + a.ArgTypes = []common.Type{common.String, common.Int} + return nil +} diff --git a/internal/primitive/transform/action/strings/split_from_start_test.go b/internal/primitive/transform/action/strings/split_from_start_test.go index 9c53d25e9..30b1da6cb 100644 --- a/internal/primitive/transform/action/strings/split_from_start_test.go +++ b/internal/primitive/transform/action/strings/split_from_start_test.go @@ -1 +1,93 @@ +// Copyright 2023 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 strings_test + +import ( + "testing" + + cetest "github.com/cloudevents/sdk-go/v2/test" + "github.com/linkall-labs/vanus/internal/primitive/transform/action/strings" + "github.com/linkall-labs/vanus/internal/primitive/transform/context" + "github.com/linkall-labs/vanus/internal/primitive/transform/runtime" + . "github.com/smartystreets/goconvey/convey" +) + +func TestSplitFromStartAction(t *testing.T) { + funcName := strings.NewSplitFromStartAction().Name() + + Convey("test split from start: Positive testcase", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", 5, "$.data.target"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{} + e.SetExtension("test", "Hello, World!") + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err, ShouldBeNil) + res, ok := data["target"] + So(ok, ShouldBeTrue) + So(res, ShouldResemble, []string{"Hello", ", World!"}) + }) + + Convey("test split from start: Positive testcase, length 1", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", 0, "$.data.target"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{} + e.SetExtension("test", "H") + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err, ShouldBeNil) + res, ok := data["target"] + So(ok, ShouldBeTrue) + So(res, ShouldResemble, []string{"H"}) + }) + + Convey("test split from start: Negative testcase, split position less than one", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", 0, "$.data.target"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{} + e.SetExtension("test", "split position must be more than zero") + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err, ShouldNotBeNil) + So(e.Extensions()["test"], ShouldEqual, "split position must be more than zero") + }) + + Convey("test split from start: Negative testcase, split position greater than string length", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", 100, "$.data.target"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{} + e.SetExtension("test", "split position must be less than the length of the string") + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err, ShouldNotBeNil) + So(e.Extensions()["test"], ShouldEqual, "split position must be less than the length of the string") + }) +} diff --git a/internal/primitive/transform/function/strings_functions.go b/internal/primitive/transform/function/strings_functions.go index f69942b6b..de3010f2b 100644 --- a/internal/primitive/transform/function/strings_functions.go +++ b/internal/primitive/transform/function/strings_functions.go @@ -156,6 +156,7 @@ var SplitFromStart = function{ if splitPosition >= len(value) { return nil, fmt.Errorf("split position must be less than the length of the string") } - return []string{value[:splitPosition], value[splitPosition:]}, nil + result := []string{value[:splitPosition], value[splitPosition:]} + return result, nil }, } From ca2c152288596d0707bd3510945fbf0d0602a0bb Mon Sep 17 00:00:00 2001 From: Jeffrey Whewhetu <106184818+c0d33ngr@users.noreply.github.com> Date: Mon, 6 Mar 2023 11:23:39 +0100 Subject: [PATCH 5/7] feat: function replace between delimiters (#434) * Create replace_between_delimiters_action function * Add function for replace_between_delimiters * Add test case for replace_between_delimiters function * Register replace_between_delimiters function in init.go file * Fix syntax error in strings_function * Update replace_between_delimiters function to catch wide range of inputs * Update unit test for replace_between_delimiters function * Remove typos from contributing file * Improve replace_between_delimiter function * Add new testcase for replace_between_delimiters function * Fix and refactor replace_between_delimiter function * Update replace_between_delimiters_test * Resolve bug in replace_between_delimiter function * Fix bug in switch case for replace_between_delimiters * Fix replace_between_delimiters to pass codecov and golangci-lint checks * Refactor replace_between_delimiters function --- .../strings/replace_between_delimiters.go | 32 +++++++ .../replace_between_delimiters_test.go | 94 +++++++++++++++++++ .../transform/function/strings_functions.go | 25 +++++ .../transform/runtime/action_bench_test.go | 1 + internal/primitive/transform/runtime/init.go | 1 + 5 files changed, 153 insertions(+) create mode 100644 internal/primitive/transform/action/strings/replace_between_delimiters.go create mode 100644 internal/primitive/transform/action/strings/replace_between_delimiters_test.go diff --git a/internal/primitive/transform/action/strings/replace_between_delimiters.go b/internal/primitive/transform/action/strings/replace_between_delimiters.go new file mode 100644 index 000000000..a0ccb6910 --- /dev/null +++ b/internal/primitive/transform/action/strings/replace_between_delimiters.go @@ -0,0 +1,32 @@ +// Copyright 2023 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 strings + +import ( + "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/function" +) + +// NewReplaceBetweenDelimitersAction ["path","startDelimiter","endDelimiter","newValue"]. +func NewReplaceBetweenDelimitersAction() action.Action { + a := &action.SourceTargetSameAction{} + a.CommonAction = action.CommonAction{ + ActionName: "REPLACE_BETWEEN_DELIMITERS", + FixedArgs: []arg.TypeList{arg.EventList, arg.All, arg.All, arg.All}, + Fn: function.ReplaceBetweenDelimitersFunction, + } + return a +} diff --git a/internal/primitive/transform/action/strings/replace_between_delimiters_test.go b/internal/primitive/transform/action/strings/replace_between_delimiters_test.go new file mode 100644 index 000000000..da4230dc0 --- /dev/null +++ b/internal/primitive/transform/action/strings/replace_between_delimiters_test.go @@ -0,0 +1,94 @@ +// Copyright 2023 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 strings_test + +import ( + "testing" + + cetest "github.com/cloudevents/sdk-go/v2/test" + "github.com/linkall-labs/vanus/internal/primitive/transform/action/strings" + "github.com/linkall-labs/vanus/internal/primitive/transform/context" + "github.com/linkall-labs/vanus/internal/primitive/transform/runtime" + . "github.com/smartystreets/goconvey/convey" +) + +func TestReplaceBetweenDelimitersAction(t *testing.T) { + funcName := strings.NewReplaceBetweenDelimitersAction().Name() + + Convey("test startDelimiter and endDelimiter present in string testcase", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", "&&", "&&", "Vanus"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + e.SetExtension("test", "Hello, &&World&&!") + ceCtx := &context.EventContext{ + Event: &e, + } + err = a.Execute(ceCtx) + So(err, ShouldBeNil) + So(e.Extensions()["test"], ShouldEqual, "Hello, Vanus!") + }) + + Convey("test startDelimiter and endDelimiter present in string testcase", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", "^^", "^^", "lots of"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + e.SetExtension("test", "Vanus has ^^many^^ beginner friendly open issues!") + ceCtx := &context.EventContext{ + Event: &e, + } + err = a.Execute(ceCtx) + So(err, ShouldBeNil) + So(e.Extensions()["test"], ShouldEqual, "Vanus has lots of beginner friendly open issues!") + }) + + Convey("test startDelimiter and endDelimiter not present in string testcase", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", "**", "**", "fun"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + e.SetExtension("test", "Contributing to Vanus Opensource project is %%an eye opener%%!") + ceCtx := &context.EventContext{ + Event: &e, + } + err = a.Execute(ceCtx) + So(err, ShouldNotBeNil) + So(e.Extensions()["test"], ShouldEqual, "Contributing to Vanus Opensource project is %%an eye opener%%!") + }) + + Convey("test endDelimiter before startDelimiter in string testcase", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", "&&", "!!", "love"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + e.SetExtension("test", "I !!like&& opensource contributions") + ceCtx := &context.EventContext{ + Event: &e, + } + err = a.Execute(ceCtx) + So(err, ShouldNotBeNil) + So(e.Extensions()["test"], ShouldEqual, "I !!like&& opensource contributions") + }) + + Convey("test Only endDelimiter present in string testcase", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", "&&", "**", "supported"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + e.SetExtension("test", "FOSS is !!powered** by open communities") + ceCtx := &context.EventContext{ + Event: &e, + } + err = a.Execute(ceCtx) + So(err, ShouldNotBeNil) + So(e.Extensions()["test"], ShouldEqual, "FOSS is !!powered** by open communities") + }) +} diff --git a/internal/primitive/transform/function/strings_functions.go b/internal/primitive/transform/function/strings_functions.go index 2846d2760..239768685 100644 --- a/internal/primitive/transform/function/strings_functions.go +++ b/internal/primitive/transform/function/strings_functions.go @@ -120,6 +120,31 @@ var CapitalizeSentence = function{ }, } +var ReplaceBetweenDelimitersFunction = function{ + name: "REPLACE_BETWEEN_DELIMITERS", + fixedArgs: []common.Type{common.String, common.String, common.String, common.String}, + fn: func(args []interface{}) (interface{}, error) { + value, _ := args[0].(string) + startDelimiter, _ := args[1].(string) + endDelimiter, _ := args[2].(string) + replaceValue, _ := args[3].(string) + if startDelimiter == "" || endDelimiter == "" { + return nil, fmt.Errorf("start or end delemiter is empty") + } + startIndex := strings.Index(value, startDelimiter) + if startIndex < 0 { + return nil, fmt.Errorf("start delemiter is not exist") + } + index := startIndex + len(startDelimiter) + endIndex := strings.Index(value[index:], endDelimiter) + if endIndex < 0 { + return nil, fmt.Errorf("end delemiter is not exist") + } + return value[:startIndex] + replaceValue + value[index+endIndex+len(endDelimiter):], nil + + }, +} + var CapitalizeWord = function{ name: "CAPITALIZE_WORD", fixedArgs: []common.Type{common.String}, diff --git a/internal/primitive/transform/runtime/action_bench_test.go b/internal/primitive/transform/runtime/action_bench_test.go index ae8c9f591..143f6c1cb 100644 --- a/internal/primitive/transform/runtime/action_bench_test.go +++ b/internal/primitive/transform/runtime/action_bench_test.go @@ -81,4 +81,5 @@ func BenchmarkAction(b *testing.B) { b.Run("check_custom_values", actionBenchmark([]interface{}{"check_custom_values", "$.data.str", "value", "$.data.target", "true", "false"})) b.Run("split_with_delimiter", actionBenchmark([]interface{}{"split_with_delimiter", "$.data.str", "a", "$.data.target"})) b.Run("unfold_array", actionBenchmark([]interface{}{"unfold_array", "$.data.str", "$.data.target"})) + b.Run("replace_between_delimiter", actionBenchmark([]interface{}{"replace_between_delimiter", "$.test", "&&", "&&", "Vanus"})) } diff --git a/internal/primitive/transform/runtime/init.go b/internal/primitive/transform/runtime/init.go index d9d775f50..d30555f25 100644 --- a/internal/primitive/transform/runtime/init.go +++ b/internal/primitive/transform/runtime/init.go @@ -53,6 +53,7 @@ func init() { strings.NewReplaceBetweenPositionsAction, strings.NewCapitalizeSentenceAction, strings.NewCheckCustomValuesAction, + strings.NewReplaceBetweenDelimitersAction, strings.NewCapitalizeWordAction, strings.NewSplitWithDelimiterAction, // condition From f6227332d59951703b67eddab2add7b1c2d2f647 Mon Sep 17 00:00:00 2001 From: soumyadeep589 Date: Mon, 6 Mar 2023 15:54:06 +0530 Subject: [PATCH 6/7] feat: implement function split_between_positions (#468) * feat: implement function split_between_positions * minor: fix linting errors * minor: fix linting errors * feat: implement split between position according to new description * minor: fix linting errors --- .../action/strings/split_between_positions.go | 90 ++++++++++++++ .../strings/split_between_positions_test.go | 114 ++++++++++++++++++ internal/primitive/transform/runtime/init.go | 1 + 3 files changed, 205 insertions(+) create mode 100644 internal/primitive/transform/action/strings/split_between_positions.go create mode 100644 internal/primitive/transform/action/strings/split_between_positions_test.go diff --git a/internal/primitive/transform/action/strings/split_between_positions.go b/internal/primitive/transform/action/strings/split_between_positions.go new file mode 100644 index 000000000..a8ea063ca --- /dev/null +++ b/internal/primitive/transform/action/strings/split_between_positions.go @@ -0,0 +1,90 @@ +// Copyright 2023 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 strings + +import ( + "fmt" + + "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" +) + +type splitBetweenPositionsAction struct { + action.CommonAction +} + +// NewSplitBetweenPositionsAction["sourceJSONPath", "startPosition", "endPosition", "targetJsonPath"]. +func NewSplitBetweenPositionsAction() action.Action { + return &splitBetweenPositionsAction{ + CommonAction: action.CommonAction{ + ActionName: "SPLIT_BETWEEN_POSITIONS", + FixedArgs: []arg.TypeList{arg.EventList, arg.All, arg.All, []arg.Type{arg.EventData}}, + }, + } +} + +func (a *splitBetweenPositionsAction) Init(args []arg.Arg) error { + a.TargetArg = args[3] + a.Args = args[:3] + a.ArgTypes = []common.Type{common.String, common.Int, common.Int} + return nil +} + +func (a *splitBetweenPositionsAction) Execute(ceCtx *context.EventContext) error { + args, err := a.RunArgs(ceCtx) + if err != nil { + return err + } + + v, _ := a.TargetArg.Evaluate(ceCtx) + if v != nil { + return fmt.Errorf("key %s exists", a.TargetArg.Original()) + } + + sourceJSONPath, _ := args[0].(string) + startPosition, _ := args[1].(int) + endPosition, _ := args[2].(int) + + var substrings []string + + switch { + case startPosition >= endPosition: + // if startPosition is gte endPosition, return an error + return fmt.Errorf("start position must be less than the endPosition") + case startPosition >= len(sourceJSONPath): + // if startPosition is beyond the end of the string + substrings = []string{ + sourceJSONPath, + "", + "", + } + case endPosition > len(sourceJSONPath): + // if endPosition is beyond the end of the string + substrings = []string{ + sourceJSONPath[:startPosition], + sourceJSONPath[startPosition:], + "", + } + default: + substrings = []string{ + sourceJSONPath[:startPosition], + sourceJSONPath[startPosition:endPosition], + sourceJSONPath[endPosition:], + } + } + return a.TargetArg.SetValue(ceCtx, substrings) +} diff --git a/internal/primitive/transform/action/strings/split_between_positions_test.go b/internal/primitive/transform/action/strings/split_between_positions_test.go new file mode 100644 index 000000000..faa739ceb --- /dev/null +++ b/internal/primitive/transform/action/strings/split_between_positions_test.go @@ -0,0 +1,114 @@ +// Copyright 2023 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 strings_test + +import ( + "testing" + + cetest "github.com/cloudevents/sdk-go/v2/test" + "github.com/linkall-labs/vanus/internal/primitive/transform/action/strings" + "github.com/linkall-labs/vanus/internal/primitive/transform/context" + "github.com/linkall-labs/vanus/internal/primitive/transform/runtime" + . "github.com/smartystreets/goconvey/convey" +) + +func TestSplitBetweenPositionsAction(t *testing.T) { + funcName := strings.NewSplitBetweenPositionsAction().Name() + + Convey("test Positive testcase", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.data.appinfoA", 2, 4, "$.data.appinfoB"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{ + "appinfoA": "hello world!", + } + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err, ShouldBeNil) + res, ok := data["appinfoB"] + So(ok, ShouldBeTrue) + So(res, ShouldResemble, []string{"he", "ll", "o world!"}) + }) + + Convey("test when start position is greater than the end position", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.data.appinfoA", 7, 6, "$.data.appinfoB"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{ + "appinfoA": "hello world!", + } + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err.Error(), ShouldEqual, "start position must be less than the endPosition") + }) + + Convey("test when start position is greater than the length of the string", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.data.appinfoA", 100, 200, "$.data.appinfoB"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{ + "appinfoA": "hello world!", + } + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err, ShouldBeNil) + res, ok := data["appinfoB"] + So(ok, ShouldBeTrue) + So(res, ShouldResemble, []string{"hello world!", "", ""}) + }) + + Convey("test when end position is greater than the length of the string", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.data.appinfoA", 4, 200, "$.data.appinfoB"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{ + "appinfoA": "hello world!", + } + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err, ShouldBeNil) + res, ok := data["appinfoB"] + So(ok, ShouldBeTrue) + So(res, ShouldResemble, []string{"hell", "o world!", ""}) + }) + + Convey("test when target key exists", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.data.appinfoA", 2, 2, "$.data.appinfoB"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{ + "appinfoA": "hello world!", + "appinfoB": "", + } + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err.Error(), ShouldEqual, "key $.data.appinfoB exists") + }) +} diff --git a/internal/primitive/transform/runtime/init.go b/internal/primitive/transform/runtime/init.go index d30555f25..64bc0c7ca 100644 --- a/internal/primitive/transform/runtime/init.go +++ b/internal/primitive/transform/runtime/init.go @@ -56,6 +56,7 @@ func init() { strings.NewReplaceBetweenDelimitersAction, strings.NewCapitalizeWordAction, strings.NewSplitWithDelimiterAction, + strings.NewSplitBetweenPositionsAction, // condition condition.NewConditionIfAction, // array From 7d6f616e36ca5a485edea9beade6bca05b4e27e6 Mon Sep 17 00:00:00 2001 From: Allen Date: Mon, 6 Mar 2023 17:22:49 +0600 Subject: [PATCH 7/7] fix: update how split_from_start handles special cases, update unit tests --- .../action/strings/split_from_start_test.go | 43 +++++++++++++------ .../transform/function/strings_functions.go | 10 ++--- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/internal/primitive/transform/action/strings/split_from_start_test.go b/internal/primitive/transform/action/strings/split_from_start_test.go index 30b1da6cb..20479254b 100644 --- a/internal/primitive/transform/action/strings/split_from_start_test.go +++ b/internal/primitive/transform/action/strings/split_from_start_test.go @@ -27,7 +27,7 @@ import ( func TestSplitFromStartAction(t *testing.T) { funcName := strings.NewSplitFromStartAction().Name() - Convey("test split from start: Positive testcase", t, func() { + Convey("test split from start: Positive testcase, common", t, func() { a, err := runtime.NewAction([]interface{}{funcName, "$.test", 5, "$.data.target"}) So(err, ShouldBeNil) e := cetest.MinEvent() @@ -45,7 +45,7 @@ func TestSplitFromStartAction(t *testing.T) { }) Convey("test split from start: Positive testcase, length 1", t, func() { - a, err := runtime.NewAction([]interface{}{funcName, "$.test", 0, "$.data.target"}) + a, err := runtime.NewAction([]interface{}{funcName, "$.test", 1, "$.data.target"}) So(err, ShouldBeNil) e := cetest.MinEvent() data := map[string]interface{}{} @@ -58,36 +58,55 @@ func TestSplitFromStartAction(t *testing.T) { So(err, ShouldBeNil) res, ok := data["target"] So(ok, ShouldBeTrue) - So(res, ShouldResemble, []string{"H"}) + So(res, ShouldResemble, []string{"H", ""}) }) - Convey("test split from start: Negative testcase, split position less than one", t, func() { - a, err := runtime.NewAction([]interface{}{funcName, "$.test", 0, "$.data.target"}) + Convey("test split from start: Positive testcase, length 0", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", 1, "$.data.target"}) So(err, ShouldBeNil) e := cetest.MinEvent() data := map[string]interface{}{} - e.SetExtension("test", "split position must be more than zero") + e.SetExtension("test", "") ceCtx := &context.EventContext{ Event: &e, Data: data, } err = a.Execute(ceCtx) - So(err, ShouldNotBeNil) - So(e.Extensions()["test"], ShouldEqual, "split position must be more than zero") + So(err, ShouldBeNil) + res, ok := data["target"] + So(ok, ShouldBeTrue) + So(res, ShouldResemble, []string{"", ""}) + }) + + Convey("test split from start: Positive testcase, split position above value length", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", 10, "$.data.target"}) + So(err, ShouldBeNil) + e := cetest.MinEvent() + data := map[string]interface{}{} + e.SetExtension("test", "hello") + ceCtx := &context.EventContext{ + Event: &e, + Data: data, + } + err = a.Execute(ceCtx) + So(err, ShouldBeNil) + res, ok := data["target"] + So(ok, ShouldBeTrue) + So(res, ShouldResemble, []string{"hello", ""}) }) - Convey("test split from start: Negative testcase, split position greater than string length", t, func() { - a, err := runtime.NewAction([]interface{}{funcName, "$.test", 100, "$.data.target"}) + Convey("test split from start: Negative testcase, split position less than one", t, func() { + a, err := runtime.NewAction([]interface{}{funcName, "$.test", 0, "$.data.target"}) So(err, ShouldBeNil) e := cetest.MinEvent() data := map[string]interface{}{} - e.SetExtension("test", "split position must be less than the length of the string") + e.SetExtension("test", "split position must be more than zero") ceCtx := &context.EventContext{ Event: &e, Data: data, } err = a.Execute(ceCtx) So(err, ShouldNotBeNil) - So(e.Extensions()["test"], ShouldEqual, "split position must be less than the length of the string") + So(e.Extensions()["test"], ShouldEqual, "split position must be more than zero") }) } diff --git a/internal/primitive/transform/function/strings_functions.go b/internal/primitive/transform/function/strings_functions.go index de3010f2b..0016b4fe4 100644 --- a/internal/primitive/transform/function/strings_functions.go +++ b/internal/primitive/transform/function/strings_functions.go @@ -147,15 +147,15 @@ var SplitFromStart = function{ fn: func(args []interface{}) (interface{}, error) { value, _ := args[0].(string) splitPosition, _ := args[1].(int) - if len(value) < 2 { - return []string{value}, nil - } - if splitPosition < 1 { + + if splitPosition <= 0 { return nil, fmt.Errorf("split position must be more than zero") } + if splitPosition >= len(value) { - return nil, fmt.Errorf("split position must be less than the length of the string") + return []string{value, ""}, nil } + result := []string{value[:splitPosition], value[splitPosition:]} return result, nil },