first commit
This commit is contained in:
+212
@@ -0,0 +1,212 @@
|
||||
package condition
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.fsdpf.net/go/contracts"
|
||||
"git.fsdpf.net/go/contracts/support"
|
||||
"git.fsdpf.net/go/db"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type Condition struct {
|
||||
parent contracts.Condition
|
||||
typ contracts.ConditionType // 分组类型
|
||||
describe string // 描述
|
||||
exprs []contracts.ConditionExpr // 分组表达式成员
|
||||
childrens []contracts.Condition // 分组子集
|
||||
}
|
||||
|
||||
func (this *Condition) AppendTo(c contracts.Condition) {
|
||||
this.parent = c
|
||||
}
|
||||
|
||||
// 条件类型
|
||||
func (this Condition) Type() contracts.ConditionType {
|
||||
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 {
|
||||
if expr.GetOperator() != contracts.ConditionOperator_EQ {
|
||||
flag = append(flag, false)
|
||||
continue
|
||||
}
|
||||
|
||||
if expr.GetTokenType() != contracts.ConditionTokenType_SQL {
|
||||
flag = append(flag, false)
|
||||
continue
|
||||
}
|
||||
|
||||
eRight := fmt.Sprintf("%s.%s", expr.GetFieldResource(), expr.GetField()) == strings.ReplaceAll(expr.GetTokenName(), "`", "")
|
||||
|
||||
if this.typ == contracts.ConditionType_OR && eRight {
|
||||
return true
|
||||
}
|
||||
|
||||
flag = append(flag, eRight)
|
||||
}
|
||||
|
||||
for _, cond := range this.childrens {
|
||||
cRight := cond.IsAlwaysRight()
|
||||
|
||||
if this.typ == contracts.ConditionType_OR && cRight {
|
||||
return true
|
||||
}
|
||||
|
||||
flag = append(flag, cRight)
|
||||
}
|
||||
|
||||
if len(flag) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return !lo.Some(flag, []bool{false})
|
||||
}
|
||||
|
||||
// 生成 SQL 语句
|
||||
func (this Condition) ToSql(m contracts.ModelParam) db.Expression {
|
||||
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 == "" {
|
||||
if this.parent == nil && this.Type() == contracts.ConditionType_OR {
|
||||
return db.Raw("false")
|
||||
} else if this.parent == nil && this.Type() == contracts.ConditionType_AND {
|
||||
return db.Raw("true")
|
||||
}
|
||||
return db.Raw("")
|
||||
}
|
||||
|
||||
// 包裹 SQL, 避免语法表达错误
|
||||
if this.parent == nil || this.Type() == contracts.ConditionType_OR {
|
||||
sql = "(" + sql + ")"
|
||||
}
|
||||
|
||||
if this.describe != "" {
|
||||
sql += "/*" + this.describe + "*/"
|
||||
}
|
||||
|
||||
return db.Raw(sql)
|
||||
}
|
||||
|
||||
// 设置条件表达式
|
||||
func (this *Condition) SetExpr(expr contracts.ConditionExpr) contracts.Condition {
|
||||
expr.AppendTo(this)
|
||||
this.exprs = append(this.exprs, expr)
|
||||
return this
|
||||
}
|
||||
|
||||
// 设置条件子集
|
||||
func (this *Condition) SetCondition(c contracts.Condition) contracts.Condition {
|
||||
c.AppendTo(this)
|
||||
this.childrens = append(this.childrens, c)
|
||||
return this
|
||||
}
|
||||
|
||||
// 设置 Token 匹配前缀
|
||||
func (this *Condition) SetMatchPrefix(prefix string) contracts.Condition {
|
||||
for _, expr := range this.exprs {
|
||||
expr.SetMatchPrefix(prefix)
|
||||
}
|
||||
for _, cond := range this.childrens {
|
||||
cond.SetMatchPrefix(prefix)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
func (this Condition) GetFieldsValue(m contracts.ModelParam, isWithResource bool) (result map[string]any) {
|
||||
if this.IsEmpty() {
|
||||
return
|
||||
}
|
||||
|
||||
// 表达式
|
||||
for _, item := range this.exprs {
|
||||
if item.GetOperator() != contracts.ConditionOperator_EQ {
|
||||
continue
|
||||
}
|
||||
|
||||
vField := map[string]any{item.GetField(): item.GetTokenValue(m)}
|
||||
|
||||
if isWithResource {
|
||||
vField = map[string]any{item.GetFieldResource(): vField}
|
||||
}
|
||||
|
||||
result = support.MergeMap(result, vField)
|
||||
}
|
||||
// 条件子集
|
||||
for _, item := range this.childrens {
|
||||
result = support.MergeMap(result, item.GetFieldsValue(m, isWithResource))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contracts.ConditionOperator operator
|
||||
* @param contracts.ConditionTokenType types
|
||||
* @return map[string][string] // 如: {"TestA.field_a": "param"}
|
||||
*/
|
||||
func (this Condition) GetFields(operator contracts.ConditionOperator, types ...contracts.ConditionTokenType) map[string]string {
|
||||
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
|
||||
}
|
||||
|
||||
func New(typ contracts.ConditionType, describe string) contracts.Condition {
|
||||
return &Condition{typ: typ, describe: describe}
|
||||
}
|
||||
Reference in New Issue
Block a user