-
Couldn't load subscription status.
- Fork 152
Hooks
Generally, User use Hook will implement the callback method through the operated document. But many operations of Qmgo don't have documents as parameter(like Update method), which we think it's a very concise way.
So the Hook v1 of Qmgo will be different from the "general" Hook implementation:
-
The user implements the struct method of Hook, and passes it through
optionsof a specific operation API, thenQmgoautomatically do callback. -
Only
InsertOne、InsertMany、UpsertandReplaceOnecan do hook withoutoptions -
If the
Hookoperation fails, there is no rollback operation in current version. -
The hook before and after a certain operation takes effect independently, for example, you only need to implement
BeforeInsert() errorto make hook before insert work.
User need to implement struct methods to use Insert Hook:
BeforeInsert(ctx context.Context) error // implement it for hook before insert
AfterInsert(ctx context.Context) error // implement it for hook after insertIn the InsertOne process
-
Implement the
Hookmethod ofInsertthrough a custom struct (Userin the following example) -
Pass in
options.InsertOneOptionsto makeHookwork -
If the second parameter doc implement the
Hookmethod,options.InsertOneOptionscan be ignore in InsertOne. -
If you use the document
Userto implement the method and modify the document inBeforeInsert(), the modified document will be inserted into the database
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
}
func (u *User) BeforeInsert(ctx context.Context) error {
fmt.Println("before insert called")
return nil
}
func (u *User) AfterInsert(ctx context.Context) error {
fmt.Println("before insert called")
return nil
}
u := &User{Name: "Alice", Age: 7}
_, err := cli.InsertOne(context.Background(), u)
// following example also works
// _, err := cli.InsertOne(context.Background(), u, options.InsertOneOptions{
// InsertHook: u,
// })In the InsertMany process
-
Implement the
Hookmethod ofInsertthrough a custom structure (Userin the following example), -
Pass in
options.InsertManyOptionsto makeHookwork. -
If the second parameter
docsimplement theHookmethod,options.InsertManyOptionscan be ignore inInsertMany. -
If you use the document
Userto implement method and modify the document inBeforeInsert(), the modified document will be inserted into the database -
Because multiple documents are inserted, and
Hookhappens for each document, soHookwill be called back multiple times according to the number of inserted documents
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
}
func (u *User) BeforeInsert(ctx context.Context) error {
fmt.Println("before insert called")
return nil
}
func (u *User) AfterInsert(ctx context.Context) error {
fmt.Println("before insert called")
return nil
}
u1 := &User{Name: "Lucas", Age: 7}
u2 := &User{Name: "Alice", Age: 7}
us := []*User{u1, u2}
_, err := cli.InsertMany(ctx, us)
// following example also works
// _, err := cli.InsertMany(ctx, us, options.InsertManyOptions{
// InsertHook: us,
// })User need to implement struct methods to use Update Hook:
BeforeUpdate(ctx context.Context) error // implement it for hook before update
AfterUpdate(ctx context.Context) error // implement it for hook after update-
Implement the
Hookmethod ofUpdatethrough a custom struct (MyUpdateHookin the following example) -
Pass in
options.UpdateOptionsto makeHookwork. -
If you use the document
Userto directly implement methods and modify the document in theBeforeUpdate(), will not affect the document written in the database.
type MyUpdateHook struct {
beforeUpdateCount int
afterUpdateCount int
}
func (u *MyUpdateHook) BeforeUpdate(ctx context.Context) error {
u.beforeUpdateCount++
return nil
}
func (u *MyUpdateHook) AfterUpdate(ctx context.Context) error {
u.afterUpdateCount++
return nil
}
u := User{Name: "Lucas", Age: 7}
uh := &MyUpdateHook{}
_, err := cli.InsertOne(context.Background(), u)
ast.NoError(err)
err = cli.UpdateOne(ctx, bson.M{"name": "Lucas"}, bson.M{operator.Set: bson.M{"age": 27}}, options.UpdateOptions{
UpdateHook: uh,
})
cli.UpdateAll(ctx, bson.M{"name": "Lucas"}, bson.M{operator.Set: bson.M{"age": 27}}, options.UpdateOptions{
UpdateHook: uh,
})-
Implement the
Hookmethod ofUpdatethrough a custom struct (Userin the following example) -
Pass in
options.UpdateOptionsto makeHookwork. -
If the third parameter
docimplement theHookmethod,options.UpdateOptionscan be ignore inReplaceOne. -
If you use the document
Userto directly implement methods and modify the document in theBeforeUpdate(), the modified document will be updated into the database.
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
beforeUpdate int
afterUpdate int
}
func (u *User) BeforeUpdate(ctx context.Context) error {
u.beforeUpdate++
return nil
}
func (u *User) AfterUpdate(ctx context.Context) error {
u.afterUpdate++
return nil
}
u := &User{}
err = cli.ReplaceOne(ctx, bson.M{"name": "Lucas"}, &u)
// following example also works
// err = cli.ReplaceOne(ctx, bson.M{"name": "Lucas"}, &u, options.UpdateOptions{
// UpdateHook: u,
// })User need to implement struct methods to use Upsert Hook:
BeforeUpsert(ctx context.Context) error // implement it for hook before upsert
AfterUpsert(ctx context.Context) error // implement it for hook before upsertIn the Upsert API
-
Implement the
Hookmethod ofUpsertthrough a custom struct (Userin the following example) -
Pass in
options.UpsertOptionsto makeHookwork -
If the second parameter doc implement the
Hookmethod,options.UpsertOptionscan be ignore in Upsert. -
If you use the document
Userto implement the method and modify the document inBeforeUpsert(), the modified document will be inserted into the database
type User struct {
Name string `bson:"name"`
Age int `bson:"age"`
}
func (u *User) BeforeUpsert(ctx context.Context) error {
return nil
}
func (u *User) AfterUpsert(ctx context.Context) error {
return nil
}
u := &User{Name: "Alice", Age: 7}
_, err = cli.Upsert(context.Background(), bson.M{"name": "Lucas"}, u)
// following example also works
// _, err = cli.Upsert(context.Background(), bson.M{"name": "Lucas"}, u, options.UpsertOptions{
// UpsertHook: myHook,
//})User need to implement struct methods to use Remove Hook:
BeforeRemove(ctx context.Context) error // implement it for hook before remove
AfterRemove(ctx context.Context) error // implement it for hook before remove-
A custom structure (
MyRemoveHookin the following example) implements theHookmethod ofRemove -
Pass in
options.RemoveOptionsto makeHookwork.
type MyRemoveHook struct {
beforeCount int
afterCount int
}
func (m *MyRemoveHook) BeforeRemove(ctx context.Context) error {
m.beforeCount++
return nil
}
func (m *MyRemoveHook) AfterRemove(ctx context.Context) error {
m.afterCount++
return nil
}
rh := &MyRemoveHook{}
err = cli.Remove(ctx, bson.M{"age": 17}, options.RemoveOptions{
RemoveHook: rh,
})
rh = &MyRemoveHook{}
_, err = cli.RemoveAll(ctx, bson.M{"age": "7"}, options.RemoveOptions{
RemoveHook: rh,
})User need to implement struct methods to use Query Hook:
BeforeQuery(ctx context.Context) error // implement it for hook before query
AfterQuery(ctx context.Context) error // implement it for hook before query- A custom struct (
MyQueryHookin the following example) implements theHookmethod ofQuery - Pass in
options.FindOptionsto makeHookwork.
type MyQueryHook struct {
beforeCount int
afterCount int
}
func (q *MyQueryHook) BeforeQuery(ctx context.Context) error {
q.beforeCount++
return nil
}
func (q *MyQueryHook) AfterQuery(ctx context.Context) error {
q.afterCount++
return nil
}
qk := &MyQueryHook{}
err = cli.Find(ctx, bson.M{"age": 17}, options.FindOptions{
QueryHook: qk,
}).One(ur)
err = cli.Find(ctx, bson.M{"age": 17}, options.FindOptions{
QueryHook: qh,
}).All(&ur)