diff --git a/goextVersion.go b/goextVersion.go index b276897..6cf06cb 100644 --- a/goextVersion.go +++ b/goextVersion.go @@ -1,5 +1,5 @@ package goext -const GoextVersion = "0.0.447" +const GoextVersion = "0.0.448" -const GoextVersionTimestamp = "2024-05-10T21:33:01+0200" +const GoextVersionTimestamp = "2024-05-12T16:45:45+0200" diff --git a/wmo/collection.go b/wmo/collection.go index bbfdc27..b638ac9 100644 --- a/wmo/collection.go +++ b/wmo/collection.go @@ -52,6 +52,7 @@ type Coll[TData any] struct { customDecoder *func(ctx context.Context, dec Decodable) (TData, error) // custom decoding function (useful if TData is an interface) isInterfaceDataType bool // true if TData is an interface (not a struct) unmarshalHooks []func(d TData) TData // called for every object after unmarshalling + marshalHooks []func(d TData) TData // called for every object before marshalling extraModPipeline []func(ctx context.Context) mongo.Pipeline // appended to pipelines after filter/limit/skip/sort, used for $lookup, $set, $unset, $project, etc } @@ -83,18 +84,32 @@ func (c *Coll[TData]) WithDecodeFunc(cdf func(ctx context.Context, dec Decodable return c } +// WithUnmarshalHook +// function that is called for every object after reading from DB func (c *Coll[TData]) WithUnmarshalHook(fn func(d TData) TData) *Coll[TData] { c.unmarshalHooks = append(c.unmarshalHooks, fn) return c } +// WithMarshalHook +// function that is called for every object before writing to DB +func (c *Coll[TData]) WithMarshalHook(fn func(d TData) TData) *Coll[TData] { + c.extraModPipeline = append(c.marshalHooks, fn) + + return c +} + +// WithModifyingPipeline +// pipeline that is appended to all read operations (after filtering) func (c *Coll[TData]) WithModifyingPipeline(p mongo.Pipeline) *Coll[TData] { c.extraModPipeline = append(c.extraModPipeline, func(ctx context.Context) mongo.Pipeline { return p }) return c } +// WithModifyingPipelineFunc +// pipeline that is appended to all read operations (after filtering) func (c *Coll[TData]) WithModifyingPipelineFunc(fn func(ctx context.Context) mongo.Pipeline) *Coll[TData] { c.extraModPipeline = append(c.extraModPipeline, fn) diff --git a/wmo/queryInsert.go b/wmo/queryInsert.go index ef76014..3e8bdc3 100644 --- a/wmo/queryInsert.go +++ b/wmo/queryInsert.go @@ -9,6 +9,10 @@ import ( ) func (c *Coll[TData]) InsertOne(ctx context.Context, valueIn TData) (TData, error) { + for _, hook := range c.marshalHooks { + valueIn = hook(valueIn) + } + insRes, err := c.coll.InsertOne(ctx, valueIn) if err != nil { return *new(TData), exerr.Wrap(err, "mongo-query[insert-one] failed").Str("collection", c.Name()).Build() @@ -36,6 +40,12 @@ func (c *Coll[TData]) InsertOneUnchecked(ctx context.Context, valueIn any) (TDat } func (c *Coll[TData]) InsertMany(ctx context.Context, valueIn []TData) (*mongo.InsertManyResult, error) { + for _, hook := range c.marshalHooks { + for i := 0; i < len(valueIn); i++ { + valueIn[i] = hook(valueIn[i]) + } + } + insRes, err := c.coll.InsertMany(ctx, langext.ArrayToInterface(valueIn)) if err != nil { return nil, exerr.Wrap(err, "mongo-query[insert-many] failed").Int("len(valueIn)", len(valueIn)).Str("collection", c.Name()).Build() diff --git a/wmo/queryUpdate.go b/wmo/queryUpdate.go index 6a6bd8c..8cafea1 100644 --- a/wmo/queryUpdate.go +++ b/wmo/queryUpdate.go @@ -61,6 +61,10 @@ func (c *Coll[TData]) UpdateMany(ctx context.Context, filterQuery bson.M, update } func (c *Coll[TData]) ReplaceOne(ctx context.Context, filterQuery bson.M, value TData) error { + for _, hook := range c.marshalHooks { + value = hook(value) + } + _, err := c.coll.UpdateOne(ctx, filterQuery, bson.M{"$set": value}) if err != nil { return exerr.Wrap(err, "mongo-query[replace-one] failed"). @@ -73,6 +77,10 @@ func (c *Coll[TData]) ReplaceOne(ctx context.Context, filterQuery bson.M, value } func (c *Coll[TData]) FindOneAndReplace(ctx context.Context, filterQuery bson.M, value TData) (TData, error) { + for _, hook := range c.marshalHooks { + value = hook(value) + } + mongoRes := c.coll.FindOneAndReplace(ctx, filterQuery, value, options.FindOneAndReplace().SetReturnDocument(options.After)) if err := mongoRes.Err(); err != nil { return *new(TData), exerr.Wrap(err, "mongo-query[find-one-and-update] failed").