Skip to content

Commit a9fc72d

Browse files
Feat: Refactor model hook and add beforeUpdate hook registration for field hook. #55
feat: - hook: refactor the model hook to add support for the `beforeDelete`, `afterDelete`, `beforeUpdate`, `afterUpdate`, and `beforeFind` hooks in MongoDB operations. - plugin: add the registration of the `beforeUpdate` hook when the field hook is enabled.
1 parent 206e1d3 commit a9fc72d

File tree

4 files changed

+337
-4
lines changed

4 files changed

+337
-4
lines changed

callback.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type PluginConfig struct {
4646

4747
func InitPlugin(config *PluginConfig) {
4848
if config.EnableDefaultFieldHook {
49-
opTypes := []operation.OpType{operation.OpTypeBeforeInsert, operation.OpTypeBeforeUpsert}
49+
opTypes := []operation.OpType{operation.OpTypeBeforeInsert, operation.OpTypeBeforeUpdate, operation.OpTypeBeforeUpsert}
5050
for _, opType := range opTypes {
5151
typ := opType
5252
RegisterPlugin("mongox:default_field", func(ctx context.Context, opCtx *operation.OpContext, opts ...any) error {
@@ -57,8 +57,10 @@ func InitPlugin(config *PluginConfig) {
5757
if config.EnableModelHook {
5858
opTypes := []operation.OpType{
5959
operation.OpTypeBeforeInsert, operation.OpTypeAfterInsert,
60+
operation.OpTypeBeforeDelete, operation.OpTypeAfterDelete,
61+
operation.OpTypeBeforeUpdate, operation.OpTypeAfterUpdate,
6062
operation.OpTypeBeforeUpsert, operation.OpTypeAfterUpsert,
61-
operation.OpTypeAfterFind,
63+
operation.OpTypeBeforeFind, operation.OpTypeAfterFind,
6264
}
6365
for _, opType := range opTypes {
6466
typ := opType

callback_test.go

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,46 @@ func TestPluginInit_EnableEnableDefaultFieldHook(t *testing.T) {
257257
require.NotZero(t, model.ID)
258258
require.NotZero(t, model.CreatedAt)
259259
RemovePlugin("mongox:default_field", operation.OpTypeBeforeInsert)
260+
RemovePlugin("mongox:default_field", operation.OpTypeBeforeUpdate)
261+
RemovePlugin("mongox:default_field", operation.OpTypeBeforeUpsert)
262+
})
263+
t.Run("beforeUpdate", func(t *testing.T) {
264+
var (
265+
model = &Model{}
266+
m = bson.M{}
267+
)
268+
err := callback.GetCallback().Execute(
269+
context.Background(),
270+
operation.NewOpContext(nil, operation.WithDoc(model), operation.WithUpdates(m)),
271+
operation.OpTypeBeforeUpdate,
272+
)
273+
require.Nil(t, err)
274+
require.Zero(t, model.ID)
275+
require.Zero(t, model.CreatedAt)
276+
require.Zero(t, model.UpdatedAt)
277+
278+
cfg := &PluginConfig{
279+
EnableDefaultFieldHook: true,
280+
}
281+
InitPlugin(cfg)
282+
283+
err = callback.GetCallback().Execute(
284+
context.Background(),
285+
operation.NewOpContext(nil, operation.WithDoc(model), operation.WithUpdates(m)),
286+
operation.OpTypeBeforeUpdate,
287+
)
288+
require.Nil(t, err)
289+
require.Zero(t, model.ID)
290+
require.Zero(t, model.CreatedAt)
291+
require.NotZero(t, model.UpdatedAt)
292+
require.Equal(t, bson.M{
293+
"$set": bson.M{
294+
"updated_at": model.UpdatedAt,
295+
},
296+
}, m)
297+
298+
RemovePlugin("mongox:default_field", operation.OpTypeBeforeInsert)
299+
RemovePlugin("mongox:default_field", operation.OpTypeBeforeUpdate)
260300
RemovePlugin("mongox:default_field", operation.OpTypeBeforeUpsert)
261301
})
262302
t.Run("beforeUpsert", func(t *testing.T) {
@@ -299,6 +339,7 @@ func TestPluginInit_EnableEnableDefaultFieldHook(t *testing.T) {
299339
}, m)
300340

301341
RemovePlugin("mongox:default_field", operation.OpTypeBeforeInsert)
342+
RemovePlugin("mongox:default_field", operation.OpTypeBeforeUpdate)
302343
RemovePlugin("mongox:default_field", operation.OpTypeBeforeUpsert)
303344
})
304345
}
@@ -315,6 +356,26 @@ func (t *testModelHookStruct) AfterInsert(_ context.Context) error {
315356
return nil
316357
}
317358

359+
func (t *testModelHookStruct) BeforeDelete(_ context.Context) error {
360+
*t++
361+
return nil
362+
}
363+
364+
func (t *testModelHookStruct) AfterDelete(_ context.Context) error {
365+
*t++
366+
return nil
367+
}
368+
369+
func (t *testModelHookStruct) BeforeUpdate(_ context.Context) error {
370+
*t++
371+
return nil
372+
}
373+
374+
func (t *testModelHookStruct) AfterUpdate(_ context.Context) error {
375+
*t++
376+
return nil
377+
}
378+
318379
func (t *testModelHookStruct) BeforeUpsert(_ context.Context) error {
319380
*t++
320381
return nil
@@ -325,6 +386,11 @@ func (t *testModelHookStruct) AfterUpsert(_ context.Context) error {
325386
return nil
326387
}
327388

389+
func (t *testModelHookStruct) BeforeFind(_ context.Context) error {
390+
*t++
391+
return nil
392+
}
393+
328394
func (t *testModelHookStruct) AfterFind(_ context.Context) error {
329395
*t++
330396
return nil
@@ -392,6 +458,82 @@ func TestPluginInit_EnableModelHook(t *testing.T) {
392458
wantErr: nil,
393459
want: 2,
394460
},
461+
{
462+
name: "beforeDelete",
463+
ctx: context.Background(),
464+
ocOption: func(tm *testModelHookStruct) []operation.OpContextOption {
465+
return []operation.OpContextOption{
466+
operation.WithModelHook(tm),
467+
}
468+
},
469+
opType: operation.OpTypeBeforeDelete,
470+
wantErr: nil,
471+
want: 1,
472+
},
473+
{
474+
name: "afterDelete",
475+
ctx: context.Background(),
476+
ocOption: func(tm *testModelHookStruct) []operation.OpContextOption {
477+
return []operation.OpContextOption{
478+
operation.WithModelHook(tm),
479+
}
480+
},
481+
opType: operation.OpTypeAfterDelete,
482+
wantErr: nil,
483+
want: 1,
484+
},
485+
{
486+
name: "beforeUpdate",
487+
ctx: context.Background(),
488+
ocOption: func(tm *testModelHookStruct) []operation.OpContextOption {
489+
return []operation.OpContextOption{
490+
operation.WithUpdates(tm),
491+
}
492+
},
493+
opType: operation.OpTypeBeforeUpdate,
494+
wantErr: nil,
495+
want: 1,
496+
},
497+
{
498+
name: "beforeUpdate with model hook",
499+
ctx: context.Background(),
500+
ocOption: func(tm *testModelHookStruct) []operation.OpContextOption {
501+
*tm = 1
502+
return []operation.OpContextOption{
503+
operation.WithUpdates(new(testModelHookStruct)),
504+
operation.WithModelHook(tm),
505+
}
506+
},
507+
opType: operation.OpTypeBeforeUpdate,
508+
wantErr: nil,
509+
want: 2,
510+
},
511+
{
512+
name: "afterUpdate",
513+
ctx: context.Background(),
514+
ocOption: func(tm *testModelHookStruct) []operation.OpContextOption {
515+
return []operation.OpContextOption{
516+
operation.WithUpdates(tm),
517+
}
518+
},
519+
opType: operation.OpTypeAfterUpdate,
520+
wantErr: nil,
521+
want: 1,
522+
},
523+
{
524+
name: "afterUpdate with model hook",
525+
ctx: context.Background(),
526+
ocOption: func(tm *testModelHookStruct) []operation.OpContextOption {
527+
*tm = 1
528+
return []operation.OpContextOption{
529+
operation.WithUpdates(new(testModelHookStruct)),
530+
operation.WithModelHook(tm),
531+
}
532+
},
533+
opType: operation.OpTypeAfterUpdate,
534+
wantErr: nil,
535+
want: 2,
536+
},
395537
{
396538
name: "beforeUpsert",
397539
ctx: context.Background(),
@@ -444,6 +586,18 @@ func TestPluginInit_EnableModelHook(t *testing.T) {
444586
wantErr: nil,
445587
want: 2,
446588
},
589+
{
590+
name: "beforeFind",
591+
ctx: context.Background(),
592+
ocOption: func(tm *testModelHookStruct) []operation.OpContextOption {
593+
return []operation.OpContextOption{
594+
operation.WithModelHook(tm),
595+
}
596+
},
597+
opType: operation.OpTypeBeforeFind,
598+
wantErr: nil,
599+
want: 1,
600+
},
447601
{
448602
name: "afterFind",
449603
ctx: context.Background(),
@@ -500,8 +654,13 @@ func TestPluginInit_EnableModelHook(t *testing.T) {
500654
func remoteModelPlugin() {
501655
RemovePlugin("mongox:model", operation.OpTypeBeforeInsert)
502656
RemovePlugin("mongox:model", operation.OpTypeAfterInsert)
657+
RemovePlugin("mongox:model", operation.OpTypeBeforeDelete)
658+
RemovePlugin("mongox:model", operation.OpTypeAfterDelete)
659+
RemovePlugin("mongox:model", operation.OpTypeBeforeUpdate)
660+
RemovePlugin("mongox:model", operation.OpTypeAfterUpdate)
503661
RemovePlugin("mongox:model", operation.OpTypeBeforeUpsert)
504662
RemovePlugin("mongox:model", operation.OpTypeAfterUpsert)
663+
RemovePlugin("mongox:model", operation.OpTypeBeforeFind)
505664
RemovePlugin("mongox:model", operation.OpTypeAfterFind)
506665
}
507666

hook/model/model.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ func getPayload(opCtx *operation.OpContext, opType operation.OpType) any {
2828
if opCtx.ModelHook != nil {
2929
return opCtx.ModelHook
3030
}
31+
3132
switch opType {
3233
case operation.OpTypeBeforeInsert, operation.OpTypeAfterInsert, operation.OpTypeAfterFind:
3334
return opCtx.Doc
34-
case operation.OpTypeBeforeUpsert, operation.OpTypeAfterUpsert:
35+
case operation.OpTypeBeforeUpdate, operation.OpTypeAfterUpdate, operation.OpTypeBeforeUpsert, operation.OpTypeAfterUpsert:
3536
return opCtx.Updates
3637
default:
37-
return nil
38+
return opCtx.ModelHook
3839
}
3940
}
4041

@@ -81,6 +82,22 @@ func execute(ctx context.Context, doc any, opType operation.OpType, _ ...any) er
8182
if m, ok := doc.(AfterInsert); ok {
8283
return m.AfterInsert(ctx)
8384
}
85+
case operation.OpTypeBeforeDelete:
86+
if m, ok := doc.(BeforeDelete); ok {
87+
return m.BeforeDelete(ctx)
88+
}
89+
case operation.OpTypeAfterDelete:
90+
if m, ok := doc.(AfterDelete); ok {
91+
return m.AfterDelete(ctx)
92+
}
93+
case operation.OpTypeBeforeUpdate:
94+
if m, ok := doc.(BeforeUpdate); ok {
95+
return m.BeforeUpdate(ctx)
96+
}
97+
case operation.OpTypeAfterUpdate:
98+
if m, ok := doc.(AfterUpdate); ok {
99+
return m.AfterUpdate(ctx)
100+
}
84101
case operation.OpTypeBeforeUpsert:
85102
if m, ok := doc.(BeforeUpsert); ok {
86103
return m.BeforeUpsert(ctx)
@@ -89,6 +106,10 @@ func execute(ctx context.Context, doc any, opType operation.OpType, _ ...any) er
89106
if m, ok := doc.(AfterUpsert); ok {
90107
return m.AfterUpsert(ctx)
91108
}
109+
case operation.OpTypeBeforeFind:
110+
if m, ok := doc.(BeforeFind); ok {
111+
return m.BeforeFind(ctx)
112+
}
92113
case operation.OpTypeAfterFind:
93114
if m, ok := doc.(AfterFind); ok {
94115
return m.AfterFind(ctx)

0 commit comments

Comments
 (0)