Skip to content

Commit

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

Signed-off-by: Rui-Gan <[email protected]>

* add docs

Signed-off-by: Rui-Gan <[email protected]>

* fix lint

Signed-off-by: Rui-Gan <[email protected]>

---------

Signed-off-by: Rui-Gan <[email protected]>
  • Loading branch information
Rui-Gan committed Aug 4, 2023
1 parent 94283f3 commit f5aff7a
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 0 deletions.
18 changes: 18 additions & 0 deletions docs/en_US/sqls/functions/object_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,21 @@ result:
```sql
{"a":1, "b":2}
```

## OBJECT_CONCAT

```text
object_concat(obj1, obj2, ...)
```

This function concatenates the input objects and returns a new object. It requires a minimum of two input objects. In cases where there are duplicate attribute names among the input objects, the attribute from the last relevant object in the input list is selected and copied to the output object. To illustrate, here's an example:

```sql
object_concat({"a": 1}, {"b": 2}, {"b": 3})
```

result:

```sql
{"a":1, "b":3}
```
18 changes: 18 additions & 0 deletions docs/zh_CN/sqls/functions/object_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,21 @@ object_construct("a", 1, "b", 2)
```sql
{"a":1, "b":2}
```

## OBJECT_CONCAT

```text
object_concat(obj1, obj2, ...)
```

该函数是一个连接输入对象并返回新对象的函数。该函数至少需要两个输入对象作为参数。当输入对象中存在相同属性名称时,函数将选择输入列表中最后一个相关对象的属性,并将其复制到输出对象中。以下是一个示例:

```sql
object_concat({"a": 1}, {"b": 2}, {"b": 3})
```

得到如下结果:

```sql
{"a":1, "b":3}
```
20 changes: 20 additions & 0 deletions internal/binder/function/funcs_obj.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,24 @@ func registerObjectFunc() {
val: ValidateOneArg,
check: returnNilIfHasAnyNil,
}
builtins["object_concat"] = builtinFunc{
fType: ast.FuncTypeScalar,
exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
res := make(map[string]interface{})
for i, arg := range args {
arg, ok := arg.(map[string]interface{})
if !ok {
return fmt.Errorf("the argument should be map[string]interface{}, got %v", args[i]), false
}
for k, v := range arg {
res[k] = v
}
}
return res, true
},
val: func(_ api.FunctionContext, args []ast.Expr) error {
return ValidateAtLeast(2, len(args))
},
check: returnNilIfHasAnyNil,
}
}
41 changes: 41 additions & 0 deletions internal/binder/function/funcs_obj_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,47 @@ func TestObjectFunctions(t *testing.T) {
},
result: fmt.Errorf("second argument should be string"),
},
{
name: "object_concat",
args: []interface{}{
map[string]interface{}{
"a": 1,
"b": 2,
},
map[string]interface{}{
"b": 3,
"c": 4,
},
map[string]interface{}{
"a": 2,
"d": 1,
},
},
result: map[string]interface{}{
"a": 2,
"b": 3,
"c": 4,
"d": 1,
},
},
{
name: "object_concat",
args: []interface{}{
map[string]interface{}{
"a": 1,
"b": 2,
},
map[string]interface{}{
"b": 3,
"c": 4,
},
[]interface{}{
1,
2,
},
},
result: fmt.Errorf("the argument should be map[string]interface{}, got %v", []interface{}{1, 2}),
},
}
for i, tt := range tests {
f, ok := builtins[tt.name]
Expand Down

0 comments on commit f5aff7a

Please sign in to comment.