Skip to content

Commit b7e200a

Browse files
Feat: Refactor the field hook, add a custom interface for flexibility, and update MongoDB operations and OpContext to adapt to these changes. (#53)
feat: - hook: - refactor the interface and rename it to . - add a new custom interface to allow developers to highly customize field names and types. Implement this interface as a replacement for . - adjust the implementation of the field hook to support MongoDB's insert, update, and upsert operations, ensuring that the uid=501(chenmingyong) gid=20(staff) groups=20(staff),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),33(_appstore),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),400(com.apple.access_remote_ae),701(com.apple.sharepoint.group.1), , and fields are automatically set correctly. - model: implement the refactored new interface . - operation: add the field to the struct. - bsonx: add the function to convert and types into type. - finder: - add the field to the struct. - when creating an instance of the operation.OpContext struct and the OpContext, pass the []*options.FindOneOptions object. - creator: - add the field to the struct. - when creating an instance of the operation.OpContext struct and the OpContext, pass the []*options.InsertOneResult object and []*options.InsertManyResult object. - deleter: - merge and into and add a new field. - when creating an instance of the operation.OpContext struct and the OpContext, pass the []*options.DeleteOptions object. - updater: - add the field to the struct. - when creating an instance of the operation.OpContext struct and the OpContext, pass the []*options.UpdateOptions object. - enhance the and methods to adapt to the refactored field hook. - refactor the method to internally call the method instead of , and ensure it adapts to the refactored field hook.
1 parent b8e668f commit b7e200a

28 files changed

+1091
-398
lines changed

bsonx/bsonx.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,47 @@ func D(key string, value any) bson.D {
4141
func Id(value any) bson.M {
4242
return M("_id", value)
4343
}
44+
45+
func ToBsonM(data any) bson.M {
46+
if data == nil {
47+
return nil
48+
}
49+
if d, ok := data.(bson.M); ok {
50+
return d
51+
}
52+
53+
if d, ok := data.(bson.D); ok {
54+
return dToM(d)
55+
}
56+
57+
if d, ok := data.(map[string]any); ok {
58+
return MapToBsonM(d)
59+
}
60+
61+
if d, ok := data.(*map[string]any); ok && d != nil {
62+
return MapToBsonM(*d)
63+
}
64+
65+
return nil
66+
}
67+
68+
func MapToBsonM(data map[string]any) bson.M {
69+
m := bson.M{}
70+
for k, v := range data {
71+
m[k] = v
72+
}
73+
return m
74+
}
75+
76+
func dToM(d bson.D) bson.M {
77+
marshal, err := bson.Marshal(d)
78+
if err != nil {
79+
return nil
80+
}
81+
var m bson.M
82+
err = bson.Unmarshal(marshal, &m)
83+
if err != nil {
84+
return nil
85+
}
86+
return m
87+
}

callback_test.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,12 @@ func TestRegisterPlugin_Update(t *testing.T) {
163163
isCalled = true
164164
return nil
165165
}, operation.OpTypeBeforeUpdate)
166-
err := callback.Callbacks.Execute(context.Background(), operation.NewOpContext(nil, operation.WithFilter(bson.M{"name": "Mingyong Chen"}), operation.WithUpdate(bson.M{"$set": bson.M{"name": "Burt"}})), operation.OpTypeBeforeUpdate)
166+
err := callback.Callbacks.Execute(context.Background(), operation.NewOpContext(nil, operation.WithFilter(bson.M{"name": "Mingyong Chen"}), operation.WithUpdates(bson.M{"$set": bson.M{"name": "Burt"}})), operation.OpTypeBeforeUpdate)
167167
require.Nil(t, err)
168168
assert.True(t, isCalled)
169169
isCalled = false
170170
RemovePlugin("before update", operation.OpTypeBeforeUpdate)
171-
err = callback.Callbacks.Execute(context.Background(), operation.NewOpContext(nil, operation.WithFilter(bson.M{"name": "Mingyong Chen"}), operation.WithUpdate(bson.M{"$set": bson.M{"name": "Burt"}})), operation.OpTypeBeforeUpdate)
171+
err = callback.Callbacks.Execute(context.Background(), operation.NewOpContext(nil, operation.WithFilter(bson.M{"name": "Mingyong Chen"}), operation.WithUpdates(bson.M{"$set": bson.M{"name": "Burt"}})), operation.OpTypeBeforeUpdate)
172172
require.Nil(t, err)
173173
assert.False(t, isCalled)
174174
})
@@ -181,12 +181,12 @@ func TestRegisterPlugin_Update(t *testing.T) {
181181
isCalled = true
182182
return nil
183183
}, operation.OpTypeAfterUpdate)
184-
err := callback.Callbacks.Execute(context.Background(), operation.NewOpContext(nil, operation.WithFilter(bson.M{"name": "Mingyong Chen"}), operation.WithUpdate(bson.M{"$set": bson.M{"name": "Burt"}})), operation.OpTypeAfterUpdate)
184+
err := callback.Callbacks.Execute(context.Background(), operation.NewOpContext(nil, operation.WithFilter(bson.M{"name": "Mingyong Chen"}), operation.WithUpdates(bson.M{"$set": bson.M{"name": "Burt"}})), operation.OpTypeAfterUpdate)
185185
require.Nil(t, err)
186186
assert.True(t, isCalled)
187187
isCalled = false
188188
RemovePlugin("after update", operation.OpTypeAfterUpdate)
189-
err = callback.Callbacks.Execute(context.Background(), operation.NewOpContext(nil, operation.WithFilter(bson.M{"name": "Mingyong Chen"}), operation.WithUpdate(bson.M{"$set": bson.M{"name": "Burt"}})), operation.OpTypeAfterUpdate)
189+
err = callback.Callbacks.Execute(context.Background(), operation.NewOpContext(nil, operation.WithFilter(bson.M{"name": "Mingyong Chen"}), operation.WithUpdates(bson.M{"$set": bson.M{"name": "Burt"}})), operation.OpTypeAfterUpdate)
190190
require.Nil(t, err)
191191
assert.False(t, isCalled)
192192
})
@@ -260,10 +260,13 @@ func TestPluginInit_EnableEnableDefaultFieldHook(t *testing.T) {
260260
RemovePlugin("mongox:default_field", operation.OpTypeBeforeUpsert)
261261
})
262262
t.Run("beforeUpsert", func(t *testing.T) {
263-
model := &Model{}
263+
var (
264+
model = &Model{}
265+
m = bson.M{}
266+
)
264267
err := callback.GetCallback().Execute(
265268
context.Background(),
266-
operation.NewOpContext(nil, operation.WithDoc(model)),
269+
operation.NewOpContext(nil, operation.WithDoc(model), operation.WithUpdates(m)),
267270
operation.OpTypeBeforeUpsert,
268271
)
269272
require.Nil(t, err)
@@ -278,13 +281,23 @@ func TestPluginInit_EnableEnableDefaultFieldHook(t *testing.T) {
278281

279282
err = callback.GetCallback().Execute(
280283
context.Background(),
281-
operation.NewOpContext(nil, operation.WithReplacement(model)),
284+
operation.NewOpContext(nil, operation.WithDoc(model), operation.WithUpdates(m)),
282285
operation.OpTypeBeforeUpsert,
283286
)
284287
require.Nil(t, err)
285288
require.NotZero(t, model.ID)
286289
require.NotZero(t, model.CreatedAt)
287290
require.NotZero(t, model.UpdatedAt)
291+
require.Equal(t, bson.M{
292+
"$set": bson.M{
293+
"updated_at": model.UpdatedAt,
294+
},
295+
"$setOnInsert": bson.M{
296+
"_id": model.ID,
297+
"created_at": model.CreatedAt,
298+
},
299+
}, m)
300+
288301
RemovePlugin("mongox:default_field", operation.OpTypeBeforeInsert)
289302
RemovePlugin("mongox:default_field", operation.OpTypeBeforeUpsert)
290303
})

creator/creator.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ func (c *Creator[T]) postActionHandler(ctx context.Context, globalOpContext *ope
8686
}
8787

8888
func (c *Creator[T]) InsertOne(ctx context.Context, doc *T, opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error) {
89-
opContext := operation.NewOpContext(c.collection, operation.WithDoc(doc))
90-
err := c.preActionHandler(ctx, opContext, NewOpContext(c.collection, WithDoc(doc)), operation.OpTypeBeforeInsert)
89+
opContext := operation.NewOpContext(c.collection, operation.WithDoc(doc), operation.WithMongoOptions(opts))
90+
err := c.preActionHandler(ctx, opContext, NewOpContext(c.collection, WithDoc(doc), WithMongoOptions[T](opts)), operation.OpTypeBeforeInsert)
9191
if err != nil {
9292
return nil, err
9393
}
@@ -97,7 +97,7 @@ func (c *Creator[T]) InsertOne(ctx context.Context, doc *T, opts ...*options.Ins
9797
return nil, err
9898
}
9999

100-
err = c.postActionHandler(ctx, opContext, NewOpContext(c.collection, WithDoc(doc)), operation.OpTypeAfterInsert)
100+
err = c.postActionHandler(ctx, opContext, NewOpContext(c.collection, WithDoc(doc), WithMongoOptions[T](opts)), operation.OpTypeAfterInsert)
101101
if err != nil {
102102
return nil, err
103103
}
@@ -106,8 +106,8 @@ func (c *Creator[T]) InsertOne(ctx context.Context, doc *T, opts ...*options.Ins
106106
}
107107

108108
func (c *Creator[T]) InsertMany(ctx context.Context, docs []*T, opts ...*options.InsertManyOptions) (*mongo.InsertManyResult, error) {
109-
opContext := operation.NewOpContext(c.collection, operation.WithDoc(docs))
110-
err := c.preActionHandler(ctx, opContext, NewOpContext(c.collection, WithDocs(docs)), operation.OpTypeBeforeInsert)
109+
opContext := operation.NewOpContext(c.collection, operation.WithDoc(docs), operation.WithMongoOptions(opts))
110+
err := c.preActionHandler(ctx, opContext, NewOpContext(c.collection, WithDocs(docs), WithMongoOptions[T](opts)), operation.OpTypeBeforeInsert)
111111
if err != nil {
112112
return nil, err
113113
}
@@ -117,7 +117,7 @@ func (c *Creator[T]) InsertMany(ctx context.Context, docs []*T, opts ...*options
117117
return nil, err
118118
}
119119

120-
err = c.postActionHandler(ctx, opContext, NewOpContext(c.collection, WithDocs(docs)), operation.OpTypeAfterInsert)
120+
err = c.postActionHandler(ctx, opContext, NewOpContext(c.collection, WithDocs(docs), WithMongoOptions[T](opts)), operation.OpTypeAfterInsert)
121121
if err != nil {
122122
return nil, err
123123
}

creator/opt_op_context_gen.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
// Generated by optioner -type OpContext; DO NOT EDIT
1+
// Generated by [optioner] command-line tool; DO NOT EDIT
22
// If you have any questions, please create issues and submit contributions at:
33
// https://github.com/chenmingyong0423/go-optioner
44

55
package creator
66

7-
import (
8-
"go.mongodb.org/mongo-driver/mongo"
9-
)
7+
import "go.mongodb.org/mongo-driver/mongo"
108

119
type OpContextOption[T any] func(*OpContext[T])
1210

@@ -33,3 +31,9 @@ func WithDocs[T any](docs []*T) OpContextOption[T] {
3331
opContext.Docs = docs
3432
}
3533
}
34+
35+
func WithMongoOptions[T any](mongoOptions any) OpContextOption[T] {
36+
return func(opContext *OpContext[T]) {
37+
opContext.MongoOptions = mongoOptions
38+
}
39+
}

creator/types.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ import (
2222

2323
//go:generate optioner -type OpContext
2424
type OpContext[T any] struct {
25-
Col *mongo.Collection `opt:"-"`
26-
Doc *T
27-
Docs []*T
25+
Col *mongo.Collection `opt:"-"`
26+
Doc *T
27+
Docs []*T
28+
MongoOptions any
2829
}
2930

3031
type (

deleter/deleter.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (d *Deleter[T]) RegisterAfterHooks(hooks ...afterHookFn) *Deleter[T] {
5151
return d
5252
}
5353

54-
func (d *Deleter[T]) preActionHandler(ctx context.Context, globalOpContext *operation.OpContext, opContext *BeforeOpContext, opType operation.OpType) error {
54+
func (d *Deleter[T]) preActionHandler(ctx context.Context, globalOpContext *operation.OpContext, opContext *OpContext, opType operation.OpType) error {
5555
err := callback.GetCallback().Execute(ctx, globalOpContext, opType)
5656
if err != nil {
5757
return err
@@ -65,7 +65,7 @@ func (d *Deleter[T]) preActionHandler(ctx context.Context, globalOpContext *oper
6565
return nil
6666
}
6767

68-
func (d *Deleter[T]) postActionHandler(ctx context.Context, globalOpContext *operation.OpContext, opContext *AfterOpContext, opType operation.OpType) error {
68+
func (d *Deleter[T]) postActionHandler(ctx context.Context, globalOpContext *operation.OpContext, opContext *OpContext, opType operation.OpType) error {
6969
err := callback.GetCallback().Execute(ctx, globalOpContext, opType)
7070
if err != nil {
7171
return err
@@ -86,8 +86,8 @@ func (d *Deleter[T]) Filter(filter any) *Deleter[T] {
8686
}
8787

8888
func (d *Deleter[T]) DeleteOne(ctx context.Context, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) {
89-
globalPoContext := operation.NewOpContext(d.collection, operation.WithFilter(d.filter))
90-
err := d.preActionHandler(ctx, globalPoContext, NewBeforeOpContext(d.collection, d.filter), operation.OpTypeBeforeDelete)
89+
globalPoContext := operation.NewOpContext(d.collection, operation.WithFilter(d.filter), operation.WithMongoOptions(opts))
90+
err := d.preActionHandler(ctx, globalPoContext, NewOpContext(d.collection, d.filter, WithMongoOptions(opts)), operation.OpTypeBeforeDelete)
9191
if err != nil {
9292
return nil, err
9393
}
@@ -97,7 +97,7 @@ func (d *Deleter[T]) DeleteOne(ctx context.Context, opts ...*options.DeleteOptio
9797
return nil, err
9898
}
9999

100-
err = d.postActionHandler(ctx, globalPoContext, NewAfterOpContext(d.collection, d.filter), operation.OpTypeAfterDelete)
100+
err = d.postActionHandler(ctx, globalPoContext, NewOpContext(d.collection, d.filter, WithMongoOptions(opts)), operation.OpTypeAfterDelete)
101101
if err != nil {
102102
return nil, err
103103
}
@@ -106,8 +106,8 @@ func (d *Deleter[T]) DeleteOne(ctx context.Context, opts ...*options.DeleteOptio
106106
}
107107

108108
func (d *Deleter[T]) DeleteMany(ctx context.Context, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) {
109-
globalPoContext := operation.NewOpContext(d.collection, operation.WithFilter(d.filter))
110-
err := d.preActionHandler(ctx, globalPoContext, NewBeforeOpContext(d.collection, d.filter), operation.OpTypeBeforeDelete)
109+
globalPoContext := operation.NewOpContext(d.collection, operation.WithFilter(d.filter), operation.WithMongoOptions(opts))
110+
err := d.preActionHandler(ctx, globalPoContext, NewOpContext(d.collection, d.filter, WithMongoOptions(opts)), operation.OpTypeBeforeDelete)
111111
if err != nil {
112112
return nil, err
113113
}
@@ -117,7 +117,7 @@ func (d *Deleter[T]) DeleteMany(ctx context.Context, opts ...*options.DeleteOpti
117117
return nil, err
118118
}
119119

120-
err = d.postActionHandler(ctx, globalPoContext, NewAfterOpContext(d.collection, d.filter), operation.OpTypeAfterDelete)
120+
err = d.postActionHandler(ctx, globalPoContext, NewOpContext(d.collection, d.filter, WithMongoOptions(opts)), operation.OpTypeAfterDelete)
121121
if err != nil {
122122
return nil, err
123123
}

deleter/deleter_e2e_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ func TestDeleter_e2e_DeleteOne(t *testing.T) {
230230
ctx: context.Background(),
231231
opts: []*options.DeleteOptions{options.Delete().SetComment("test")},
232232
beforeHook: []beforeHookFn{
233-
func(ctx context.Context, opCtx *BeforeOpContext, opts ...any) error {
233+
func(ctx context.Context, opCtx *OpContext, opts ...any) error {
234234
return fmt.Errorf("before hook error")
235235
},
236236
},
@@ -247,7 +247,7 @@ func TestDeleter_e2e_DeleteOne(t *testing.T) {
247247
ctx: context.Background(),
248248
opts: []*options.DeleteOptions{options.Delete().SetComment("test")},
249249
afterHook: []afterHookFn{
250-
func(ctx context.Context, opCtx *AfterOpContext, opts ...any) error {
250+
func(ctx context.Context, opCtx *OpContext, opts ...any) error {
251251
return fmt.Errorf("after hook error")
252252
},
253253
},
@@ -272,15 +272,15 @@ func TestDeleter_e2e_DeleteOne(t *testing.T) {
272272
ctx: context.Background(),
273273
opts: []*options.DeleteOptions{options.Delete().SetComment("test")},
274274
beforeHook: []beforeHookFn{
275-
func(ctx context.Context, opCtx *BeforeOpContext, opts ...any) error {
275+
func(ctx context.Context, opCtx *OpContext, opts ...any) error {
276276
if opCtx.Filter == nil {
277277
return fmt.Errorf("filter is nil")
278278
}
279279
return nil
280280
},
281281
},
282282
afterHook: []afterHookFn{
283-
func(ctx context.Context, opCtx *AfterOpContext, opts ...any) error {
283+
func(ctx context.Context, opCtx *OpContext, opts ...any) error {
284284
if opCtx.Filter == nil {
285285
return fmt.Errorf("filter is nil")
286286
}
@@ -499,7 +499,7 @@ func TestDeleter_e2e_DeleteMany(t *testing.T) {
499499
ctx: context.Background(),
500500
opts: []*options.DeleteOptions{options.Delete().SetComment("test")},
501501
beforeHook: []beforeHookFn{
502-
func(ctx context.Context, opCtx *BeforeOpContext, opts ...any) error {
502+
func(ctx context.Context, opCtx *OpContext, opts ...any) error {
503503
return fmt.Errorf("before hook error")
504504
},
505505
},
@@ -524,7 +524,7 @@ func TestDeleter_e2e_DeleteMany(t *testing.T) {
524524
require.Equal(t, int64(0), deleteResult.DeletedCount)
525525
},
526526
afterHook: []afterHookFn{
527-
func(ctx context.Context, opCtx *AfterOpContext, opts ...any) error {
527+
func(ctx context.Context, opCtx *OpContext, opts ...any) error {
528528
return fmt.Errorf("after hook error")
529529
},
530530
},
@@ -552,15 +552,15 @@ func TestDeleter_e2e_DeleteMany(t *testing.T) {
552552
require.Equal(t, int64(0), deleteResult.DeletedCount)
553553
},
554554
beforeHook: []beforeHookFn{
555-
func(ctx context.Context, opCtx *BeforeOpContext, opts ...any) error {
555+
func(ctx context.Context, opCtx *OpContext, opts ...any) error {
556556
if opCtx.Filter == nil {
557557
return fmt.Errorf("filter is nil")
558558
}
559559
return nil
560560
},
561561
},
562562
afterHook: []afterHookFn{
563-
func(ctx context.Context, opCtx *AfterOpContext, opts ...any) error {
563+
func(ctx context.Context, opCtx *OpContext, opts ...any) error {
564564
if opCtx.Filter == nil {
565565
return fmt.Errorf("filter is nil")
566566
}

deleter/opt_after_op_context_gen.go

Lines changed: 0 additions & 24 deletions
This file was deleted.

deleter/opt_before_op_context_gen.go

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)