condition/condition.go

242 lines
4.8 KiB
Go
Raw Normal View History

2023-07-20 14:55:00 +08:00
package condition
import (
"fmt"
"strings"
"git.fsdpf.net/go/db"
"git.fsdpf.net/go/utils"
2023-07-20 14:55:00 +08:00
"github.com/samber/lo"
)
2024-05-09 09:26:57 +08:00
type ConditionType string
2024-05-08 22:58:27 +08:00
const (
2024-05-09 09:26:57 +08:00
OR ConditionType = "OR"
AND ConditionType = "AND"
2024-05-08 22:58:27 +08:00
)
2023-07-20 14:55:00 +08:00
type Condition struct {
2024-05-09 09:26:57 +08:00
parent *Condition
typ ConditionType // 分组类型
describe string // 描述
exprs []*ConditionExpr // 分组表达式成员
childrens []*Condition // 分组子集
2023-07-20 14:55:00 +08:00
}
2024-05-09 09:26:57 +08:00
func (this *Condition) AppendTo(c *Condition) {
2023-07-20 14:55:00 +08:00
this.parent = c
}
// 条件类型
2024-05-09 09:26:57 +08:00
func (this Condition) Type() ConditionType {
2023-07-20 14:55:00 +08:00
return this.typ
}
// 判断条件为空
func (this Condition) IsEmpty() bool {
if len(this.exprs) > 0 {
return false
}
for _, cond := range this.childrens {
if !cond.IsEmpty() {
return false
}
}
return true
}
// 判断条件不为空
func (this Condition) IsNotEmpty() bool {
return !this.IsEmpty()
}
// 判断条件是否恒成立
func (this Condition) IsAlwaysRight() bool {
flag := []bool{}
for _, expr := range this.exprs {
2024-05-08 22:58:27 +08:00
if expr.GetOperator() != EQ {
2023-07-20 14:55:00 +08:00
flag = append(flag, false)
continue
}
2024-05-08 22:58:27 +08:00
if expr.GetTokenType() != SQL {
2023-07-20 14:55:00 +08:00
flag = append(flag, false)
continue
}
eRight := fmt.Sprintf("%s.%s", expr.GetFieldResource(), expr.GetField()) == strings.ReplaceAll(expr.GetTokenName(), "`", "")
2024-05-08 22:58:27 +08:00
if this.typ == OR && eRight {
2023-07-20 14:55:00 +08:00
return true
}
flag = append(flag, eRight)
}
for _, cond := range this.childrens {
cRight := cond.IsAlwaysRight()
2024-05-08 22:58:27 +08:00
if this.typ == OR && cRight {
2023-07-20 14:55:00 +08:00
return true
}
flag = append(flag, cRight)
}
if len(flag) == 0 {
return true
}
return !lo.Some(flag, []bool{false})
}
// 生成 SQL 语句
func (this Condition) ToSql(m TokenValue) db.Expression {
2023-07-20 14:55:00 +08:00
conditions := []string{}
// 表达式
for _, item := range this.exprs {
if item.IsIgnoreEmptyParma(m) {
continue
}
conditions = append(conditions, string(item.ToSql(m)))
}
// 条件子集
for _, item := range this.childrens {
conditions = append(conditions, string(item.ToSql(m)))
}
// 去除无效的表达式
conditions = lo.Filter(conditions, func(item string, _ int) bool { return item != "" })
// 组合 SQL
sql := strings.Join(conditions, " "+string(this.Type())+" ")
if sql == "" {
2024-05-08 22:58:27 +08:00
if this.parent == nil && this.Type() == OR {
2023-07-20 14:55:00 +08:00
return db.Raw("false")
2024-05-08 22:58:27 +08:00
} else if this.parent == nil && this.Type() == AND {
2023-07-20 14:55:00 +08:00
return db.Raw("true")
}
return db.Raw("")
}
// 包裹 SQL, 避免语法表达错误
2024-05-08 22:58:27 +08:00
if this.parent == nil || this.Type() == OR {
2023-07-20 14:55:00 +08:00
sql = "(" + sql + ")"
}
if this.describe != "" {
sql += "/*" + this.describe + "*/"
}
return db.Raw(sql)
}
// 设置条件表达式
2024-05-09 09:26:57 +08:00
func (this *Condition) SetExpr(expr *ConditionExpr) *Condition {
2023-07-20 14:55:00 +08:00
expr.AppendTo(this)
this.exprs = append(this.exprs, expr)
return this
}
// 设置条件子集
2024-05-09 09:26:57 +08:00
func (this *Condition) SetCondition(c *Condition) *Condition {
2023-07-20 14:55:00 +08:00
c.AppendTo(this)
this.childrens = append(this.childrens, c)
return this
}
// 设置 Token 匹配前缀
2024-05-09 09:26:57 +08:00
func (this *Condition) SetMatchPrefix(prefix string) *Condition {
2023-07-20 14:55:00 +08:00
for _, expr := range this.exprs {
expr.SetMatchPrefix(prefix)
}
for _, cond := range this.childrens {
cond.SetMatchPrefix(prefix)
}
return this
}
func (this Condition) GetFieldsValue(m TokenValue, isWithResource bool) (result map[string]any) {
2023-07-20 14:55:00 +08:00
if this.IsEmpty() {
return
}
// 表达式
for _, item := range this.exprs {
2024-05-08 22:58:27 +08:00
if item.GetOperator() != EQ {
2023-07-20 14:55:00 +08:00
continue
}
vField := map[string]any{item.GetField(): item.GetTokenValue(m)}
if isWithResource {
vField = map[string]any{item.GetFieldResource(): vField}
}
result = utils.MergeMap(result, vField)
2023-07-20 14:55:00 +08:00
}
// 条件子集
for _, item := range this.childrens {
result = utils.MergeMap(result, item.GetFieldsValue(m, isWithResource))
2023-07-20 14:55:00 +08:00
}
return result
}
/**
* @param ConditionOperator operator
* @param TokenType types
2023-07-20 14:55:00 +08:00
* @return map[string][string] // 如: {"TestA.field_a": "param"}
*/
func (this Condition) GetFields(operator ConditionOperator, types ...TokenType) map[string]string {
2023-07-20 14:55:00 +08:00
result := make(map[string]string)
if this.IsEmpty() {
return result
}
// 表达式
for _, item := range this.exprs {
if item.GetOperator() != operator || !lo.Contains(types, item.GetTokenType()) {
continue
}
result[fmt.Sprintf("%s.%s", item.GetFieldResource(), item.GetField())] = item.GetTokenName()
}
// 条件子集
for _, item := range this.childrens {
result = lo.Assign(result, item.GetFields(operator, types...))
}
return result
}
2024-05-09 10:35:14 +08:00
func (this *Condition) SetOption(opts ...Option) *Condition {
for i := 0; i < len(opts); i++ {
opts[i](this)
}
return this
}
2024-05-09 10:08:28 +08:00
type Option func(option *Condition)
func Type(v ConditionType) Option {
return func(option *Condition) {
option.typ = v
}
}
func Describe(v string) Option {
return func(option *Condition) {
option.describe = v
}
}
func New(opts ...Option) *Condition {
cond := &Condition{typ: AND}
2024-05-09 10:35:14 +08:00
cond.SetOption(opts...)
2024-05-09 10:08:28 +08:00
return cond
2023-07-20 14:55:00 +08:00
}