Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d203e02
fix(crud): 保证分组树与实体事件事务一致性
zhou-hao Oct 10, 2026
8fbd0cf
fix(crud): 串行处理树分片及父子路径
zhou-hao Oct 10, 2026
d8f4e39
fix(认证): 保留只读维度类型的必选字段
zhou-hao Oct 10, 2026
3a9953c
test(认证): 隔离测试数据库并修正自动配置
zhou-hao Oct 10, 2026
d64ac0f
fix(crud): 修复同批移动路径与子树删除分片
zhou-hao Oct 10, 2026
1646ade
fix(crud): 保留稀疏树更新字段并修复同步移根
zhou-hao Oct 10, 2026
9a8ffd8
fix(框架): 修复稀疏树更新与维度成员身份
zhou-hao Oct 11, 2026
7050c33
fix(树CRUD): 修复新增子级路径及并发删除重插
zhou-hao Oct 11, 2026
2c7ae8a
fix(树CRUD): 避免稀疏更新覆盖已提交树移动
zhou-hao Oct 11, 2026
bc5317e
test(树CRUD): 补全树操作与事务集成场景
zhou-hao Oct 12, 2026
d3379b5
refactor(CRUD): 将普通DSL事务边界交还业务服务
zhou-hao Oct 12, 2026
a8b556f
fix(成员绑定): 恢复已发布成员ID与原服务行为
zhou-hao Oct 12, 2026
1cadc45
fix(树CRUD): 隔离稀疏更新输入与持久图补齐
zhou-hao Oct 12, 2026
e373b68
refactor(树CRUD): 提供通用删除准备阶段并重读当前子树
zhou-hao Oct 12, 2026
2cc826f
test(树CRUD): 明确完整保存与实体事件校验契约
zhou-hao Oct 13, 2026
3bf1a76
fix(树CRUD)!: 统一根标记及同步保存更新入口
zhou-hao Oct 13, 2026
63b0f29
fix(框架): 解决动态维度与5.0.x主线冲突
zhou-hao Oct 20, 2026
0748ee9
fix(树结构): 统一空父级与显式根标记保存
zhou-hao Oct 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,132 @@
5. 坐等审查
6. 合并

## 事务边界与通用树集成测试

普通 `ReactiveCrudService.createUpdate/createDelete` 返回仓储 DSL,不隐式开启事务。
需要将 SQL、实体事件及其他写入一起回滚时,业务 Service 应对完整业务 Publisher 明确声明
事务;命名 CRUD 方法保持其事务注解。基础树 insert/save/update/delete 的复合操作由
程序式事务保持完整原子性,直接调用非代理树 Service 也应在后批失败或取消时整体回滚。
普通缓存 DSL 保持既有 hook 行为:修改数量大于零时清除缓存,零修改时不清除。

树 CRUD 的测试使用真实 JDBC/R2DBC 仓储、实体事件和原事务。期望关系根据测试输入的
`parentId` 独立推导,不调用生产树准备 helper 生成期望值;回滚比较完整持久化快照,
取消执行后等待事务 `afterCompletion` 再查询数据库。

实体事件失败与调用方失败使用独立分支。事件失败分支必须由真实
`EntityCreatedEvent`、`EntitySavedEvent`、`EntityModifyEvent` 或 `EntityDeletedEvent` 的监听器拒绝触发,
不能额外抛出调用方异常使测试误通过。同步删除的 after 监听器还核对原事务内 SQL
已执行,再验证事件拒绝使整棵子树及调用方先前写入一起恢复。

用例入口:

1. `SyncTreeCrudRegressionTest`:乱序多根 `insert(Collection)`、小批次 `save(List)`
深层移动与遗漏后代、后批实体事件/调用方失败,以及重叠 seed 的 `deleteById(Collection)`。
2. `ReactiveTreeCrudCoverageTest`:两种 `updateById` 的现有缺父级/循环拒绝规则;
同步与响应式共用 forest 夹具逐层验证查询 children、明确指定的排序、默认排序索引。
3. `ReactiveTreeCrudCoverageTest`:buffer=2 子树删除在后批 SQL/事件开始后取消,
确认整棵树与调用方写入一起回滚;非代理树复合操作在后批失败或取消时恢复完整快照,
追加 hook 不重复执行原 seed SQL。
4. `PlainCrudTransactionTest`:Spring 代理业务事务内的真实事件失败与 SQL 后取消;
无调用方事务的普通 DSL 不承诺隐式回滚,追加 hook 和 SQL 执行次数保持仓储行为。
5. `GenericReactiveCacheSupportCrudServiceTest`:有无调用方事务时,普通缓存 DSL 的
正修改/零修改结果、缓存清除和追加 hook 顺序;`ScopedReactiveTreeSortEntityServiceTest`
验证普通更新的调用方事务与树删除自身事务。

