给 Condition/ConditionExpr 加 MarshalJSON/UnmarshalJSON,中间过一层 DTO (conditionDTO/exprDTO)避免 UnmarshalJSON 递归。FromMap(m map[string]any) 方便从已经解析好的 map(比如请求参数)直接构造 Condition,不用先序列化 成 JSON 字符串再解析一遍。
127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
package condition_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"git.fsdpf.net/go/condition"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type conditionJSONTest struct {
|
|
suite.Suite
|
|
}
|
|
|
|
func TestConditionJSONSuite(t *testing.T) {
|
|
suite.Run(t, new(conditionJSONTest))
|
|
}
|
|
|
|
// 构造一个有代表性的多层条件
|
|
func buildTestCondition() *condition.Condition {
|
|
cond := condition.New(condition.Describe("测试"))
|
|
cond.SetExpr(condition.NewExpr("User", "name",
|
|
condition.Operator(condition.LIKE),
|
|
condition.Token("张三", condition.STRING),
|
|
))
|
|
cond.SetExpr(condition.NewExpr("User", "age",
|
|
condition.Operator(condition.GE),
|
|
condition.Token("18", condition.STRING),
|
|
))
|
|
|
|
sub := condition.New(condition.Type(condition.OR))
|
|
sub.SetExpr(condition.NewExpr("User", "status",
|
|
condition.Operator(condition.IN),
|
|
condition.Token("active", condition.STRING),
|
|
))
|
|
sub.SetExpr(condition.NewExpr("User", "roles",
|
|
condition.FieldSqlFn("json_contains", ""),
|
|
condition.Token("admin", condition.STRING),
|
|
))
|
|
cond.SetCondition(sub)
|
|
|
|
return cond
|
|
}
|
|
|
|
func (t *conditionJSONTest) TestMarshalUnmarshal() {
|
|
orig := buildTestCondition()
|
|
|
|
data, err := json.Marshal(orig)
|
|
t.Require().NoError(err)
|
|
t.T().Log("JSON:", string(data))
|
|
|
|
got := condition.New()
|
|
t.Require().NoError(json.Unmarshal(data, got))
|
|
|
|
// 二次序列化结果应一致
|
|
data2, err := json.Marshal(got)
|
|
t.Require().NoError(err)
|
|
t.Equal(string(data), string(data2))
|
|
}
|
|
|
|
func (t *conditionJSONTest) TestFromMap() {
|
|
m := map[string]any{
|
|
"type": "AND",
|
|
"describe": "来自Map",
|
|
"exprs": []any{
|
|
map[string]any{
|
|
"operator": "=",
|
|
"field": "name",
|
|
"fieldResource": "User",
|
|
"tokenType": "string",
|
|
"token": "张三",
|
|
},
|
|
map[string]any{
|
|
"operator": ">=",
|
|
"field": "age",
|
|
"fieldResource": "User",
|
|
"tokenType": "string",
|
|
"token": "18",
|
|
},
|
|
},
|
|
"childrens": []any{
|
|
map[string]any{
|
|
"type": "OR",
|
|
"exprs": []any{
|
|
map[string]any{
|
|
"operator": "IS NULL",
|
|
"field": "deleted_at",
|
|
"fieldResource": "User",
|
|
"tokenType": "string",
|
|
"token": "",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
cond, err := condition.FromMap(m)
|
|
t.Require().NoError(err)
|
|
t.False(cond.IsEmpty())
|
|
|
|
data, err := json.Marshal(cond)
|
|
t.Require().NoError(err)
|
|
t.T().Log("FromMap JSON:", string(data))
|
|
}
|
|
|
|
func (t *conditionJSONTest) TestRoundTrip() {
|
|
orig := buildTestCondition()
|
|
|
|
// Condition → JSON → Condition → JSON,两次 JSON 应一致
|
|
data1, err := json.Marshal(orig)
|
|
t.Require().NoError(err)
|
|
|
|
cond2 := condition.New()
|
|
t.Require().NoError(json.Unmarshal(data1, cond2))
|
|
|
|
data2, err := json.Marshal(cond2)
|
|
t.Require().NoError(err)
|
|
|
|
t.JSONEq(string(data1), string(data2))
|
|
}
|
|
|
|
func (t *conditionJSONTest) TestFromMapEmpty() {
|
|
cond, err := condition.FromMap(map[string]any{})
|
|
t.Require().NoError(err)
|
|
t.True(cond.IsEmpty())
|
|
}
|