Files
streamsql/functions/expr_bridge.go
T
2025-08-07 19:23:48 +08:00

785 lines
26 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"
"regexp"
"strconv"
"strings"
"sync"
"github.com/expr-lang/expr"
"github.com/expr-lang/expr/vm"
"github.com/rulego/streamsql/utils/cast"
)
// ExprBridge bridges StreamSQL function system with expr-lang/expr
type ExprBridge struct {
streamSQLFunctions map[string]Function
exprProgram *vm.Program
exprEnv map[string]interface{}
mutex sync.RWMutex // Add read-write lock to protect concurrent access
}
// NewExprBridge creates new expression bridge
func NewExprBridge() *ExprBridge {
return &ExprBridge{
streamSQLFunctions: make(map[string]Function), // Initialize as empty, dynamically get
exprEnv: make(map[string]interface{}),
}
}
// RegisterStreamSQLFunctionsToExpr registers StreamSQL functions to expr environment
func (bridge *ExprBridge) RegisterStreamSQLFunctionsToExpr() []expr.Option {
bridge.mutex.Lock()
defer bridge.mutex.Unlock()
options := make([]expr.Option, 0)
// Dynamically get all currently registered functions
allFunctions := ListAll()
// Register all StreamSQL functions to expr environment
for name, fn := range allFunctions {
// To avoid closure issues, use immediately executed function
function := fn
wrappedFunc := func(function Function) func(params ...interface{}) (interface{}, error) {
return func(params ...interface{}) (interface{}, error) {
ctx := &FunctionContext{
Data: bridge.exprEnv,
}
return function.Execute(ctx, params)
}
}(function)
// Add function to expr environment
bridge.exprEnv[name] = wrappedFunc
// Register function type information
options = append(options, expr.Function(
name,
wrappedFunc,
))
}
return options
}
// CreateEnhancedExprEnvironment creates enhanced expr execution environment
func (bridge *ExprBridge) CreateEnhancedExprEnvironment(data map[string]interface{}) map[string]interface{} {
bridge.mutex.RLock()
defer bridge.mutex.RUnlock()
// Merge data and function environment
env := make(map[string]interface{})
// Add user data
for k, v := range data {
env[k] = v
}
// Dynamically get all currently registered functions
allFunctions := ListAll()
// Add all StreamSQL functions
for name, fn := range allFunctions {
// Ensure closure captures correct function instance
function := fn
wrappedFunc := func(function Function) func(params ...interface{}) (interface{}, error) {
return func(params ...interface{}) (interface{}, error) {
ctx := &FunctionContext{
Data: data, // Use current data context
}
return function.Execute(ctx, params)
}
}(function)
// Register lowercase version
env[name] = wrappedFunc
// Register uppercase version
env[strings.ToUpper(name)] = wrappedFunc
}
// Add some convenient math function aliases to avoid conflicts with built-ins
env["streamsql_abs"] = env["abs"]
env["streamsql_sqrt"] = env["sqrt"]
env["streamsql_min"] = env["min"]
env["streamsql_max"] = env["max"]
// Add custom LIKE matching function
env["like_match"] = func(text, pattern string) bool {
return bridge.matchesLikePattern(text, pattern)
}
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...)
// 添加LIKE相关的自定义函数只需要like_match其他是内置操作符
options = append(options,
expr.Function("like_match", func(params ...any) (any, error) {
if len(params) != 2 {
return false, fmt.Errorf("like_match function requires 2 parameters")
}
text, ok1 := params[0].(string)
pattern, ok2 := params[1].(string)
if !ok1 || !ok2 {
return false, fmt.Errorf("like_match function requires string parameters")
}
return bridge.matchesLikePattern(text, pattern), nil
}),
)
// 启用一些有用的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.ContainsBacktickIdentifiers(expression) {
processedExpr, err := bridge.PreprocessBacktickIdentifiers(expression)
if err == nil {
expression = processedExpr
}
}
// 检查是否包含LIKE操作符如果有则进行预处理
if bridge.ContainsLikeOperator(expression) {
processedExpr, err := bridge.PreprocessLikeExpression(expression)
if err == nil {
expression = processedExpr
}
}
// 检查是否包含IS NULL或IS NOT NULL操作符如果有则进行预处理
if bridge.ContainsIsNullOperator(expression) {
processedExpr, err := bridge.PreprocessIsNullExpression(expression)
if err == nil {
expression = processedExpr
}
}
// 检查是否包含字符串拼接模式
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 {
// 检查是否是函数调用,如果是则不要回退到数值表达式处理
if bridge.isFunctionCall(expression) {
return nil, fmt.Errorf("failed to evaluate function call '%s': %v", expression, err)
}
// 如果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)
}
// ContainsLikeOperator 检查表达式是否包含LIKE操作符
func (bridge *ExprBridge) ContainsLikeOperator(expression string) bool {
// 简单检查是否包含LIKE关键字
upperExpr := strings.ToUpper(expression)
return strings.Contains(upperExpr, " LIKE ")
}
// ContainsIsNullOperator 检查表达式是否包含IS NULL或IS NOT NULL操作符
func (bridge *ExprBridge) ContainsIsNullOperator(expression string) bool {
upperExpr := strings.ToUpper(expression)
return strings.Contains(upperExpr, " IS NULL") || strings.Contains(upperExpr, " IS NOT NULL")
}
// isFunctionCall 检查表达式是否是函数调用
func (bridge *ExprBridge) isFunctionCall(expression string) bool {
// 如果是CASE表达式则不是函数调用
trimmed := strings.TrimSpace(expression)
upperTrimmed := strings.ToUpper(trimmed)
if strings.HasPrefix(upperTrimmed, "CASE ") || strings.HasPrefix(upperTrimmed, "CASE\t") || strings.HasPrefix(upperTrimmed, "CASE\n") {
return false
}
// 检查是否符合简单函数调用模式: function_name(args)
// 函数调用应该以标识符开始,后跟括号
if !strings.Contains(expression, "(") || !strings.Contains(expression, ")") {
return false
}
// 检查是否以标识符开始(函数名)
for i, r := range trimmed {
if i == 0 {
if !((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || r == '_') {
return false
}
} else if r == '(' {
// 找到了开括号,说明这可能是函数调用
return true
} else if !((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_') {
// 遇到了非标识符字符且不是开括号,说明不是简单函数调用
return false
}
}
return false
}
// PreprocessLikeExpression 预处理LIKE表达式转换为expr-lang可理解的函数调用
func (bridge *ExprBridge) PreprocessLikeExpression(expression string) (string, error) {
// 使用正则表达式匹配LIKE模式
// 匹配: field LIKE 'pattern' 或 `field` LIKE 'pattern' (允许空模式)
// 支持反引号标识符和普通标识符
likePattern := `((?:` + "`" + `[^` + "`" + `]+` + "`" + `|\w+)(?:\.(?:` + "`" + `[^` + "`" + `]+` + "`" + `|\w+))*)\s+LIKE\s+'([^']*)'`
re, err := regexp.Compile(likePattern)
if err != nil {
return expression, err
}
// 替换所有LIKE表达式
result := re.ReplaceAllStringFunc(expression, func(match string) string {
submatches := re.FindStringSubmatch(match)
if len(submatches) != 3 {
return match // 保持原样
}
field := submatches[1]
pattern := submatches[2]
// 处理反引号标识符,去除反引号
if len(field) >= 2 && field[0] == '`' && field[len(field)-1] == '`' {
field = field[1 : len(field)-1] // 去掉反引号
}
// 将LIKE模式转换为相应的函数调用
return bridge.convertLikeToFunction(field, pattern)
})
return result, nil
}
// PreprocessIsNullExpression 预处理IS NULL和IS NOT NULL表达式转换为expr-lang可理解的表达式
func (bridge *ExprBridge) PreprocessIsNullExpression(expression string) (string, error) {
// 匹配复杂表达式的 IS NOT NULL 模式 (如函数调用)
complexNotNullPattern := `([A-Za-z_][A-Za-z0-9_]*\s*\([^)]*\))\s+IS\s+NOT\s+NULL`
reComplexNotNull, err := regexp.Compile(complexNotNullPattern)
if err != nil {
return expression, err
}
// 先处理复杂表达式的IS NOT NULL
result := reComplexNotNull.ReplaceAllString(expression, "is_not_null($1)")
// 匹配复杂表达式的 IS NULL 模式
complexNullPattern := `([A-Za-z_][A-Za-z0-9_]*\s*\([^)]*\))\s+IS\s+NULL`
reComplexNull, err := regexp.Compile(complexNullPattern)
if err != nil {
return result, err
}
// 处理复杂表达式的IS NULL
result = reComplexNull.ReplaceAllString(result, "is_null($1)")
// 匹配简单字段的 IS NOT NULL 模式 (必须在复杂表达式之后处理)
isNotNullPattern := `(\w+(?:\.\w+)*)\s+IS\s+NOT\s+NULL`
reNotNull, err := regexp.Compile(isNotNullPattern)
if err != nil {
return result, err
}
// 替换简单字段的IS NOT NULL
result = reNotNull.ReplaceAllString(result, "$1 != nil")
// 匹配简单字段的 IS NULL 模式
isNullPattern := `(\w+(?:\.\w+)*)\s+IS\s+NULL`
reNull, err := regexp.Compile(isNullPattern)
if err != nil {
return result, err
}
// 再替换简单字段的IS NULL
result = reNull.ReplaceAllString(result, "$1 == nil")
return result, nil
}
// ContainsBacktickIdentifiers 检查表达式是否包含反引号标识符
func (bridge *ExprBridge) ContainsBacktickIdentifiers(expression string) bool {
return strings.Contains(expression, "`")
}
// PreprocessBacktickIdentifiers 预处理反引号标识符,去除反引号
func (bridge *ExprBridge) PreprocessBacktickIdentifiers(expression string) (string, error) {
// 使用正则表达式匹配反引号标识符
// 匹配: `identifier` 或 `nested.field`
backtickPattern := "`([^`]+)`"
re, err := regexp.Compile(backtickPattern)
if err != nil {
return expression, err
}
// 替换所有反引号标识符,去除反引号
result := re.ReplaceAllString(expression, "$1")
return result, nil
}
// convertLikeToFunction 将LIKE模式转换为expr-lang操作符
func (bridge *ExprBridge) convertLikeToFunction(field, pattern string) string {
// 处理空模式
if pattern == "" {
return fmt.Sprintf("%s == ''", field)
}
// 分析模式类型
if strings.HasPrefix(pattern, "%") && strings.HasSuffix(pattern, "%") && len(pattern) > 1 {
// %pattern% -> contains操作符但不是单独的%
inner := strings.Trim(pattern, "%")
if inner == "" {
// %% 表示匹配任何字符串
return "true"
}
return fmt.Sprintf("%s contains '%s'", field, inner)
} else if strings.HasPrefix(pattern, "%") && len(pattern) > 1 {
// %pattern -> endsWith操作符
suffix := strings.TrimPrefix(pattern, "%")
return fmt.Sprintf("%s endsWith '%s'", field, suffix)
} else if strings.HasSuffix(pattern, "%") && len(pattern) > 1 {
// pattern% -> startsWith操作符
prefix := strings.TrimSuffix(pattern, "%")
return fmt.Sprintf("%s startsWith '%s'", field, prefix)
} else if pattern == "%" {
// 单独的%匹配任何字符串
return "true"
} else if strings.Contains(pattern, "%") || strings.Contains(pattern, "_") {
// 复杂模式如prefix%suffix或包含单字符通配符使用自定义的like_match函数
return fmt.Sprintf("like_match(%s, '%s')", field, pattern)
} else {
// 精确匹配
return fmt.Sprintf("%s == '%s'", field, pattern)
}
}
// matchesLikePattern 实现LIKE模式匹配
// 支持%匹配任意字符序列和_匹配单个字符
func (bridge *ExprBridge) matchesLikePattern(text, pattern string) bool {
return bridge.likeMatch(text, pattern, 0, 0)
}
// likeMatch 递归实现LIKE匹配算法
func (bridge *ExprBridge) likeMatch(text, pattern string, textIndex, patternIndex int) bool {
// 如果模式已经匹配完成
if patternIndex >= len(pattern) {
return textIndex >= len(text) // 文本也应该匹配完成
}
// 如果文本已经结束,但模式还有非%字符,则不匹配
if textIndex >= len(text) {
// 检查剩余的模式是否都是%
for i := patternIndex; i < len(pattern); i++ {
if pattern[i] != '%' {
return false
}
}
return true
}
// 处理当前模式字符
patternChar := pattern[patternIndex]
if patternChar == '%' {
// %可以匹配0个或多个字符
// 尝试匹配0个字符跳过%
if bridge.likeMatch(text, pattern, textIndex, patternIndex+1) {
return true
}
// 尝试匹配1个或多个字符
for i := textIndex; i < len(text); i++ {
if bridge.likeMatch(text, pattern, i+1, patternIndex+1) {
return true
}
}
return false
} else if patternChar == '_' {
// _匹配恰好一个字符
return bridge.likeMatch(text, pattern, textIndex+1, patternIndex+1)
} else {
// 普通字符必须精确匹配
if text[textIndex] == patternChar {
return bridge.likeMatch(text, pattern, textIndex+1, patternIndex+1)
}
return false
}
}
// 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{} {
bridge.mutex.RLock()
defer bridge.mutex.RUnlock()
info := make(map[string]interface{})
// StreamSQL函数信息 - 动态获取所有当前注册的函数
streamSQLFuncs := make(map[string]interface{})
allFunctions := ListAll() // 动态获取所有注册的函数
for name, fn := range allFunctions {
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) {
bridge.mutex.RLock()
defer bridge.mutex.RUnlock()
// 进行大小写不敏感的查找
lowerName := strings.ToLower(name)
// 首先检查StreamSQL函数优先级更高 - 动态获取
allFunctions := ListAll()
if fn, exists := allFunctions[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
var globalBridgeMutex sync.RWMutex
// GetExprBridge 获取全局桥接器实例
func GetExprBridge() *ExprBridge {
// 首先使用读锁检查是否已初始化
globalBridgeMutex.RLock()
if globalBridge != nil {
defer globalBridgeMutex.RUnlock()
return globalBridge
}
globalBridgeMutex.RUnlock()
// 使用写锁进行初始化
globalBridgeMutex.Lock()
defer globalBridgeMutex.Unlock()
// 双重检查模式,防止并发初始化
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()
}