Files
streamsql/functions/functions_multirow.go
2025-06-11 18:45:39 +08:00

109 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package functions
import (
"fmt"
"reflect"
)
// UnnestFunction 将数组展开为多行
type UnnestFunction struct {
*BaseFunction
}
func NewUnnestFunction() *UnnestFunction {
return &UnnestFunction{
BaseFunction: NewBaseFunction("unnest", TypeString, "多行函数", "将数组展开为多行", 1, 1),
}
}
func (f *UnnestFunction) Validate(args []interface{}) error {
return f.ValidateArgCount(args)
}
func (f *UnnestFunction) Execute(ctx *FunctionContext, args []interface{}) (interface{}, error) {
if err := f.Validate(args); err != nil {
return nil, err
}
array := args[0]
if array == nil {
return []interface{}{}, nil
}
// 使用反射检查是否为数组或切片
v := reflect.ValueOf(array)
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
return nil, fmt.Errorf("unnest requires an array or slice, got %T", array)
}
// 转换为 []interface{}
result := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
elem := v.Index(i).Interface()
// 如果数组元素是对象map则展开为列
if elemMap, ok := elem.(map[string]interface{}); ok {
// 对于对象,我们返回一个特殊的结构来表示需要展开为列
result[i] = map[string]interface{}{
"__unnest_object__": true,
"__data__": elemMap,
}
} else {
result[i] = elem
}
}
return result, nil
}
// UnnestResult 表示 unnest 函数的结果
type UnnestResult struct {
Rows []map[string]interface{}
}
// IsUnnestResult 检查是否为 unnest 结果
func IsUnnestResult(value interface{}) bool {
if slice, ok := value.([]interface{}); ok {
for _, item := range slice {
if itemMap, ok := item.(map[string]interface{}); ok {
if unnest, exists := itemMap["__unnest_object__"]; exists {
if unnestBool, ok := unnest.(bool); ok && unnestBool {
return true
}
}
}
}
}
return false
}
// ProcessUnnestResult 处理 unnest 结果,将其转换为多行
func ProcessUnnestResult(value interface{}) []map[string]interface{} {
slice, ok := value.([]interface{})
if !ok {
return nil
}
var rows []map[string]interface{}
for _, item := range slice {
if itemMap, ok := item.(map[string]interface{}); ok {
if unnest, exists := itemMap["__unnest_object__"]; exists {
if unnestBool, ok := unnest.(bool); ok && unnestBool {
if data, exists := itemMap["__data__"]; exists {
if dataMap, ok := data.(map[string]interface{}); ok {
rows = append(rows, dataMap)
}
}
continue
}
}
}
// 对于非对象元素,创建一个包含单个值的行
row := map[string]interface{}{
"value": item,
}
rows = append(rows, row)
}
return rows
}