Browse Source

feat(func): support array_concat (#1999)

* feat: support array_concat function

Signed-off-by: Yaid <sunzhenyucn@gmail.com>

* test: add unit tests for array_concat

Signed-off-by: Yaid <sunzhenyucn@gmail.com>

* docs(func): add docs for array_concat

Signed-off-by: Yaid <sunzhenyucn@gmail.com>

* docs(func): add missing type annotation for clode blocks

Signed-off-by: Yaid <sunzhenyucn@gmail.com>

---------

Signed-off-by: Yaid <sunzhenyucn@gmail.com>
Yaid 1 year ago
parent
commit
c4a649eb45

+ 8 - 0
docs/en_US/sqls/functions/array_functions.md

@@ -125,3 +125,11 @@ sequence(start, stop, step)
 ```
 
 Returns an array of integers from start to stop, incrementing by step.
+
+## ARRAY_CONCAT
+
+```text
+array_concat(array1, array2, ...)
+```
+
+Returns the concatenation of the input arrays, this function does not modify the existing arrays, but returns new one.

+ 8 - 0
docs/zh_CN/sqls/functions/array_functions.md

@@ -122,3 +122,11 @@ sequence(start, stop[, step])
 
 返回一个从第一个开始参数到第二个结束参数的整数列表,每个元素按照给定的步长递增或递减。若未提供步长,则默认为
 1(如果第一个开始参数小于第二个结束参数),或 -1(如果第一个开始参数大于第二个结束参数),且步长不允许为 0。
+
+## ARRAY_CONCAT
+
+```text
+array_concat(array1, array2, ...)
+```
+
+用于合并两个或多个数组。此函数不会更改现有数组,而是返回一个新的数组。

+ 25 - 0
internal/binder/function/funcs_array.go

@@ -18,6 +18,7 @@ import (
 	"fmt"
 	"math"
 	"math/rand"
+	"reflect"
 	"strings"
 
 	"github.com/lf-edge/ekuiper/pkg/api"
@@ -637,4 +638,28 @@ func registerArrayFunc() {
 		},
 		check: returnNilIfHasAnyNil,
 	}
+	builtins["array_concat"] = builtinFunc{
+		fType: ast.FuncTypeScalar,
+		exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
+			var res []interface{}
+
+			for _, arg := range args {
+				v := reflect.ValueOf(arg)
+
+				switch v.Kind() {
+				case reflect.Slice:
+					array := arg.([]interface{})
+					res = append(res, array...)
+				default:
+					return errorArrayNotArrayElementError, false
+				}
+			}
+
+			return res, true
+		},
+		val: func(ctx api.FunctionContext, args []ast.Expr) error {
+			return ValidateAtLeast(1, len(args))
+		},
+		check: returnNilIfHasAnyNil,
+	}
 }

+ 20 - 0
internal/binder/function/funcs_array_test.go

@@ -690,6 +690,26 @@ func TestArrayCommonFunctions(t *testing.T) {
 			},
 			result: "a,b",
 		},
+		{
+			name: "array_concat",
+			args: []interface{}{
+				[]interface{}{1},
+				[]interface{}{2},
+				[]interface{}{"3"},
+				[]interface{}{nil},
+			},
+			result: []interface{}{
+				1, 2, "3", nil,
+			},
+		},
+		{
+			name: "array_concat",
+			args: []interface{}{
+				[]interface{}{1},
+				nil,
+			},
+			result: errorArrayNotArrayElementError,
+		},
 	}
 	for i, tt := range tests {
 		f, ok := builtins[tt.name]

+ 7 - 0
internal/binder/function/validator_funcs.go

@@ -35,6 +35,13 @@ func ValidateLen(exp, actual int) error {
 	return nil
 }
 
+func ValidateAtLeast(min, actual int) error {
+	if actual < min {
+		return fmt.Errorf("At least has %d argument but found %d.", min, actual)
+	}
+	return nil
+}
+
 // Shared validating functions
 
 func ValidateNoArg(_ api.FunctionContext, args []ast.Expr) error {