From dcfd2f42daf45bf43b9e2cafb6cf6bbca5d15e57 Mon Sep 17 00:00:00 2001 From: what Date: Fri, 21 Aug 2026 09:03:29 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=20README=EF=BC=8C?= =?UTF-8?q?=E8=AF=B4=E6=98=8E=E5=BD=93=E5=89=8D=E5=88=86=E6=94=AF=E7=9A=84?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 配合 v1-legacy 维护分支的拆分,记录 master 这条线(Condition/ConditionExpr 表达式树、TokenValue、JSON 序列化、engine 规则引擎)目前有哪些能力,跟 v1-legacy 分支做区分;顺带记一下 engine.go 那个已知的 nil user 问题。 --- README.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d152cab..7298c28 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,54 @@ -# condition +# git.fsdpf.net/go/condition(master) +条件表达式 DSL:把一组条件(等值/比较/模糊匹配/IN 等)组织成可嵌套的 `AND`/`OR` 树,渲染成 +`db-v2` 的表达式(`db.Expression`),供权限过滤、规则引擎等场景复用同一套条件描述。配合 +"-v2" 系列项目使用。 + +## 这个仓库有什么 + +### `Condition`/`ConditionExpr` + +- `Condition`:条件树的节点,`AppendTo`/`SetCondition`/`SetExpr` 组装子条件/表达式, + `ToSql(m TokenValue) db.Expression` 渲染成 `db-v2` 的表达式树——内部用 + `exp.NewExpressionList(this.typ, conditions...)` 构造,不是手工拼 SQL 字符串。 + `ConditionType` 是 `exp.ExpressionListType`(`AND`/`OR`)的类型别名。 +- `ConditionExpr`:单个表达式(字段 + 操作符 + 值),`ConditionOperator` 是 + `exp.BooleanOperation` 的类型别名(`EQ`/`NE`/`GT`/`LIKE`/`IN` 等),跟 `db-v2` 的操作符 + 体系直接对齐,不用自己维护一份字符串常量再转换。 +- `util.go`:`ToConditionOperator(op string) ConditionOperator` 把字符串(比如从配置/请求 + 参数解析出来的)转成 `ConditionOperator`。 + +### `TokenValue`(`token_value.go`) + +条件渲染时取值用的接口:`GetParam(k string) valuex.Accessor`(配合 `reflux/valuex` 统一属性 +访问方式)+ `User() req.User`。`NewTokenValue(x valuex.Accessor, opts ...tValueOpt)` 构造, +`WithUser(user)` 显式指定用户;不传时会尝试从 `x` 上探测 `User()` 方法,两者都拿不到会 +panic——`TokenValue` 必须绑定一个具体用户,不支持匿名/无用户场景。 + +### JSON 序列化(`condition_json.go`) + +`Condition`/`ConditionExpr` 都实现了 `MarshalJSON`/`UnmarshalJSON`(内部过一层 DTO 结构避免 +递归),`FromMap(m map[string]any) (*Condition, error)` 直接从已解析好的 map 构造,不用先转 +成 JSON 字符串再解析一遍——典型场景是权限配置、规则条件存在数据库的 JSON 列里,读出来直接 +反序列化成 `Condition` 用。 + +### `engine` 子包:规则引擎 + +`Engine[T any]`:按 `Case(cond *condition.Condition, cb func(data T, g req.GlobalParams) error)` +注册一组"条件 -> 回调"规则,`Execute(data T)` 对传入数据求值,命中第一个条件为真的分支就 +调用对应回调(`Default(cb)` 兜底)。内部通过 `db/engine`(sqlite3 内存库)把 `data`(用 +`reflux.R` 包装)当成一行虚拟数据跑 SQL 判断条件是否成立,不用自己写一套表达式求值器。 +`EngineOption`(`Debug()`/`Relation(...)`)控制调试日志和关联字段展开。 + +## 已知问题 + +`engine.go` 在调用方没有显式传 `GlobalParams` 时,会用 `nil` user 构造一个兜底值,这跟 +`TokenValue` 现在强制要求非 nil user 冲突,`TestEngine` 目前会 panic——待 `Engine.Execute` +支持显式传 user 时一并解决,暂时未修。 + +## 分支状态 + +`master` 是持续开发中的新架构,**跟老仓库 `v1-legacy` 分支不兼容**——`Condition.ToSql` 从手工 +拼 SQL 字符串换成了 `db-v2` 表达式树,`TokenValue` 从 `req.GlobalParams` 换成了 +`reflux/valuex`,`engine` 包的连接管理也换成了 `db/engine`。还在用老版 API 的老项目,参见 +`v1-legacy` 分支。