# 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` 分支。