+ IF & Case Process
This commit is contained in:
parent
2c597509c7
commit
c0df8b4b12
7 changed files with 420 additions and 0 deletions
49
helper/case.go
Normal file
49
helper/case.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/exception"
|
||||
)
|
||||
|
||||
// CaseParam 条件参数
|
||||
type CaseParam struct {
|
||||
When []Condition `json:"when"`
|
||||
Name string `json:"name"`
|
||||
Process string `json:"process"`
|
||||
Args []interface{} `json:"args"`
|
||||
}
|
||||
|
||||
// Case 条件判断
|
||||
func Case(params ...CaseParam) interface{} {
|
||||
for _, param := range params {
|
||||
if When(param.When) {
|
||||
return gou.NewProcess(param.Process, param.Args...).Run()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CaseParamOf 读取参数
|
||||
func CaseParamOf(v interface{}) CaseParam {
|
||||
data, err := jsoniter.Marshal(v)
|
||||
if err != nil {
|
||||
exception.New("参数错误: %s", 400, err).Throw()
|
||||
}
|
||||
res := CaseParam{}
|
||||
err = jsoniter.Unmarshal(data, &res)
|
||||
if err != nil {
|
||||
exception.New("参数错误: %s", 400, err).Throw()
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ProcessCase xiang.helper.Case Case条件判断
|
||||
func ProcessCase(process *gou.Process) interface{} {
|
||||
process.ValidateArgNums(1)
|
||||
params := []CaseParam{}
|
||||
for _, v := range process.Args {
|
||||
params = append(params, CaseParamOf(v))
|
||||
}
|
||||
return Case(params...)
|
||||
}
|
||||
62
helper/case_test.go
Normal file
62
helper/case_test.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/yaoapp/gou"
|
||||
)
|
||||
|
||||
func TestCase(t *testing.T) {
|
||||
|
||||
gou.RegisterProcessHandler("xiang.unit.return", func(process *gou.Process) interface{} {
|
||||
return process.Args
|
||||
})
|
||||
|
||||
case1 := CaseParam{
|
||||
When: []Condition{
|
||||
{Left: "张三", OP: "=", Right: "李四", Compute: Computes["="]},
|
||||
{OR: true, Left: "李四", OP: "=", Right: "李四", Compute: Computes["="]},
|
||||
},
|
||||
Name: "打印信息",
|
||||
Process: "xiang.unit.Return",
|
||||
Args: []interface{}{"world"},
|
||||
}
|
||||
|
||||
case2 := CaseParam{
|
||||
When: []Condition{
|
||||
{Left: "张三", OP: "=", Right: "张三", Compute: Computes["="]},
|
||||
},
|
||||
Name: "打印信息",
|
||||
Process: "xiang.unit.Return",
|
||||
Args: []interface{}{"foo"},
|
||||
}
|
||||
|
||||
v := Case(case1, case2).([]interface{})
|
||||
assert.Equal(t, "world", v[0])
|
||||
}
|
||||
|
||||
func TestProcessCase(t *testing.T) {
|
||||
|
||||
gou.RegisterProcessHandler("xiang.unit.return", func(process *gou.Process) interface{} {
|
||||
return process.Args
|
||||
})
|
||||
|
||||
args := []interface{}{
|
||||
map[string]interface{}{
|
||||
"when": []map[string]interface{}{{"用户": "张三", "=": "李四"}, {"or": true, "用户": "李四", "=": "李四"}},
|
||||
"name": "打印信息",
|
||||
"process": "xiang.unit.Return",
|
||||
"args": []interface{}{"world"},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"when": []map[string]interface{}{{"用户": "张三", "=": "张三"}},
|
||||
"name": "打印信息",
|
||||
"process": "xiang.unit.Return",
|
||||
"args": []interface{}{"foo"},
|
||||
},
|
||||
}
|
||||
process := gou.NewProcess("xiang.helper.Case", args...)
|
||||
res := process.Run().([]interface{})
|
||||
assert.Equal(t, "world", res[0])
|
||||
}
|
||||
170
helper/condition.go
Normal file
170
helper/condition.go
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/kun/any"
|
||||
)
|
||||
|
||||
// ComputeFunc 计算函数
|
||||
type ComputeFunc func(interface{}, interface{}) bool
|
||||
|
||||
// Computes 可用计算式
|
||||
var Computes = map[string]ComputeFunc{
|
||||
"=": func(left interface{}, right interface{}) bool {
|
||||
return left == right
|
||||
},
|
||||
">": func(left interface{}, right interface{}) bool {
|
||||
return any.Of(left).CFloat64() == any.Of(right).CFloat64()
|
||||
},
|
||||
">=": func(left interface{}, right interface{}) bool {
|
||||
return any.Of(left).CFloat64() >= any.Of(right).CFloat64()
|
||||
},
|
||||
"<": func(left interface{}, right interface{}) bool {
|
||||
return any.Of(left).CFloat64() < any.Of(right).CFloat64()
|
||||
},
|
||||
"<=": func(left interface{}, right interface{}) bool {
|
||||
return any.Of(left).CFloat64() <= any.Of(right).CFloat64()
|
||||
},
|
||||
"!=": func(left interface{}, right interface{}) bool {
|
||||
return left != right
|
||||
},
|
||||
"hasprefix": func(left interface{}, right interface{}) bool {
|
||||
return strings.HasPrefix(fmt.Sprintf("%v", left), fmt.Sprintf("%v", right))
|
||||
},
|
||||
"hassuffix": func(left interface{}, right interface{}) bool {
|
||||
return strings.HasSuffix(fmt.Sprintf("%v", left), fmt.Sprintf("%v", right))
|
||||
},
|
||||
"contains": func(left interface{}, right interface{}) bool {
|
||||
return strings.Contains(fmt.Sprintf("%v", left), fmt.Sprintf("%v", right))
|
||||
},
|
||||
"match": func(left interface{}, right interface{}) bool {
|
||||
re := regexp.MustCompile(fmt.Sprintf("%v", right))
|
||||
return re.Match([]byte(fmt.Sprintf("%v", left)))
|
||||
},
|
||||
"is": func(left interface{}, right interface{}) bool {
|
||||
if is, ok := right.(string); ok {
|
||||
is = strings.ToLower(is)
|
||||
if is == "null" {
|
||||
return left == nil
|
||||
} else if is == "notnull" {
|
||||
return left != nil
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
}
|
||||
|
||||
// Condition 判断条件
|
||||
type Condition struct {
|
||||
Left interface{} `json:"left"`
|
||||
Right interface{} `json:"right"`
|
||||
Compute ComputeFunc `json:"-"`
|
||||
OP string `json:"op"`
|
||||
OR bool `json:"or"`
|
||||
Comment string `json:"comment"`
|
||||
}
|
||||
|
||||
// When 多项条件判断
|
||||
func When(conds []Condition) bool {
|
||||
res := true
|
||||
for _, cond := range conds {
|
||||
if cond.OR {
|
||||
res = res || cond.Exec()
|
||||
continue
|
||||
}
|
||||
res = res && cond.Exec()
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Exec 执行条件判断
|
||||
func (cond Condition) Exec() bool {
|
||||
return cond.Compute(cond.Left, cond.Right)
|
||||
}
|
||||
|
||||
// UnmarshalJSON for json marshalJSON
|
||||
func (cond *Condition) UnmarshalJSON(data []byte) error {
|
||||
origin := map[string]interface{}{}
|
||||
err := jsoniter.Unmarshal(data, &origin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*cond = ConditionOf(origin)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON for json marshalJSON
|
||||
func (cond Condition) MarshalJSON() ([]byte, error) {
|
||||
return jsoniter.Marshal(cond.ToMap())
|
||||
}
|
||||
|
||||
// ConditionOf 从 map[string]interface{}
|
||||
func ConditionOf(input map[string]interface{}) Condition {
|
||||
cond := Condition{}
|
||||
for k, val := range input {
|
||||
key := strings.ToLower(k)
|
||||
// { "=": "foo" }
|
||||
if compute, has := Computes[key]; has {
|
||||
cond.Right = val
|
||||
cond.Compute = compute
|
||||
cond.OP = k
|
||||
continue
|
||||
}
|
||||
|
||||
switch key {
|
||||
case "left":
|
||||
cond.Left = val
|
||||
continue
|
||||
case "right":
|
||||
cond.Right = val
|
||||
continue
|
||||
case "op":
|
||||
if val, ok := val.(string); ok {
|
||||
if compute, has := Computes[val]; has {
|
||||
cond.Compute = compute
|
||||
cond.OP = val
|
||||
}
|
||||
|
||||
}
|
||||
continue
|
||||
case "or":
|
||||
if val, ok := val.(bool); ok {
|
||||
cond.OR = val
|
||||
}
|
||||
continue
|
||||
case "comment":
|
||||
if val, ok := val.(string); ok {
|
||||
cond.Comment = val
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// { "用户不存在": "bar"},
|
||||
cond.Comment = key
|
||||
cond.Left = val
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
// ToMap Condition 转换为 map[string]interface{}
|
||||
func (cond Condition) ToMap() map[string]interface{} {
|
||||
res := map[string]interface{}{}
|
||||
if cond.OP != "" {
|
||||
res[cond.OP] = cond.Right
|
||||
}
|
||||
if cond.Comment != "" {
|
||||
res[cond.Comment] = cond.Left
|
||||
} else {
|
||||
res["left"] = cond.Left
|
||||
res["right"] = cond.Right
|
||||
}
|
||||
if cond.OR {
|
||||
res["or"] = true
|
||||
}
|
||||
return res
|
||||
}
|
||||
49
helper/condition_test.go
Normal file
49
helper/condition_test.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCondition(t *testing.T) {
|
||||
data := []byte(`{ "用户不存在": "张三", "=": "李四" }`)
|
||||
cond := Condition{}
|
||||
err := jsoniter.Unmarshal(data, &cond)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "张三", cond.Left)
|
||||
assert.Equal(t, "李四", cond.Right)
|
||||
assert.Equal(t, "=", cond.OP)
|
||||
assert.Equal(t, "用户不存在", cond.Comment)
|
||||
assert.Equal(t, false, cond.OR)
|
||||
assert.False(t, cond.Exec())
|
||||
|
||||
data = []byte(`{ "用户不存在":"张三", "is":"null" }`)
|
||||
cond = Condition{}
|
||||
err = jsoniter.Unmarshal(data, &cond)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "张三", cond.Left)
|
||||
assert.Equal(t, "null", cond.Right)
|
||||
assert.Equal(t, "is", cond.OP)
|
||||
assert.Equal(t, "用户不存在", cond.Comment)
|
||||
assert.Equal(t, false, cond.OR)
|
||||
assert.False(t, cond.Exec())
|
||||
|
||||
data = []byte(`{ "left":"李四", "right":"李四", "op":"=", "or":true }`)
|
||||
cond = Condition{}
|
||||
err = jsoniter.Unmarshal(data, &cond)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "李四", cond.Left)
|
||||
assert.Equal(t, "李四", cond.Right)
|
||||
assert.Equal(t, "=", cond.OP)
|
||||
assert.Equal(t, true, cond.OR)
|
||||
assert.True(t, cond.Exec())
|
||||
|
||||
data, err = jsoniter.Marshal(cond)
|
||||
assert.Nil(t, err)
|
||||
str := string(data)
|
||||
assert.Contains(t, str, `"=":"李四"`)
|
||||
assert.Contains(t, str, `"or":true`)
|
||||
assert.Contains(t, str, `"left":"李四"`)
|
||||
}
|
||||
26
helper/if.go
Normal file
26
helper/if.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
package helper
|
||||
|
||||
import "github.com/yaoapp/gou"
|
||||
|
||||
// IF 条件判断
|
||||
func IF(param CaseParam, paramElse ...CaseParam) interface{} {
|
||||
if When(param.When) {
|
||||
return gou.NewProcess(param.Process, param.Args...).Run()
|
||||
} else if len(paramElse) > 0 && When(paramElse[0].When) {
|
||||
return gou.NewProcess(paramElse[0].Process, paramElse[0].Args...).Run()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProcessIF xiang.helper.IF IF条件判断
|
||||
func ProcessIF(process *gou.Process) interface{} {
|
||||
process.ValidateArgNums(1)
|
||||
params := []CaseParam{}
|
||||
for _, v := range process.Args {
|
||||
params = append(params, CaseParamOf(v))
|
||||
}
|
||||
if len(params) > 1 {
|
||||
IF(params[0], params[1])
|
||||
}
|
||||
return IF(params[0])
|
||||
}
|
||||
62
helper/if_test.go
Normal file
62
helper/if_test.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/yaoapp/gou"
|
||||
)
|
||||
|
||||
func TestIF(t *testing.T) {
|
||||
|
||||
gou.RegisterProcessHandler("xiang.unit.return", func(process *gou.Process) interface{} {
|
||||
return process.Args
|
||||
})
|
||||
|
||||
case1 := CaseParam{
|
||||
When: []Condition{
|
||||
{Left: "张三", OP: "=", Right: "李四", Compute: Computes["="]},
|
||||
{OR: true, Left: "李四", OP: "=", Right: "李四", Compute: Computes["="]},
|
||||
},
|
||||
Name: "打印信息",
|
||||
Process: "xiang.unit.Return",
|
||||
Args: []interface{}{"world"},
|
||||
}
|
||||
|
||||
case2 := CaseParam{
|
||||
When: []Condition{
|
||||
{Left: "张三", OP: "=", Right: "张三", Compute: Computes["="]},
|
||||
},
|
||||
Name: "打印信息",
|
||||
Process: "xiang.unit.Return",
|
||||
Args: []interface{}{"foo"},
|
||||
}
|
||||
|
||||
v := IF(case1, case2).([]interface{})
|
||||
assert.Equal(t, "world", v[0])
|
||||
}
|
||||
|
||||
func TestProcessIF(t *testing.T) {
|
||||
|
||||
gou.RegisterProcessHandler("xiang.unit.return", func(process *gou.Process) interface{} {
|
||||
return process.Args
|
||||
})
|
||||
|
||||
args := []interface{}{
|
||||
map[string]interface{}{
|
||||
"when": []map[string]interface{}{{"用户": "张三", "=": "李四"}, {"or": true, "用户": "李四", "=": "李四"}},
|
||||
"name": "打印信息",
|
||||
"process": "xiang.unit.Return",
|
||||
"args": []interface{}{"world"},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"when": []map[string]interface{}{{"用户": "张三", "=": "张三"}},
|
||||
"name": "打印信息",
|
||||
"process": "xiang.unit.Return",
|
||||
"args": []interface{}{"foo"},
|
||||
},
|
||||
}
|
||||
process := gou.NewProcess("xiang.helper.IF", args...)
|
||||
res := process.Run().([]interface{})
|
||||
assert.Equal(t, "world", res[0])
|
||||
}
|
||||
|
|
@ -21,6 +21,8 @@ func init() {
|
|||
gou.RegisterProcessHandler("xiang.helper.JwtValidate", ProcessJwtValidate)
|
||||
gou.RegisterProcessHandler("xiang.helper.For", ProcessFor)
|
||||
gou.RegisterProcessHandler("xiang.helper.Each", ProcessEach)
|
||||
gou.RegisterProcessHandler("xiang.helper.Case", ProcessCase)
|
||||
gou.RegisterProcessHandler("xiang.helper.IF", ProcessIF)
|
||||
gou.RegisterProcessHandler("xiang.helper.Print", ProcessPrint)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue