模型和查询钩子

介绍

钩子是用户定义的函数,在某些操作之前和/或之后调用,例如,在每个处理的查询之前。

为了确保您的模型实现了钩子接口,请使用 编译时检查在新窗口中打开,例如,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 还会在扫描行值之前和之后调用 BeforeScanRowAfterScanRow 钩子。例如 示例在新窗口中打开

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{})