package tests import ( "fmt" "git.fsdpf.net/go/condflow" "git.fsdpf.net/go/condflow/tests/fixtures" "git.fsdpf.net/go/condition" "git.fsdpf.net/go/contracts/base" "git.fsdpf.net/go/reflux" "git.fsdpf.net/go/reflux/fieldx" "git.fsdpf.net/go/req" "git.fsdpf.net/go/req/resx" "github.com/samber/do/v2" ) // setupExampleExecutor 创建并注册示例 executor func setupExampleExecutor(app do.Injector) { // 创建 resource exampleRes := resx.New(app, "Example", "examples", resx.WithUuid("660e8400-e29b-41d4-a716-446655440002"), resx.WithName("示例"), resx.WithFields( resx.NewResField("id", "", resx.FieldWithName("ID"), resx.FieldWithDataType(req.ResInteger)), resx.NewResField("created_user", "", resx.FieldWithName("创建者"), resx.FieldWithDefault("00000000-0000-0000-0000-000000000000"), resx.FieldWithDataType(req.ResString)), resx.NewResField("owned_user", "", resx.FieldWithName("拥有者"), resx.FieldWithDefault("00000000-0000-0000-0000-000000000000"), resx.FieldWithDataType(req.ResString)), resx.NewResField("created_at", "", resx.FieldWithName("创建时间"), resx.FieldWithDefault("sql:CURRENT_TIMESTAMP"), resx.FieldWithDataType(req.ResTimestamp)), resx.NewResField("updated_at", "", resx.FieldWithName("更新时间"), resx.FieldWithDefault("sql:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"), resx.FieldWithDataType(req.ResTimestamp)), resx.NewResField("uuid", "", resx.FieldWithName("UUID"), resx.FieldWithDefault("sql:uuid()"), resx.FieldWithDataType(req.ResString)), resx.NewResField("status", "", resx.FieldWithName("状态"), resx.FieldWithDefault("pending"), resx.FieldWithDataType(req.ResString)), resx.NewResField("type", "", resx.FieldWithName("类型"), resx.FieldWithDataType(req.ResString)), resx.NewResField("data", "", resx.FieldWithName("数据"), resx.FieldWithDefault("{}"), resx.FieldWithDataType(req.ResJson)), ), ) executor := condflow.NewActionInvoker(fixtures.NewExampleExecutor(exampleRes), nil) do.ProvideNamedValue(app, fmt.Sprintf("%s/ExampleExecutor", executor.Res().GetCode()), executor) } // Example_userApprovalFlow 用户审批流示例 func Example_userApprovalFlow() { // 初始化 DI 容器并注册 executor app := do.New() setupExampleExecutor(app) // 创建条件流 flow := condflow.New("user-approval-flow") // Case 1: 金额 <= 1000,自动通过 case1Cond := condition.New(condition.Describe("小额自动审批")) case1Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("1000", condition.STRING))) case1Config, _ := fieldx.SchemaFromMap(map[string]any{ "notify": map[string]any{ "type": "string", "value": "true", }, "message": map[string]any{ "type": "string", "value": "申请已自动通过", }, }) case1 := condflow.NewCondCase( "auto-approve-small", case1Cond, "Example/ExampleExecutor@AutoApprove", ). WithPriority(100). WithActionConfig(case1Config) // Case 2: 1000 < 金额 <= 10000,需要经理审批 case2Cond := condition.New(condition.Describe("经理审批")) case2Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("1000", condition.STRING))). SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("10000", condition.STRING))) case2Config, _ := fieldx.SchemaFromMap(map[string]any{ "approver_role": map[string]any{ "type": "string", "value": "manager", }, "timeout_hours": map[string]any{ "type": "string", "value": "24", }, "notify": map[string]any{ "type": "string", "value": "true", }, }) case2 := condflow.NewCondCase( "manager-approval", case2Cond, "Example/ExampleExecutor@ManagerApproval", ). WithPriority(90). WithActionConfig(case2Config) // Case 3: 金额 > 10000,需要总监审批 case3Cond := condition.New(condition.Describe("总监审批")) case3Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("10000", condition.STRING))) case3Config, _ := fieldx.SchemaFromMap(map[string]any{ "approver_role": map[string]any{ "type": "string", "value": "director", }, "timeout_hours": map[string]any{ "type": "string", "value": "48", }, "notify": map[string]any{ "type": "string", "value": "true", }, "cc_roles": map[string]any{ "type": "string", "value": "manager,ceo", }, }) case3 := condflow.NewCondCase( "director-approval", case3Cond, "Example/ExampleExecutor@DirectorApproval", ). WithPriority(80). WithActionConfig(case3Config) // Case 4: 用户信用评分 < 60,直接拒绝 case4Cond := condition.New(condition.Describe("信用不足拒绝")) case4Cond.SetExpr(condition.NewExpr("@", "user->>'credit_score'", condition.Operator(condition.LT), condition.Token("60", condition.STRING))) case4Config, _ := fieldx.SchemaFromMap(map[string]any{ "reason": map[string]any{ "type": "string", "value": "信用评分不足", }, "notify": map[string]any{ "type": "string", "value": "true", }, "suggest_retry": map[string]any{ "type": "string", "value": "false", }, }) case4 := condflow.NewCondCase( "reject-low-credit", case4Cond, "Example/ExampleExecutor@Reject", ). WithPriority(200). // 最高优先级,优先检查 WithActionConfig(case4Config) // 添加所有条件分支到流程 flow.AddCase(case4). // 优先级最高 AddCase(case1). AddCase(case2). AddCase(case3) // 生成包含多种数据类型的测试 map input := reflux.New(map[string]any{ // 基础类型 "amount": 5000.50, // float64 "count": 100, // int "active": true, // bool "user_name": "张三", // string "age": int32(25), // int32 "total": int64(1000000), // int64 "score": float32(98.5), // float32 "is_vip": false, // bool // 数组/切片类型 "tags": []string{"vip", "premium", "active"}, // slice "scores": []int{85, 90, 95}, // slice of int "prices": []float64{19.99, 29.99, 39.99}, // slice of float // Map 类型 "preferences": map[string]any{ "newsletter": true, "theme": "dark", "language": "zh-CN", }, // 嵌套结构 "user": map[string]any{ "id": 12345, "email": "user@example.com", "level": 5, "credit_score": 85, "created_at": "2024-01-01", }, // 空值测试 "nullable_field": nil, "empty_string": "", }) flow.Run(app, input, base.GetSystemUser()) fmt.Printf("条件流名称: %s\n", flow.Name()) fmt.Printf("条件分支数量: %d\n", flow.CaseCount()) // Output: // 条件流名称: user-approval-flow // 条件分支数量: 4 } // Example_emailCampaignFlow 邮件营销活动流示例 func Example_emailCampaignFlow() { // 初始化 DI 容器并注册 executor app := do.New() setupExampleExecutor(app) // 创建邮件营销条件流 flow := condflow.New("email-campaign-flow") // Case 1: VIP 用户 - 发送专属优惠 vipCond := condition.New(condition.Describe("VIP用户筛选")) vipCond.SetExpr(condition.NewExpr("User", "level", condition.Operator(condition.GE), condition.Token("5", condition.STRING))). SetExpr(condition.NewExpr("User", "email", condition.Operator(condition.IS_NOT_NULL))). SetExpr(condition.NewExpr("User", "preferences->'newsletter'", condition.Token("true", condition.STRING))). SetExpr(condition.NewExpr("User", "tags", condition.FieldSqlFn("json_contains", ""), condition.Token("vip", condition.STRING))) vipConfig, _ := fieldx.SchemaFromMap(map[string]any{ "template": map[string]any{ "type": "string", "value": "vip-exclusive-offer", }, "subject": map[string]any{ "type": "string", "value": "尊贵的VIP会员,专属优惠来啦!", }, "discount": map[string]any{ "type": "string", "value": "30", }, "valid_days": map[string]any{ "type": "string", "value": "30", }, "priority": map[string]any{ "type": "string", "value": "high", }, "attachments": map[string]any{ "type": "string", "value": "vip-catalog.pdf", }, }) vipCase := condflow.NewCondCase("vip-campaign", vipCond, "Example/ExampleExecutor@VIPEmail"). WithPriority(100). WithActionConfig(vipConfig) // Case 2: 新用户 - 发送欢迎邮件 newUserCond := condition.New(condition.Describe("新用户识别")) newUserCond.SetExpr(condition.NewExpr("User", "created_at", condition.Operator(condition.GE), condition.Token("DATE_SUB(NOW(), INTERVAL 7 DAY)", condition.SQL))). SetExpr(condition.NewExpr("User", "email_verified", condition.Token("true", condition.STRING))) newUserConfig, _ := fieldx.SchemaFromMap(map[string]any{ "template": map[string]any{ "type": "string", "value": "welcome-new-user", }, "subject": map[string]any{ "type": "string", "value": "欢迎加入我们!", }, "coupon_code": map[string]any{ "type": "string", "value": "WELCOME2024", }, "discount": map[string]any{ "type": "string", "value": "10", }, "trigger_delay": map[string]any{ "type": "string", "value": "1h", }, }) newUserCase := condflow.NewCondCase("new-user-welcome", newUserCond, "Example/ExampleExecutor@WelcomeEmail"). WithPriority(90). WithActionConfig(newUserConfig) // Case 3: 普通活跃用户 - 发送常规营销邮件 regularCond := condition.New(condition.Describe("活跃普通用户")) regularCond.SetExpr(condition.NewExpr("User", "last_login_at", condition.Operator(condition.GE), condition.Token("DATE_SUB(NOW(), INTERVAL 30 DAY)", condition.SQL))). SetExpr(condition.NewExpr("User", "email", condition.Operator(condition.IS_NOT_NULL))). SetExpr(condition.NewExpr("User", "preferences->'newsletter'", condition.Token("true", condition.STRING))) regularConfig, _ := fieldx.SchemaFromMap(map[string]any{ "template": map[string]any{ "type": "string", "value": "regular-promotion", }, "subject": map[string]any{ "type": "string", "value": "本月精选优惠", }, "discount": map[string]any{ "type": "string", "value": "15", }, "valid_days": map[string]any{ "type": "string", "value": "14", }, }) regularCase := condflow.NewCondCase("regular-campaign", regularCond, "Example/ExampleExecutor@RegularEmail"). WithPriority(50). WithActionConfig(regularConfig) // Case 4: 未订阅用户 - 跳过 skipCond := condition.New(condition.Describe("未订阅用户")) skipCond.SetExpr(condition.NewExpr("User", "preferences->'newsletter'", condition.Token("false", condition.STRING))) skipConfig, _ := fieldx.SchemaFromMap(map[string]any{ "reason": map[string]any{ "type": "string", "value": "用户未订阅营销邮件", }, "log": map[string]any{ "type": "string", "value": "true", }, }) skipCase := condflow.NewCondCase("skip-unsubscribed", skipCond, "Example/ExampleExecutor@Skip"). WithPriority(200). // 最高优先级 WithActionConfig(skipConfig) // 添加所有条件分支 flow.AddCase(skipCase). AddCase(vipCase). AddCase(newUserCase). AddCase(regularCase) fmt.Printf("条件流名称: %s\n", flow.Name()) fmt.Printf("条件分支数量: %d\n", flow.CaseCount()) // Output: // 条件流名称: email-campaign-flow // 条件分支数量: 4 } // Example_orderProcessingFlow 订单处理流示例 func Example_orderProcessingFlow() { // 初始化 DI 容器并注册 executor app := do.New() setupExampleExecutor(app) // 创建订单处理条件流 flow := condflow.New("order-processing-flow") // Case 1: 高价值订单 + VIP客户 -> 优先处理 + 包邮 premiumCond := condition.New(condition.Describe("高价值VIP订单")) premiumCond.SetExpr(condition.NewExpr("Order", "total_amount", condition.Operator(condition.GE), condition.Token("5000", condition.STRING))). SetExpr(condition.NewExpr("User", "level", condition.Operator(condition.GE), condition.Token("5", condition.STRING))) premiumConfig, _ := fieldx.SchemaFromMap(map[string]any{ "shipping_method": map[string]any{ "type": "string", "value": "express", }, "shipping_fee": map[string]any{ "type": "string", "value": "0", }, "priority": map[string]any{ "type": "string", "value": "high", }, "gift_wrapping": map[string]any{ "type": "string", "value": "true", }, "insurance": map[string]any{ "type": "string", "value": "true", }, }) premiumCase := condflow.NewCondCase("premium-order", premiumCond, "Example/ExampleExecutor@ExpressShipping"). WithPriority(100). WithActionConfig(premiumConfig). WithNextCaseOnSuccess(true) // 继续执行下一个case(通知客户) // Case 2: 紧急订单 -> 加急配送 urgentCond := condition.New(condition.Describe("紧急订单")) urgentCond.SetExpr(condition.NewExpr("Order", "tags", condition.FieldSqlFn("json_contains", ""), condition.Token("urgent", condition.STRING))) urgentConfig, _ := fieldx.SchemaFromMap(map[string]any{ "shipping_method": map[string]any{ "type": "string", "value": "express", }, "max_hours": map[string]any{ "type": "string", "value": "24", }, "priority": map[string]any{ "type": "string", "value": "urgent", }, }) urgentCase := condflow.NewCondCase("urgent-order", urgentCond, "Example/ExampleExecutor@ExpressShipping"). WithPriority(95). WithActionConfig(urgentConfig) // Case 3: 跨区域订单 -> 仓库调配 crossRegionCond := condition.New(condition.Describe("跨区域订单")) crossRegionCond.SetExpr(condition.NewExpr("Order", "shipping_province", condition.Operator(condition.NE), condition.Token("warehouse_province", condition.PARAM))) crossRegionConfig, _ := fieldx.SchemaFromMap(map[string]any{ "check_inventory": map[string]any{ "type": "string", "value": "true", }, "transfer_if_needed": map[string]any{ "type": "string", "value": "true", }, "estimated_days": map[string]any{ "type": "string", "value": "5", }, }) crossRegionCase := condflow.NewCondCase("cross-region-order", crossRegionCond, "Example/ExampleExecutor@WarehouseTransfer"). WithPriority(80). WithActionConfig(crossRegionConfig) // Case 4: 普通订单 -> 标准配送 standardCond := condition.New(condition.Describe("普通订单")) standardCond.SetExpr(condition.NewExpr("Order", "total_amount", condition.Operator(condition.GT), condition.Token("0", condition.STRING))) standardConfig, _ := fieldx.SchemaFromMap(map[string]any{ "shipping_method": map[string]any{ "type": "string", "value": "standard", }, "estimated_days": map[string]any{ "type": "string", "value": "3", }, }) standardCase := condflow.NewCondCase("standard-order", standardCond, "Example/ExampleExecutor@StandardShipping"). WithPriority(50). WithActionConfig(standardConfig) // Case 5: 通知客户(配合 premium case 的 nextCaseOnSuccess) notifyCond := condition.New(condition.Describe("需要通知的订单")) notifyCond.SetExpr(condition.NewExpr("Order", "notify_customer", condition.Token("true", condition.STRING))) notifyConfig, _ := fieldx.SchemaFromMap(map[string]any{ "channels": map[string]any{ "type": "string", "value": "email,sms", }, "template": map[string]any{ "type": "string", "value": "order-confirmed", }, "immediate": map[string]any{ "type": "string", "value": "true", }, }) notifyCase := condflow.NewCondCase("notify-customer", notifyCond, "Example/ExampleExecutor@NotifyCustomer"). WithPriority(40). WithActionConfig(notifyConfig) // 添加所有条件分支 flow.AddCase(premiumCase). AddCase(urgentCase). AddCase(crossRegionCase). AddCase(standardCase). AddCase(notifyCase) fmt.Printf("条件流名称: %s\n", flow.Name()) fmt.Printf("条件分支数量: %d\n", flow.CaseCount()) // Output: // 条件流名称: order-processing-flow // 条件分支数量: 5 } // Example_nestedFlow 嵌套流程示例 - 展示如何使用 NextFlowOnSuccess func Example_nestedFlow() { // 初始化 DI 容器并注册 executor app := do.New() setupExampleExecutor(app) // 创建主流程:用户注册流程 mainFlow := condflow.New("user-registration-flow") // 创建子流程:邮件验证流程 emailVerificationFlow := condflow.New("email-verification-flow") verifyCond := condition.New(condition.Describe("发送验证邮件")) verifyConfig, _ := fieldx.SchemaFromMap(map[string]any{ "template": map[string]any{ "type": "string", "value": "email-verification", }, "expire_in": map[string]any{ "type": "string", "value": "24h", }, }) verifyCase := condflow.NewCondCase("send-verify-email", verifyCond, "Example/ExampleExecutor@SendVerification"). WithActionConfig(verifyConfig) emailVerificationFlow.AddCase(verifyCase) // 创建子流程:欢迎礼包流程 welcomePackFlow := condflow.New("welcome-pack-flow") couponCond := condition.New(condition.Describe("创建新用户优惠券")) couponConfig, _ := fieldx.SchemaFromMap(map[string]any{ "coupon_type": map[string]any{ "type": "string", "value": "new_user", }, "discount": map[string]any{ "type": "string", "value": "20", }, "valid_days": map[string]any{ "type": "string", "value": "30", }, }) couponCase := condflow.NewCondCase("new-user-coupon", couponCond, "Example/ExampleExecutor@CreateCoupon"). WithActionConfig(couponConfig) welcomePackFlow.AddCase(couponCase) // 主流程 Case: 邮箱注册用户 emailRegCond := condition.New(condition.Describe("邮箱注册")) emailRegCond.SetExpr(condition.NewExpr("User", "register_type", condition.Token("email", condition.STRING))) emailRegConfig, _ := fieldx.SchemaFromMap(map[string]any{ "send_welcome": map[string]any{ "type": "string", "value": "true", }, }) emailRegCase := condflow.NewCondCase("email-registration", emailRegCond, "Example/ExampleExecutor@CreateUser"). WithPriority(100). WithNextFlowOnSuccess(emailVerificationFlow, nil). // 成功后执行邮件验证流程 WithActionConfig(emailRegConfig) // 主流程 Case: 手机号注册用户 phoneRegCond := condition.New(condition.Describe("手机号注册")) phoneRegCond.SetExpr(condition.NewExpr("User", "register_type", condition.Token("phone", condition.STRING))) phoneRegConfig, _ := fieldx.SchemaFromMap(map[string]any{ "send_sms": map[string]any{ "type": "string", "value": "true", }, }) phoneRegCase := condflow.NewCondCase("phone-registration", phoneRegCond, "Example/ExampleExecutor@CreateUser"). WithPriority(90). WithNextFlowOnSuccess(welcomePackFlow, nil). // 成功后执行欢迎礼包流程 WithActionConfig(phoneRegConfig) mainFlow.AddCase(emailRegCase). AddCase(phoneRegCase) fmt.Printf("主流程名称: %s\n", mainFlow.Name()) fmt.Printf("主流程分支数量: %d\n", mainFlow.CaseCount()) // Output: // 主流程名称: user-registration-flow // 主流程分支数量: 2 }