From fc3969d74a8e332c94cbea5ea0fe8f72a12567c3 Mon Sep 17 00:00:00 2001 From: what Date: Fri, 21 Aug 2026 09:34:15 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=20README=EF=BC=8C?= =?UTF-8?q?=E8=AF=B4=E6=98=8E=20condflow=20=E7=9A=84=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E6=A6=82=E5=BF=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 顺带清理 go.mod:condition/contracts/db/reflux/req 之前都靠指向本地兄弟 目录的 replace 绕开版本解析,现在锁定成各自 master 最新的真实 commit, 去掉 replace——本地多仓库协同开发改用父目录的 go.work。 Example_userApprovalFlow 这个例子测试目前会失败(预期输出跟实际 SQL 生成 对不上),验证过跟这次改动无关(改动前后表现一致),是已经存在的问题, 不在这次改动范围内。 --- README.md | 33 +++++++++++++++++++++++++++++++++ go.mod | 19 +++++-------------- go.sum | 10 ++++++++++ 3 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..a784f81 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# git.fsdpf.net/go/condflow + +条件流引擎:把一串"条件 -> 动作"的分支(`CondCase`)按优先级串成一个决策流(`CondFlow`), +输入一份数据,按顺序求值每个分支的条件(复用 `git.fsdpf.net/go/condition` 的 `Condition` +DSL),命中的分支执行对应动作,支持分支之间链式跳转到下一个流。典型场景:审批流程(金额分档 +审批、信用分拒绝)、营销规则(分群发券)等需要"按条件走不同处理逻辑"的业务。 + +## 核心概念 + +- **`CondFlow`**:一个决策流,`New(name string)` 创建,`AddCase(c *CondCase)` 按优先级加入 + 分支,`Run(app do.Injector, input reflux.R, user req.User) error` 执行——按 `getSortedCases()` + 排好的顺序对每个分支求值,命中就执行 `Action`,`WithNextCaseOnSuccess(true)` 控制命中后要不 + 要继续尝试后面的分支(默认命中一个就停)。 +- **`CondCase`**:单个分支,`NewCondCase(name, cond *condition.Condition, action string)` + 构造,绑定一个 `condition.Condition` 和一个 action 的名字(通过 `ActionInvoker` 按名字查 + 实际实现)。`WithPriority`/`WithActionParams`/`WithActionConfig` 配置优先级和动作参数; + `WithNextFlowOnSuccess(flow *CondFlow, params fieldx.Schema)` 支持分支命中后跳转到另一个 + `CondFlow` 继续执行,串成更复杂的决策树。 +- **`Action`/`ActionInvoker`**:实际执行的业务逻辑,`type Action func(ctx Context, cfg + valuex.Accessor) (reflux.R, error)`,`ActionInvoker` 按名字查找、调用具体的 `Action` + 实现(`Executor` 接口 + 反射,`NewActionInvokerWithValue` 支持从一个结构体值上按方法名找 + 对应的 action)。 +- **`Context`/`FlowContext`**:执行上下文,带当前用户(`req.User`)、输入数据的按路径取值 + (`Get`/`GetParam`,基于 `valuex.Accessor`)、`Fork(input)` 派生一个新上下文(分支跳转时 + 用)、`Res() req.Resource` 拿到动作关联的资源。 +- **条件求值**:`CondFlow.makeTable`/`makeCTE` 把输入数据(`reflux.R`)包装成一张虚拟的 + `Flow` 表(用 `db-v2` 的 `CTE`),每个分支的 `condition.Condition.ToSql(...)` 渲染成 + `IF(条件, 1, 0)` 列,一次查询同时算出所有分支是否命中,不用逐个分支单独跑判断逻辑。 + +## 已知问题 + +`tests/example_test.go` 里的 `Example_userApprovalFlow` 目前会失败(预期输出跟实际生成的 SQL +对不上,具体差异待排查),其它测试和例子都正常。 diff --git a/go.mod b/go.mod index fd5b3ad..49f7519 100644 --- a/go.mod +++ b/go.mod @@ -2,21 +2,12 @@ module git.fsdpf.net/go/condflow go 1.25.5 -replace ( - git.fsdpf.net/go/condition => ../condition-v2 - git.fsdpf.net/go/contracts => ../contracts-v2 - git.fsdpf.net/go/db => ../db-v2 - git.fsdpf.net/go/orm => ../orm-v2 - git.fsdpf.net/go/reflux => ../reflux - git.fsdpf.net/go/req => ../req-v2 -) - require ( - git.fsdpf.net/go/condition v0.0.0-00010101000000-000000000000 - git.fsdpf.net/go/contracts v0.0.0-00010101000000-000000000000 - git.fsdpf.net/go/db v0.0.0-00010101000000-000000000000 - git.fsdpf.net/go/reflux v0.0.0-00010101000000-000000000000 - git.fsdpf.net/go/req v0.0.0-00010101000000-000000000000 + git.fsdpf.net/go/condition v0.0.0-20260821010329-dcfd2f42daf4 + git.fsdpf.net/go/contracts v0.0.0-20260821005955-ff3d65db22b5 + git.fsdpf.net/go/db v0.0.0-20260820090948-9c6bb5a83508 + git.fsdpf.net/go/reflux v0.0.0-20260820092857-1f48635da3f1 + git.fsdpf.net/go/req v0.0.0-20260820100114-1d95bf64a2a0 github.com/samber/do/v2 v2.0.0 github.com/stretchr/testify v1.11.1 ) diff --git a/go.sum b/go.sum index afd1858..cf7e2e4 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,16 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +git.fsdpf.net/go/condition v0.0.0-20260821010329-dcfd2f42daf4 h1:8ce14rkXteERFSvK43Xxpjwa1caKHdHX6qHC+6LOCSI= +git.fsdpf.net/go/condition v0.0.0-20260821010329-dcfd2f42daf4/go.mod h1:fgyIm04l+hAGv6Z8oKQqX61CATpzw7D2qaxD1x2ffmA= +git.fsdpf.net/go/contracts v0.0.0-20260821005955-ff3d65db22b5 h1:YrKqs44utdsOm9a7VLh8o3yRtgywmbm1On4gXRxl4n4= +git.fsdpf.net/go/contracts v0.0.0-20260821005955-ff3d65db22b5/go.mod h1:UeD8vBuMp9Z+zexKb0NoLtZGmXwoypE0dFWxJw7Yhso= +git.fsdpf.net/go/db v0.0.0-20260820090948-9c6bb5a83508 h1:xv2SV/Qb0TKJFnzfBtSKSeXwa6NZPRBVoGfWDahsezo= +git.fsdpf.net/go/db v0.0.0-20260820090948-9c6bb5a83508/go.mod h1:oDPmvCdZn/vTpbuPYPYkjdrhpis/XtMIi3eni4sYRvM= +git.fsdpf.net/go/reflux v0.0.0-20260820092857-1f48635da3f1 h1:TRn++7oWwtANQM5JWTQGdW6fAkWMIbIsZX6tzmnsrLQ= +git.fsdpf.net/go/reflux v0.0.0-20260820092857-1f48635da3f1/go.mod h1:8OLCLMUwdsZ8u2sRI9y/qaE4fTf5d0SrCJ6Zn+lttFY= +git.fsdpf.net/go/req v0.0.0-20260820100114-1d95bf64a2a0 h1:HWM1soZb13IIQA69M8DgyLYu9goz7PArtWI2mQay918= +git.fsdpf.net/go/req v0.0.0-20260820100114-1d95bf64a2a0/go.mod h1:Lm8WoA8EYs2696rmlxpySoCQY26Qh97cDxVF6NLBfZ8= git.fsdpf.net/go/utils v0.0.0-20240509025914-c03a9cb48aff h1:1hokQGKGIstoI7WDBir2N24OGgnussZ3GmucK4TQRuI= git.fsdpf.net/go/utils v0.0.0-20240509025914-c03a9cb48aff/go.mod h1:NUoyQtFr905YT+pi850mvSf4YX0WghQIcMQkTvize5o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=