goext/wmo/queryPaginate.go

88 lines
2.8 KiB
Go
Raw Normal View History

package wmo
import (
"context"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
pag "gogs.mikescher.com/BlackForestBytes/goext/pagination"
)
2024-01-13 21:36:47 +01:00
func (c *Coll[TData]) Paginate(ctx context.Context, filter pag.MongoFilter, page int, limit *int) ([]TData, pag.Pagination, error) {
type totalCountResult struct {
Count int `bson:"count"`
}
if page < 0 {
page = 1
}
pipelineSort := mongo.Pipeline{}
pipelineFilter := mongo.Pipeline{}
2023-11-09 10:02:31 +01:00
sort := bson.D{}
if filter != nil {
pipelineFilter = filter.FilterQuery(ctx)
sort = filter.Sort(ctx)
}
2023-11-09 10:02:31 +01:00
if len(sort) != 0 {
pipelineSort = append(pipelineSort, bson.D{{Key: "$sort", Value: sort}})
}
pipelinePaginate := mongo.Pipeline{}
if limit != nil {
2023-11-08 18:53:02 +01:00
pipelinePaginate = append(pipelinePaginate, bson.D{{Key: "$skip", Value: *limit * (page - 1)}})
pipelinePaginate = append(pipelinePaginate, bson.D{{Key: "$limit", Value: *limit}})
2023-11-08 18:53:02 +01:00
} else {
page = 1
}
pipelineCount := mongo.Pipeline{}
2023-11-09 11:48:45 +01:00
pipelineCount = append(pipelineCount, bson.D{{Key: "$count", Value: "count"}})
2024-01-09 08:51:46 +01:00
extrModPipelineResolved := mongo.Pipeline{}
for _, ppl := range c.extraModPipeline {
extrModPipelineResolved = langext.ArrConcat(extrModPipelineResolved, ppl(ctx))
}
pipelineList := langext.ArrConcat(pipelineFilter, pipelineSort, pipelinePaginate, extrModPipelineResolved, pipelineSort)
2023-11-13 15:19:48 +01:00
pipelineTotalCount := langext.ArrConcat(pipelineFilter, pipelineCount)
cursorList, err := c.coll.Aggregate(ctx, pipelineList)
if err != nil {
return nil, pag.Pagination{}, exerr.Wrap(err, "mongo-aggregation failed").Any("pipeline", pipelineList).Str("collection", c.Name()).Build()
}
entities, err := c.decodeAll(ctx, cursorList)
if err != nil {
return nil, pag.Pagination{}, exerr.Wrap(err, "failed to all-decode entities").Build()
}
cursorTotalCount, err := c.coll.Aggregate(ctx, pipelineTotalCount)
if err != nil {
return nil, pag.Pagination{}, exerr.Wrap(err, "mongo-aggregation failed").Any("pipeline", pipelineTotalCount).Str("collection", c.Name()).Build()
}
var tcRes totalCountResult
if cursorTotalCount.Next(ctx) {
err = cursorTotalCount.Decode(&tcRes)
if err != nil {
return nil, pag.Pagination{}, exerr.Wrap(err, "failed to decode mongo-aggregation $count result").Any("pipeline", pipelineTotalCount).Str("collection", c.Name()).Build()
}
} else {
tcRes.Count = 0 // no entries in DB
}
paginationObj := pag.Pagination{
Page: page,
Limit: langext.Coalesce(limit, tcRes.Count),
TotalPages: pag.CalcPaginationTotalPages(tcRes.Count, langext.Coalesce(limit, tcRes.Count)),
TotalItems: tcRes.Count,
CurrentPageCount: len(entities),
}
return entities, paginationObj, nil
}