Files
streamsql/condition/condition.go
2025-06-16 18:00:06 +08:00

114 lines
2.9 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 condition
import (
"fmt"
"github.com/expr-lang/expr"
"github.com/expr-lang/expr/vm"
)
type Condition interface {
Evaluate(env interface{}) bool
}
type ExprCondition struct {
program *vm.Program
}
func NewExprCondition(expression string) (Condition, error) {
// 添加自定义字符串函数支持startsWith、endsWith、contains是内置操作符
options := []expr.Option{
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 matchesLikePattern(text, pattern), nil
}),
expr.Function("is_null", func(params ...any) (any, error) {
if len(params) != 1 {
return false, fmt.Errorf("is_null function requires 1 parameter")
}
return params[0] == nil, nil
}),
expr.Function("is_not_null", func(params ...any) (any, error) {
if len(params) != 1 {
return false, fmt.Errorf("is_not_null function requires 1 parameter")
}
return params[0] != nil, nil
}),
expr.AllowUndefinedVariables(),
expr.AsBool(),
}
program, err := expr.Compile(expression, options...)
if err != nil {
return nil, err
}
return &ExprCondition{program: program}, nil
}
func (ec *ExprCondition) Evaluate(env interface{}) bool {
result, err := expr.Run(ec.program, env)
if err != nil {
return false
}
return result.(bool)
}
// matchesLikePattern 实现LIKE模式匹配
// 支持%匹配任意字符序列和_匹配单个字符
func matchesLikePattern(text, pattern string) bool {
return likeMatch(text, pattern, 0, 0)
}
// likeMatch 递归实现LIKE匹配算法
func 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 likeMatch(text, pattern, textIndex, patternIndex+1) {
return true
}
// 尝试匹配1个或多个字符
for i := textIndex; i < len(text); i++ {
if likeMatch(text, pattern, i+1, patternIndex+1) {
return true
}
}
return false
} else if patternChar == '_' {
// _匹配恰好一个字符
return likeMatch(text, pattern, textIndex+1, patternIndex+1)
} else {
// 普通字符必须精确匹配
if text[textIndex] == patternChar {
return likeMatch(text, pattern, textIndex+1, patternIndex+1)
}
return false
}
}