package wmo import ( "context" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ct "gogs.mikescher.com/BlackForestBytes/goext/cursortoken" "gogs.mikescher.com/BlackForestBytes/goext/exerr" "gogs.mikescher.com/BlackForestBytes/goext/langext" pag "gogs.mikescher.com/BlackForestBytes/goext/pagination" ) func (c *Coll[TData]) Paginate(ctx context.Context, filter pag.Filter, 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{} pf1 := "_id" pd1 := ct.SortASC if filter != nil { pipelineFilter = filter.FilterQuery() pf1, pd1 = filter.Pagination() } if pd1 == ct.SortASC { pipelineSort = append(pipelineSort, bson.D{{Key: "$sort", Value: bson.D{{Key: pf1, Value: +1}}}}) } else if pd1 == ct.SortDESC { pipelineSort = append(pipelineSort, bson.D{{Key: "$sort", Value: bson.D{{Key: pf1, Value: -1}}}}) } pipelinePaginate := mongo.Pipeline{} if limit != nil { pipelinePaginate = append(pipelinePaginate, bson.D{{Key: "$skip", Value: *limit * (page - 1)}}) pipelinePaginate = append(pipelinePaginate, bson.D{{Key: "$limit", Value: *limit}}) } else { page = 1 } pipelineCount := mongo.Pipeline{} pipelinePaginate = append(pipelinePaginate, bson.D{{Key: "$count", Value: "count"}}) pipelineList := langext.ArrConcat(mongo.Pipeline{}, pipelineFilter, pipelinePaginate, c.extraModPipeline) pipelineTotalCount := langext.ArrConcat(mongo.Pipeline{}, 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 }