feat: Hooks 新增 UseTx,Before/After 改用类型化的 HookError

之前 Hooks.Before/After 返回裸 error,调用方没法区分"钩子本身失败"和"SQL
执行失败"。改成返回 *HookError(包一层 exec.HookError),配合 errors.As
能精确识别。

同时给 Hooks 加一个 UseTx(dataset) (QueryFactory, error) 方法,在 Before
之前调用,允许钩子在写操作真正执行前替换掉默认连接(比如需要自动开事务包住
写操作和写后回调的场景),返回 nil, nil 表示沿用默认连接。目前只有
InsertDataset/UpdateDataset/DeleteDataset 会调用 UseTx,SelectDataset
(只读)不需要。
This commit is contained in:
2026-08-20 17:08:29 +08:00
parent c8d1d2f219
commit 6ed2803158
7 changed files with 220 additions and 10 deletions
+12 -2
View File
@@ -306,12 +306,22 @@ func (id *InsertDataset) ReturnsColumns() bool {
// db.Insert("test").Rows(Record{"name":"Bob"}).Executor().Exec()
func (id *InsertDataset) Executor() (executor exec.QueryExecutor) {
if id.hooks != nil {
id.SetError(id.hooks.Before(id))
if qf, err := id.hooks.UseTx(id); err != nil {
id.SetError(err)
} else if qf != nil {
id.queryFactory = qf
}
if herr := id.hooks.Before(id); herr != nil {
id.SetError(herr)
}
}
executor = id.queryFactory.FromSQLBuilder(id.insertSQLBuilder())
if id.hooks != nil {
executor.Hook(func(result interface{}) error {
return id.hooks.After(id, result)
if herr := id.hooks.After(id, result); herr != nil {
return herr
}
return nil
})
}
return executor