这些用例维持入口契约:同步树准备覆盖 `insert(Collection)` 及 `save(E)`、`save(Collection)`、`save(List)`,
不把普通同步 `updateById` 定义为结构修图入口;没有指定排序的查询不保证顺序,
同步删除不要求叶先执行。路径容量边界按实际实体 schema 验证,不扩大 schema。

`hsweb-commons-crud` 相关集成测试的定向验证命令:
`mvn -pl hsweb-commons/hsweb-commons-crud -am -Dtest=PlainCrudTransactionTest,GenericReactiveCacheSupportCrudServiceTest,ScopedReactiveTreeSortEntityServiceTest,SyncTreeCrudRegressionTest,ReactiveTreeCrudCoverageTest -Dsurefire.failIfNoSpecifiedTests=false test`。
同步删除的正式实体事件依赖 easy-orm 同步 DSL 的默认 mapping/repository 上下文和执行级
before/after/error 共享上下文。干净 CI 使用 easy-orm `4.2` 中包含该通用修复的
`4.2.2-SNAPSHOT`。运行结果记录在对应 PR 的验证证据中。

## 树 Save 与部分更新的契约

树 Save 和响应式 `updateById` 对已有节点的 `parentId=null` 或缺省沿用持久父级;
新增节点没有父级时仍为根。显式根标记默认使用空串或 `-1`,由服务现有的
`isRootNode(E)` 扩展点判定,自定义标记沿用同一规则。历史 `parentId=null` 的根继续
识别。嵌套 `children` 表达的父子关系优先于子节点自身输入或原持久父级。

共用 helper 只补齐已有 Save 节点未指定的父级,再维护 path/level 和原有后代;
不把完整 Save 改造成部分更新。遗漏 children 不自动删除后代。业务列的 null 仍遵循
现有 ORM 忽略 null、生成默认值等规则,这一契约不提供整实体的全量 Replace。
显式标记与最终业务输入一起通过正式 Save 写入,不先执行父级清空或路径预更新。
BeforeSave 读取数据库时看到旧父级,同时接收最终准备好的移根及改名输入;Save 不额外
发布 Modify 事件,Saved 事件拒绝仍回滚整个操作、所有批次及调用方事务中的先前写入。

公开 `PATCH /资源` 是批量 Save/upsert,已有 ID 保存、不存在的 ID 新增;
`PUT /资源/{id}` 是正式 `updateById` 部分更新入口,null 沿用持久父级和业务字段。
既有节点的名称等稀疏修改可省略父级;移根必须明确提交服务识别的非 null 根标记。
同步树准备覆盖 `insert(Collection)` 及全部 Save 入口,普通同步 `updateById` 不提供
结构修图;响应式树 `updateById` 维护显式关系变化及遗漏后代的必要树字段。

实现位于 `hsweb-commons/hsweb-commons-crud` 的 `TreeSortServiceHelper`、
`TreeSortEntityService`、`ReactiveTreeSortEntityService`;公开路由由
`ReactiveServiceSaveController` 提供。`ExplicitTreeUpdateRegressionTest` 通过真实
R2DBC H2 / HTTP 和正式实体事件验证 PUT 遗漏或传 null 父级时保留关系,及 PATCH
显式根标记移根、保留遗漏后代和同批不存在 ID 新增。

根标记由 `parentId` 表达;实体自身 ID 为 `-1` 且拥有合法父级时,
仍按普通节点维护。共用 helper 使用服务的根节点判定排除根标记,缺失真实父级和循环
继续沿用原有拒绝规则。

同步 `save(E)`、`save(Collection)` 委托现有 `save(List)`,维护同一完整树关系及遗漏
后代。同步 `updateById` 直接执行仓储 UPDATE,缺失目标返回零、不新增,普通业务字段
部分更新通过正式 Modify before/after 校验,该入口不承担同步结构 patch。已发布
`save(E)` 覆写中的既有更新业务校验须迁移至正式 Modify 事件;Save 覆写只拥有保存入口。

