package wmo import ( "go.mongodb.org/mongo-driver/bson" ct "gogs.mikescher.com/BlackForestBytes/goext/cursortoken" "gogs.mikescher.com/BlackForestBytes/goext/exerr" ) func CreatePagination[TData any](coll *Coll[TData], token ct.CursorToken, fieldPrimary string, sortPrimary ct.SortDirection, fieldSecondary *string, sortSecondary *ct.SortDirection, pageSize *int) ([]bson.D, error) { cond := bson.A{} sort := bson.D{} valuePrimary, err := coll.getTokenValueAsMongoType(token.ValuePrimary, fieldPrimary) if err != nil { return nil, exerr.Wrap(err, "failed to get (primary) token-value as mongo-type").Build() } if sortPrimary == ct.SortASC { // We sort ASC on - so we want all entries newer ($gt) than the $primary cond = append(cond, bson.M{fieldPrimary: bson.M{"$gt": valuePrimary}}) sort = append(sort, bson.E{Key: fieldPrimary, Value: +1}) } else if sortPrimary == ct.SortDESC { // We sort DESC on - so we want all entries older ($lt) than the $primary cond = append(cond, bson.M{fieldPrimary: bson.M{"$lt": valuePrimary}}) sort = append(sort, bson.E{Key: fieldPrimary, Value: -1}) } if fieldSecondary != nil && sortSecondary != nil && *fieldSecondary != fieldPrimary { valueSecondary, err := coll.getTokenValueAsMongoType(token.ValueSecondary, *fieldSecondary) if err != nil { return nil, exerr.Wrap(err, "failed to get (secondary) token-value as mongo-type").Build() } if *sortSecondary == ct.SortASC { // the conflict-resolution condition, for entries with the _same_ as the $primary we take the ones with a greater $secondary (= newer) cond = append(cond, bson.M{"$and": bson.A{ bson.M{fieldPrimary: valuePrimary}, bson.M{*fieldSecondary: bson.M{"$gt": valueSecondary}}, }}) sort = append(sort, bson.E{Key: fieldPrimary, Value: +1}) } else if *sortSecondary == ct.SortDESC { // the conflict-resolution condition, for entries with the _same_ as the $primary we take the ones with a smaller $secondary (= older) cond = append(cond, bson.M{"$and": bson.A{ bson.M{fieldPrimary: valuePrimary}, bson.M{*fieldSecondary: bson.M{"$lt": valueSecondary}}, }}) sort = append(sort, bson.E{Key: fieldPrimary, Value: -1}) } } pipeline := make([]bson.D, 0, 3) if token.Mode == ct.CTMStart { // no gt/lt condition } else if token.Mode == ct.CTMNormal { pipeline = append(pipeline, bson.D{{Key: "$match", Value: bson.M{"$or": cond}}}) } else if token.Mode == ct.CTMEnd { // false pipeline = append(pipeline, bson.D{{Key: "$match", Value: bson.M{"$expr": bson.M{"$eq": bson.A{"1", "0"}}}}}) } else { return nil, exerr.New(exerr.TypeInternal, "unknown ct mode: "+string(token.Mode)).Any("token.Mode", token.Mode).Build() } pipeline = append(pipeline, bson.D{{Key: "$sort", Value: sort}}) if pageSize != nil { pipeline = append(pipeline, bson.D{{Key: "$limit", Value: int64(*pageSize + 1)}}) } return pipeline, nil }