2023-06-06 21:33:49 +02:00
|
|
|
package wmo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
|
|
"go.mongodb.org/mongo-driver/mongo"
|
2023-11-09 10:17:29 +01:00
|
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
2023-08-21 15:08:35 +02:00
|
|
|
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
|
2023-11-09 09:26:46 +01:00
|
|
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
2023-06-06 21:33:49 +02:00
|
|
|
)
|
|
|
|
|
2023-11-09 10:17:29 +01:00
|
|
|
func (c *Coll[TData]) Find(ctx context.Context, filter bson.M, opts ...*options.FindOptions) ([]TData, error) {
|
2023-06-06 21:33:49 +02:00
|
|
|
|
2023-11-09 09:26:46 +01:00
|
|
|
pipeline := mongo.Pipeline{}
|
|
|
|
pipeline = append(pipeline, bson.D{{Key: "$match", Value: filter}})
|
2023-06-06 21:33:49 +02:00
|
|
|
|
2023-11-09 10:17:29 +01:00
|
|
|
for _, opt := range opts {
|
|
|
|
if opt != nil && opt.Sort != nil {
|
|
|
|
pipeline = append(pipeline, bson.D{{Key: "$sort", Value: opt.Sort}})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, opt := range opts {
|
|
|
|
if opt != nil && opt.Skip != nil {
|
|
|
|
pipeline = append(pipeline, bson.D{{Key: "$skip", Value: *opt.Skip}})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, opt := range opts {
|
|
|
|
if opt != nil && opt.Limit != nil {
|
|
|
|
pipeline = append(pipeline, bson.D{{Key: "$limit", Value: *opt.Limit}})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-09 08:51:46 +01:00
|
|
|
for _, ppl := range c.extraModPipeline {
|
|
|
|
pipeline = langext.ArrConcat(pipeline, ppl(ctx))
|
|
|
|
}
|
2023-06-06 21:33:49 +02:00
|
|
|
|
2024-04-23 16:12:17 +02:00
|
|
|
if c.needsDoubleSort(ctx) {
|
|
|
|
for _, opt := range opts {
|
|
|
|
if opt != nil && opt.Sort != nil {
|
|
|
|
pipeline = append(pipeline, bson.D{{Key: "$sort", Value: opt.Sort}})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-09 10:17:29 +01:00
|
|
|
for _, opt := range opts {
|
|
|
|
if opt != nil && opt.Projection != nil {
|
|
|
|
pipeline = append(pipeline, bson.D{{Key: "$project", Value: opt.Projection}})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
convOpts := make([]*options.AggregateOptions, 0, len(opts))
|
|
|
|
for _, v := range opts {
|
|
|
|
vConv, err := convertFindOpt(v)
|
|
|
|
if err != nil {
|
|
|
|
return nil, exerr.Wrap(err, "mongo-aggregation failed").Any("pipeline", pipeline).Str("collection", c.Name()).Build()
|
|
|
|
}
|
|
|
|
convOpts = append(convOpts, vConv)
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor, err := c.coll.Aggregate(ctx, pipeline, convOpts...)
|
2023-06-06 21:33:49 +02:00
|
|
|
if err != nil {
|
2023-11-09 09:26:46 +01:00
|
|
|
return nil, exerr.Wrap(err, "mongo-aggregation failed").Any("pipeline", pipeline).Str("collection", c.Name()).Build()
|
2023-06-06 21:33:49 +02:00
|
|
|
}
|
|
|
|
|
2023-06-10 16:22:14 +02:00
|
|
|
res, err := c.decodeAll(ctx, cursor)
|
2023-06-06 21:33:49 +02:00
|
|
|
if err != nil {
|
2023-08-21 15:08:35 +02:00
|
|
|
return nil, exerr.Wrap(err, "failed to decode values").Build()
|
2023-06-06 21:33:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return res, nil
|
|
|
|
}
|
2023-11-09 10:17:29 +01:00
|
|
|
|
|
|
|
// converts FindOptions to AggregateOptions
|
|
|
|
func convertFindOpt(v *options.FindOptions) (*options.AggregateOptions, error) {
|
|
|
|
if v == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
r := options.Aggregate()
|
|
|
|
|
|
|
|
if v.AllowDiskUse != nil {
|
|
|
|
r.SetAllowDiskUse(*v.AllowDiskUse)
|
|
|
|
}
|
|
|
|
if v.AllowPartialResults != nil {
|
|
|
|
return nil, exerr.New(exerr.TypeMongoInvalidOpt, "Invalid option 'AllowPartialResults' (cannot convert to AggregateOptions)").Build()
|
|
|
|
}
|
|
|
|
if v.BatchSize != nil {
|
|
|
|
r.SetBatchSize(*v.BatchSize)
|
|
|
|
}
|
|
|
|
if v.Collation != nil {
|
|
|
|
r.SetCollation(v.Collation)
|
|
|
|
}
|
|
|
|
if v.Comment != nil {
|
|
|
|
r.SetComment(*v.Comment)
|
|
|
|
}
|
|
|
|
if v.CursorType != nil {
|
|
|
|
return nil, exerr.New(exerr.TypeMongoInvalidOpt, "Invalid option 'CursorType' (cannot convert to AggregateOptions)").Build()
|
|
|
|
}
|
|
|
|
if v.Hint != nil {
|
|
|
|
r.SetHint(v.Hint)
|
|
|
|
}
|
|
|
|
if v.Max != nil {
|
|
|
|
return nil, exerr.New(exerr.TypeMongoInvalidOpt, "Invalid option 'Max' (cannot convert to AggregateOptions)").Build()
|
|
|
|
}
|
|
|
|
if v.MaxAwaitTime != nil {
|
|
|
|
r.SetMaxAwaitTime(*v.MaxAwaitTime)
|
|
|
|
}
|
|
|
|
if v.MaxTime != nil {
|
|
|
|
r.SetMaxTime(*v.MaxTime)
|
|
|
|
}
|
|
|
|
if v.Min != nil {
|
|
|
|
return nil, exerr.New(exerr.TypeMongoInvalidOpt, "Invalid option 'Min' (cannot convert to AggregateOptions)").Build()
|
|
|
|
}
|
|
|
|
if v.NoCursorTimeout != nil {
|
|
|
|
return nil, exerr.New(exerr.TypeMongoInvalidOpt, "Invalid option 'NoCursorTimeout' (cannot convert to AggregateOptions)").Build()
|
|
|
|
}
|
|
|
|
if v.OplogReplay != nil {
|
|
|
|
return nil, exerr.New(exerr.TypeMongoInvalidOpt, "Invalid option 'OplogReplay' (cannot convert to AggregateOptions)").Build()
|
|
|
|
}
|
|
|
|
if v.ReturnKey != nil {
|
|
|
|
return nil, exerr.New(exerr.TypeMongoInvalidOpt, "Invalid option 'ReturnKey' (cannot convert to AggregateOptions)").Build()
|
|
|
|
}
|
|
|
|
if v.ShowRecordID != nil {
|
|
|
|
return nil, exerr.New(exerr.TypeMongoInvalidOpt, "Invalid option 'ShowRecordID' (cannot convert to AggregateOptions)").Build()
|
|
|
|
}
|
|
|
|
if v.Snapshot != nil {
|
|
|
|
return nil, exerr.New(exerr.TypeMongoInvalidOpt, "Invalid option 'Snapshot' (cannot convert to AggregateOptions)").Build()
|
|
|
|
}
|
|
|
|
if v.Let != nil {
|
|
|
|
r.SetLet(v.Let)
|
|
|
|
}
|
|
|
|
|
|
|
|
return r, nil
|
|
|
|
}
|