模型和查询钩子
介绍
钩子是用户定义的函数,在某些操作之前和/或之后调用,例如,在每个处理的查询之前。
为了确保您的模型实现了钩子接口,请使用 编译时检查,例如,var _ bun.QueryHook = (*MyHook)(nil)
。
免责声明
使用钩子进行验证或缓存似乎是个好主意,因为这样您就不会忘记对数据进行消毒或检查权限。它会产生一种虚假的安全感。
不要这样做。使用钩子的代码更难阅读、理解和调试。它更复杂,更容易出错。相反,更喜欢编写简单的代码,例如 此,即使这意味着重复自己。
func InsertUser(ctx context.Context, db *bun.DB, user *User) error {
// before insert
if _, err := db.NewInsert().Model(user).Exec(ctx); err != nil {
return err
}
// after insert
return nil
}
模型钩子
BeforeAppendModel
要更新插入或更新模型之前的某些字段,请使用 bun.BeforeAppendModelHook
,它在构造查询之前调用。例如 示例
type Model struct {
ID int64
CreatedAt time.Time
UpdatedAt time.Time
}
var _ bun.BeforeAppendModelHook = (*Model)(nil)
func (m *Model) BeforeAppendModel(ctx context.Context, query bun.Query) error {
switch query.(type) {
case *bun.InsertQuery:
m.CreatedAt = time.Now()
case *bun.UpdateQuery:
m.UpdatedAt = time.Now()
}
return nil
}
Before/AfterScanRow
Bun 还会在扫描行值之前和之后调用 BeforeScanRow
和 AfterScanRow
钩子。例如 示例
type Model struct{}
var _ bun.BeforeScanRowHook = (*Model)(nil)
func (m *Model) BeforeScanRow(ctx context.Context) error { return nil }
var _ bun.AfterScanRowHook = (*Model)(nil)
func (m *Model) AfterScanRow(ctx context.Context) error { return nil }
模型查询钩子
您还可以定义模型查询钩子,这些钩子在对特定模型执行特定类型的查询之前和之后调用。此类钩子针对每个查询调用一次,并使用 nil
模型。要访问查询数据,请使用 query.GetModel().Value()
。
var _ bun.BeforeSelectHook = (*Model)(nil)
func (*Model) BeforeSelect(ctx context.Context, query *bun.SelectQuery) error { return nil }
var _ bun.AfterSelectHook = (*Model)(nil)
func (*Model) AfterSelect(ctx context.Context, query *bun.SelectQuery) error { return nil }
var _ bun.BeforeInsertHook = (*Model)(nil)
func (*Model) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error { nil }
var _ bun.AfterInsertHook = (*Model)(nil)
func (*Model) AfterInsert(ctx context.Context, query *bun.InsertQuery) error { return nil }
var _ bun.BeforeUpdateHook = (*Model)(nil)
func (*Model) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error { return nil }
var _ bun.AfterUpdateHook = (*Model)(nil)
func (*Model) AfterUpdate(ctx context.Context, query *bun.UpdateQuery) error { return nil }
var _ bun.BeforeDeleteHook = (*Model)(nil)
func (*Model) BeforeDelete(ctx context.Context, query *bun.DeleteQuery) error { return nil }
var _ bun.AfterDeleteHook = (*Model)(nil)
func (*Model) AfterDelete(ctx context.Context, query *bun.DeleteQuery) error { return nil }
var _ bun.BeforeCreateTableHook = (*Model)(nil)
func (*Model) BeforeCreateTable(ctx context.Context, query *CreateTableQuery) error { return nil }
var _ bun.AfterCreateTableHook = (*Model)(nil)
func (*Model) AfterCreateTable(ctx context.Context, query *CreateTableQuery) error { return nil }
var _ bun.BeforeDropTableHook = (*Model)(nil)
func (*Model) BeforeDropTable(ctx context.Context, query *DropTableQuery) error { return nil }
var _ bun.AfterDropTableHook = (*Model)(nil)
func (*Model) AfterDropTable(ctx context.Context, query *DropTableQuery) error { return nil }
查询钩子
Bun 支持查询钩子,这些钩子在执行查询之前和之后调用。Bun 使用查询钩子来 记录查询 以及 性能监控。
type QueryHook struct{}
func (h *QueryHook) BeforeQuery(ctx context.Context, event *bun.QueryEvent) context.Context {
return ctx
}
func (h *QueryHook) AfterQuery(ctx context.Context, event *bun.QueryEvent) {
fmt.Println(time.Since(event.StartTime), string(event.Query))
}
db.AddQueryHook(&QueryHook{})