Files
streamsql/functions/expr_bridge.go
T
2025-05-29 14:42:21 +08:00

466 lines
16 KiB
Go

package functions
import (
"fmt"
"strconv"
"strings"
"github.com/expr-lang/expr"
"github.com/expr-lang/expr/vm"
"github.com/rulego/streamsql/utils/cast"
)
// ExprBridge 桥接 StreamSQL 函数系统与 expr-lang/expr
type ExprBridge struct {
streamSQLFunctions map[string]Function
exprProgram *vm.Program
exprEnv map[string]interface{}
}
// NewExprBridge 创建新的表达式桥接器
func NewExprBridge() *ExprBridge {
return &ExprBridge{
streamSQLFunctions: ListAll(),
exprEnv: make(map[string]interface{}),
}
}
// RegisterStreamSQLFunctionsToExpr 将StreamSQL函数注册到expr环境中
func (bridge *ExprBridge) RegisterStreamSQLFunctionsToExpr() []expr.Option {
options := make([]expr.Option, 0)
// 将所有StreamSQL函数注册到expr环境
for name, fn := range bridge.streamSQLFunctions {
// 为了避免闭包问题,创建局部变量
funcName := name
function := fn
// 将StreamSQL函数包装为expr兼容的函数
wrappedFunc := func(params ...interface{}) (interface{}, error) {
ctx := &FunctionContext{
Data: bridge.exprEnv,
}
return function.Execute(ctx, params)
}
// 添加函数到expr环境
bridge.exprEnv[funcName] = wrappedFunc
// 注册函数类型信息
options = append(options, expr.Function(
funcName,
wrappedFunc,
))
}
return options
}
// CreateEnhancedExprEnvironment 创建增强的expr执行环境
func (bridge *ExprBridge) CreateEnhancedExprEnvironment(data map[string]interface{}) map[string]interface{} {
// 合并数据和函数环境
env := make(map[string]interface{})
// 添加用户数据
for k, v := range data {
env[k] = v
}
// 添加所有StreamSQL函数
for name, fn := range bridge.streamSQLFunctions {
funcName := name
function := fn
wrappedFunc := func(params ...interface{}) (interface{}, error) {
ctx := &FunctionContext{
Data: data, // 使用当前数据上下文
}
return function.Execute(ctx, params)
}
// 注册小写版本
env[funcName] = wrappedFunc
// 注册大写版本
env[strings.ToUpper(funcName)] = wrappedFunc
}
// 添加一些便捷的数学函数别名,避免与内置冲突
env["streamsql_abs"] = env["abs"]
env["streamsql_sqrt"] = env["sqrt"]
env["streamsql_min"] = env["min"]
env["streamsql_max"] = env["max"]
return env
}
// CompileExpressionWithStreamSQLFunctions 编译表达式,包含StreamSQL函数
func (bridge *ExprBridge) CompileExpressionWithStreamSQLFunctions(expression string, dataType interface{}) (*vm.Program, error) {
options := []expr.Option{
expr.Env(dataType),
}
// 添加StreamSQL函数
streamSQLOptions := bridge.RegisterStreamSQLFunctionsToExpr()
options = append(options, streamSQLOptions...)
// 启用一些有用的expr功能
options = append(options,
expr.AllowUndefinedVariables(), // 允许未定义变量
expr.AsBool(), // 期望布尔结果(可根据需要调整)
)
return expr.Compile(expression, options...)
}
// EvaluateExpression 评估表达式,自动选择最合适的引擎
func (bridge *ExprBridge) EvaluateExpression(expression string, data map[string]interface{}) (interface{}, error) {
// 首先检查是否包含字符串拼接模式
if bridge.isStringConcatenationExpression(expression, data) {
result, err := bridge.evaluateStringConcatenation(expression, data)
if err == nil {
return result, nil
}
}
// 尝试使用编译后的程序执行(包含StreamSQL函数)
program, err := bridge.CompileExpressionWithStreamSQLFunctions(expression, data)
if err == nil {
// 创建增强环境
env := bridge.CreateEnhancedExprEnvironment(data)
result, err := expr.Run(program, env)
if err == nil {
return result, nil
}
}
// 如果编译失败,尝试直接使用expr.Eval
env := bridge.CreateEnhancedExprEnvironment(data)
result, err := expr.Eval(expression, env)
if err != nil {
// 如果expr失败,回退到自定义expr系统(仅限数值计算)
return bridge.fallbackToCustomExpr(expression, data)
}
return result, nil
}
// isStringConcatenationExpression 检查是否是字符串拼接表达式
func (bridge *ExprBridge) isStringConcatenationExpression(expression string, data map[string]interface{}) bool {
// 如果表达式包含 + 操作符
if !strings.Contains(expression, "+") {
return false
}
// 分析表达式中的操作数
parts := strings.Split(expression, "+")
for _, part := range parts {
part = strings.TrimSpace(part)
// 如果包含字符串字面量(用引号包围)
if (strings.HasPrefix(part, "'") && strings.HasSuffix(part, "'")) ||
(strings.HasPrefix(part, "\"") && strings.HasSuffix(part, "\"")) ||
part == "_" {
return true
}
// 如果是字段引用,检查字段值是否为字符串
if value, exists := data[part]; exists {
if _, isString := value.(string); isString {
return true
}
}
}
return false
}
// fallbackToCustomExpr 回退到自定义表达式系统
func (bridge *ExprBridge) fallbackToCustomExpr(expression string, data map[string]interface{}) (interface{}, error) {
// 尝试处理字符串拼接表达式
result, err := bridge.evaluateStringConcatenation(expression, data)
if err == nil {
return result, nil
}
// 如果不是字符串拼接,尝试简单的数值表达式
numResult, err := bridge.evaluateSimpleNumericExpression(expression, data)
if err == nil {
return numResult, nil
}
return nil, fmt.Errorf("unable to evaluate expression: %s, string concat error: %v, numeric error: %v", expression, err, err)
}
// evaluateStringConcatenation 处理字符串拼接表达式
func (bridge *ExprBridge) evaluateStringConcatenation(expression string, data map[string]interface{}) (interface{}, error) {
// 检查是否是字符串拼接表达式 (包含 + 和字符串字面量)
if !strings.Contains(expression, "+") {
return nil, fmt.Errorf("not a concatenation expression")
}
// 简单的字符串拼接解析器
// 支持格式: field1 + 'literal' + field2 或 field1 + "_" + field2
parts := strings.Split(expression, "+")
var result strings.Builder
for _, part := range parts {
part = strings.TrimSpace(part)
// 处理字符串字面量 (用单引号包围)
if strings.HasPrefix(part, "'") && strings.HasSuffix(part, "'") {
literal := strings.Trim(part, "'")
result.WriteString(literal)
} else if strings.HasPrefix(part, "\"") && strings.HasSuffix(part, "\"") {
literal := strings.Trim(part, "\"")
result.WriteString(literal)
} else if part == "_" {
// 处理下划线字面量
result.WriteString("_")
} else {
// 处理字段引用
if value, exists := data[part]; exists {
strValue := cast.ToString(value)
result.WriteString(strValue)
} else {
return nil, fmt.Errorf("field %s not found in data", part)
}
}
}
return result.String(), nil
}
// evaluateSimpleNumericExpression 处理简单的数值表达式
func (bridge *ExprBridge) evaluateSimpleNumericExpression(expression string, data map[string]interface{}) (interface{}, error) {
expression = strings.TrimSpace(expression)
// 处理简单的字段引用
if value, exists := data[expression]; exists {
return value, nil
}
// 处理数字字面量
if num, err := strconv.ParseFloat(expression, 64); err == nil {
return num, nil
}
// 处理简单的数学运算 (例如: field * 2, field + 5)
for _, op := range []string{"+", "-", "*", "/"} {
if strings.Contains(expression, op) {
parts := strings.Split(expression, op)
if len(parts) == 2 {
left := strings.TrimSpace(parts[0])
right := strings.TrimSpace(parts[1])
// 获取左值
var leftVal float64
if val, exists := data[left]; exists {
if f, err := bridge.toFloat64(val); err == nil {
leftVal = f
} else {
return nil, fmt.Errorf("cannot convert left operand to number: %v", val)
}
} else if f, err := strconv.ParseFloat(left, 64); err == nil {
leftVal = f
} else {
continue // 尝试下一个操作符
}
// 获取右值
var rightVal float64
if val, exists := data[right]; exists {
if f, err := bridge.toFloat64(val); err == nil {
rightVal = f
} else {
return nil, fmt.Errorf("cannot convert right operand to number: %v", val)
}
} else if f, err := strconv.ParseFloat(right, 64); err == nil {
rightVal = f
} else {
continue // 尝试下一个操作符
}
// 执行运算
switch op {
case "+":
return leftVal + rightVal, nil
case "-":
return leftVal - rightVal, nil
case "*":
return leftVal * rightVal, nil
case "/":
if rightVal == 0 {
return nil, fmt.Errorf("division by zero")
}
return leftVal / rightVal, nil
}
}
}
}
return nil, fmt.Errorf("unsupported expression: %s", expression)
}
// toFloat64 将值转换为float64
func (bridge *ExprBridge) toFloat64(val interface{}) (float64, error) {
switch v := val.(type) {
case float64:
return v, nil
case float32:
return float64(v), nil
case int:
return float64(v), nil
case int32:
return float64(v), nil
case int64:
return float64(v), nil
case string:
return strconv.ParseFloat(v, 64)
default:
return 0, fmt.Errorf("cannot convert %T to float64", val)
}
}
// GetFunctionInfo 获取函数信息,统一两个系统的函数
func (bridge *ExprBridge) GetFunctionInfo() map[string]interface{} {
info := make(map[string]interface{})
// StreamSQL函数信息
streamSQLFuncs := make(map[string]interface{})
for name, fn := range bridge.streamSQLFunctions {
streamSQLFuncs[name] = map[string]interface{}{
"name": fn.GetName(),
"type": fn.GetType(),
"category": fn.GetCategory(),
"description": fn.GetDescription(),
"source": "StreamSQL",
}
}
info["streamsql"] = streamSQLFuncs
// expr-lang/expr内置函数(列出主要的)
exprBuiltins := map[string]interface{}{
// 数学函数
"abs": map[string]interface{}{"category": "math", "description": "absolute value", "source": "expr-lang"},
"ceil": map[string]interface{}{"category": "math", "description": "ceiling", "source": "expr-lang"},
"floor": map[string]interface{}{"category": "math", "description": "floor", "source": "expr-lang"},
"round": map[string]interface{}{"category": "math", "description": "round", "source": "expr-lang"},
"max": map[string]interface{}{"category": "math", "description": "maximum", "source": "expr-lang"},
"min": map[string]interface{}{"category": "math", "description": "minimum", "source": "expr-lang"},
// 字符串函数
"trim": map[string]interface{}{"category": "string", "description": "trim whitespace", "source": "expr-lang"},
"upper": map[string]interface{}{"category": "string", "description": "to uppercase", "source": "expr-lang"},
"lower": map[string]interface{}{"category": "string", "description": "to lowercase", "source": "expr-lang"},
"split": map[string]interface{}{"category": "string", "description": "split string", "source": "expr-lang"},
"replace": map[string]interface{}{"category": "string", "description": "replace substring", "source": "expr-lang"},
"indexOf": map[string]interface{}{"category": "string", "description": "find index", "source": "expr-lang"},
"hasPrefix": map[string]interface{}{"category": "string", "description": "check prefix", "source": "expr-lang"},
"hasSuffix": map[string]interface{}{"category": "string", "description": "check suffix", "source": "expr-lang"},
// 数组/集合函数
"all": map[string]interface{}{"category": "array", "description": "all elements satisfy", "source": "expr-lang"},
"any": map[string]interface{}{"category": "array", "description": "any element satisfies", "source": "expr-lang"},
"filter": map[string]interface{}{"category": "array", "description": "filter elements", "source": "expr-lang"},
"map": map[string]interface{}{"category": "array", "description": "transform elements", "source": "expr-lang"},
"find": map[string]interface{}{"category": "array", "description": "find element", "source": "expr-lang"},
"count": map[string]interface{}{"category": "array", "description": "count elements", "source": "expr-lang"},
"concat": map[string]interface{}{"category": "array", "description": "concatenate arrays", "source": "expr-lang"},
"flatten": map[string]interface{}{"category": "array", "description": "flatten array", "source": "expr-lang"},
// 时间函数
"now": map[string]interface{}{"category": "datetime", "description": "current time", "source": "expr-lang"},
"duration": map[string]interface{}{"category": "datetime", "description": "parse duration", "source": "expr-lang"},
"date": map[string]interface{}{"category": "datetime", "description": "parse date", "source": "expr-lang"},
// 类型转换
"int": map[string]interface{}{"category": "conversion", "description": "to integer", "source": "expr-lang"},
"float": map[string]interface{}{"category": "conversion", "description": "to float", "source": "expr-lang"},
"string": map[string]interface{}{"category": "conversion", "description": "to string", "source": "expr-lang"},
"type": map[string]interface{}{"category": "conversion", "description": "get type", "source": "expr-lang"},
// JSON处理
"toJSON": map[string]interface{}{"category": "json", "description": "to JSON", "source": "expr-lang"},
"fromJSON": map[string]interface{}{"category": "json", "description": "from JSON", "source": "expr-lang"},
// Base64编码
"toBase64": map[string]interface{}{"category": "encoding", "description": "to Base64", "source": "expr-lang"},
"fromBase64": map[string]interface{}{"category": "encoding", "description": "from Base64", "source": "expr-lang"},
}
info["expr-lang"] = exprBuiltins
return info
}
// ResolveFunction 解析函数调用,优先使用StreamSQL函数
func (bridge *ExprBridge) ResolveFunction(name string) (interface{}, bool, string) {
// 进行大小写不敏感的查找
lowerName := strings.ToLower(name)
// 首先检查StreamSQL函数(优先级更高)
if fn, exists := bridge.streamSQLFunctions[lowerName]; exists {
return fn, true, "streamsql"
}
// 然后检查是否是expr-lang内置函数
exprBuiltins := []string{
"abs", "ceil", "floor", "round", "max", "min", // math
"trim", "upper", "lower", "split", "replace", "indexOf", "hasPrefix", "hasSuffix", // string
"all", "any", "filter", "map", "find", "count", "flatten", // array (移除concat)
"now", "duration", "date", // time
"int", "float", "string", "type", // conversion
"toJSON", "fromJSON", "toBase64", "fromBase64", // encoding
"len", "get", // misc
}
for _, builtin := range exprBuiltins {
if strings.ToLower(builtin) == lowerName {
return nil, true, "expr-lang" // expr-lang会自动处理
}
}
return nil, false, ""
}
// IsExprLangFunction 检查函数名是否是expr-lang内置函数
func (bridge *ExprBridge) IsExprLangFunction(name string) bool {
// expr-lang内置函数列表(移除concat避免冲突)
exprBuiltins := []string{
"abs", "ceil", "floor", "round", "max", "min", // math
"trim", "upper", "lower", "split", "replace", "indexOf", "hasPrefix", "hasSuffix", // string
"all", "any", "filter", "map", "find", "count", "flatten", // array (移除concat)
"now", "duration", "date", // time
"int", "float", "string", "type", // conversion
"toJSON", "fromJSON", "toBase64", "fromBase64", // encoding
"len", "get", // misc
}
for _, builtin := range exprBuiltins {
if builtin == name {
return true
}
}
return false
}
// 全局桥接器实例
var globalBridge *ExprBridge
// GetExprBridge 获取全局桥接器实例
func GetExprBridge() *ExprBridge {
if globalBridge == nil {
globalBridge = NewExprBridge()
}
return globalBridge
}
// 便捷函数:直接评估表达式
func EvaluateWithBridge(expression string, data map[string]interface{}) (interface{}, error) {
return GetExprBridge().EvaluateExpression(expression, data)
}
// 便捷函数:获取所有可用函数信息
func GetAllAvailableFunctions() map[string]interface{} {
return GetExprBridge().GetFunctionInfo()
}