`TreeRootMarkerRegressionTest` 与 `SyncTreeEntryPointContractTest` 使用真实 R2DBC / JDBC
H2、正式实体事件和共用持久树断言,覆盖根标记、三个同步 Save 入口、缺失/既有目标
UPDATE,以及正式同步 Modify after 拒绝使完整目标快照及调用方先前写入在原事务中回滚。
新增及调整回归同时覆盖三个同步 Save 入口、响应式稀疏 Save、自定义根标记、嵌套父级
优先级和正式 Save 事件的可见性及回滚;这些回归已纳入下述集中验证。

## 树 updateById 的业务校验边界

响应式树 `updateById` 对目标及显式既有 child 保持纯 UPDATE,使用正式 Modify 的
完整 before/after 事件;目标已被另一事务删除时返回零,不能以 Save/UPSERT 重新
创建目标或继续创建 child。显式新 child 经过服务 Save;自动补齐的后代只维护必要树字段。

`save(Publisher)` 覆写只拥有 Save 入口。原来在该覆写中校验既有节点更新的业务,需要
将更新规则迁移到 `EntityBeforeModifyEvent.getAfter()`;新增和 Save 分别监听
`EntityBeforeCreateEvent` / `EntityBeforeSaveEvent`,共同调用业务模块自己的校验函数。
既有 Save 覆写不会自动成为 UPDATE 的校验入口。

`TreeEntityEventValidationRegressionTest` 的 8 个真实 Spring / R2DBC H2 用例已通过:
两种 updateById overload 的目标拒绝、显式既有 child 拒绝和新 child 拒绝,以及直接
Create/Save 共用校验。正式 Modify after 包含持久业务列和完整树字段,child 拒绝前
读取实际已写父节点,拒绝后原事务恢复整个持久快照。

树 Save 根标记变更后的集中 `clean install` 验证通过:24 类、178 项,
0 失败、0 错误、0 跳过,覆盖真实 JDBC / R2DBC 树回归及认证兼容切片。
树回归的定向复验入口为:
`mvn -pl hsweb-commons/hsweb-commons-crud -am '-Dtest=*Tree*Test,PlainCrudTransactionTest,GenericReactiveCacheSupportCrudServiceTest' -Dsurefire.failIfNoSpecifiedTests=false test`。
该范围包含 Save 事件可见性、跨批 / 调用方事务回滚和纯 UPDATE 兼容。
普通树并发边界见下节。

## 普通树删除的并发边界

响应式普通树在子树展开后按 ID 快照执行叶先分批删除。没有 parent 外键或共同领域
约束时,另一事务在展开与删除 SQL 之间提交的新 child 可能不在删除快照内,并留下
失去父节点的记录;框架当前不保证普通树并发新增/删除的关系完整性。

当前方案不新增通用锁,也不扩大已有领域锁策略。业务需要该并发保证时,应让关联
写入和删除遵守同一领域约束;已有 `prepareTreeDelete` 领域锁的保证仅适用于共同
遵守该约束的操作。框架已验证的复合事务、完整实体事件、分组隔离、叶先分批、取消
与回滚,不能外推为所有普通树的并发关系保证。

## 成员 ID 兼容性验证

`DimensionUserEntity.generateId()` 保持原有三字段以 `-` 拼接后的 MD5 规则;已提供的
ID 保持不变。`DimensionUserIdentityTest` 固定验证旧 ID,
`DimensionUserIdentityRegressionTest` 使用真实数据库和绑定事件验证按已知 ID 保存、
重复保存更新、查询及解绑;完整认证绑定行为同时由 `DefaultDimensionUserServiceTest` 验证。
定向验证命令:
`mvn -pl hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default -am -Dtest=DimensionUserIdentityTest,DimensionUserIdentityRegressionTest,DefaultDimensionUserServiceTest -Dsurefire.failIfNoSpecifiedTests=false test`。

# BUG
如果知道导致bug的位置,你可以直接修改后`pull request`,也可以提交[issues](https://github.com/hs-web/hsweb-framework/issues/new).我们会尽快解决.

Expand Down
Loading
Loading