hybrid pagination

This commit is contained in:
Mazyar
2026-05-17 17:21:36 +03:30
parent 42d0a47226
commit 6dac5b482a
39 changed files with 696 additions and 386 deletions
+21 -7
View File
@@ -87,11 +87,16 @@ func (h *NotificationHandler) GetNotifications(c echo.Context) error {
return response.ValidationError(c, err.Error(), "")
}
pagination := response.NewPagination(c)
pagination, err := response.NewPagination(c)
if err != nil {
return response.PaginationBadRequest(c, err)
}
// Call service
notifications, err := h.service.GetNotifications(c.Request().Context(), form, pagination)
if err != nil {
if response.IsListPaginationError(err) {
return response.PaginationBadRequest(c, err)
}
return response.InternalServerError(c, "Failed to get notifications")
}
@@ -141,11 +146,16 @@ func (h *NotificationHandler) AdminNotifications(c echo.Context) error {
form.Recipient = userID
form.Status = "sent"
pagination := response.NewPagination(c)
pagination, err := response.NewPagination(c)
if err != nil {
return response.PaginationBadRequest(c, err)
}
// Call service
notifications, err := h.service.GetNotifications(c.Request().Context(), form, pagination)
if err != nil {
if response.IsListPaginationError(err) {
return response.PaginationBadRequest(c, err)
}
return response.InternalServerError(c, "Failed to get notifications")
}
@@ -254,12 +264,16 @@ func (h *NotificationHandler) CustomerNotifications(c echo.Context) error {
form.Recipient = userID
form.Status = "sent"
pagination := response.NewPagination(c)
pagination, err := response.NewPagination(c)
if err != nil {
return response.PaginationBadRequest(c, err)
}
// Call service
notifications, err := h.service.GetNotifications(c.Request().Context(), form, pagination)
if err != nil {
// Log the actual error for debugging
if response.IsListPaginationError(err) {
return response.PaginationBadRequest(c, err)
}
c.Logger().Error("GetNotifications failed", map[string]interface{}{
"error": err.Error(),
"status": form.Status,
+15 -35
View File
@@ -11,7 +11,6 @@ import (
"go.mongodb.org/mongo-driver/v2/bson"
mongopkg "go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
var (
@@ -45,7 +44,7 @@ type Notification struct {
type Repository interface {
Create(ctx context.Context, notification *Notification) error
GetByID(ctx context.Context, id string) (*Notification, error)
GetByUserID(ctx context.Context, userID string, status string, seen *bool, priority, eventType, notificationType string, pagination *response.Pagination) ([]Notification, int64, error)
GetByUserID(ctx context.Context, userID string, status string, seen *bool, priority, eventType, notificationType string, pagination *response.Pagination) (*orm.PaginatedResult[Notification], error)
Update(ctx context.Context, notification *Notification) error
MarkAsSeen(ctx context.Context, notificationID, userID string) error
MarkAllAsSeen(ctx context.Context, userID string) error
@@ -108,7 +107,7 @@ func (r *notificationRepository) GetByID(ctx context.Context, id string) (*Notif
}
// GetByUserID retrieves notifications for a specific user with filters
func (r *notificationRepository) GetByUserID(ctx context.Context, userID string, status string, seen *bool, priority, eventType, notificationType string, pagination *response.Pagination) ([]Notification, int64, error) {
func (r *notificationRepository) GetByUserID(ctx context.Context, userID string, status string, seen *bool, priority, eventType, notificationType string, pagination *response.Pagination) (*orm.PaginatedResult[Notification], error) {
filter := bson.M{"user_id": userID}
if status != "" {
@@ -131,48 +130,29 @@ func (r *notificationRepository) GetByUserID(ctx context.Context, userID string,
filter["type"] = notificationType
}
// Get total count
total, err := r.collection.CountDocuments(ctx, filter)
mongoPagination, err := orm.BuildListPagination(
pagination.Limit,
pagination.Offset,
pagination.Cursor,
pagination.SortBy,
pagination.SortOrder,
filter,
orm.ListPaginationOptions{},
)
if err != nil {
r.logger.Error("Failed to count notifications", map[string]interface{}{
"error": err.Error(),
"user_id": userID,
})
return nil, 0, err
return nil, err
}
// Build find options
findOptions := options.Find()
if pagination.Limit > 0 {
findOptions.SetLimit(int64(pagination.Limit))
}
if pagination.Offset > 0 {
findOptions.SetSkip(int64(pagination.Offset))
}
// Sort by created_at descending
findOptions.SetSort(bson.D{{Key: "created_at", Value: -1}})
cursor, err := r.collection.Find(ctx, filter, findOptions)
result, err := r.ormRepo.FindAll(ctx, filter, mongoPagination)
if err != nil {
r.logger.Error("Failed to find notifications", map[string]interface{}{
"error": err.Error(),
"user_id": userID,
})
return nil, 0, err
}
defer cursor.Close(ctx)
var notifications []Notification
if err := cursor.All(ctx, &notifications); err != nil {
r.logger.Error("Failed to decode notifications", map[string]interface{}{
"error": err.Error(),
"user_id": userID,
})
return nil, 0, err
return nil, err
}
return notifications, total, nil
return result, nil
}
// Update updates a notification
+3 -15
View File
@@ -194,7 +194,7 @@ func (s *notificationService) GetNotifications(ctx context.Context, req *SearchF
"offset": pagination.Offset,
})
notifications, total, err := s.repository.GetByUserID(ctx, req.Recipient, req.Status, req.Seen, req.Priority, req.EventType, req.Type, pagination)
page, err := s.repository.GetByUserID(ctx, req.Recipient, req.Status, req.Seen, req.Priority, req.EventType, req.Type, pagination)
if err != nil {
s.logger.Error("Failed to get notifications", map[string]interface{}{
"error": err.Error(),
@@ -203,7 +203,7 @@ func (s *notificationService) GetNotifications(ctx context.Context, req *SearchF
}
notificationsResponse := make([]*NotificationResponse, 0)
for _, notification := range notifications {
for _, notification := range page.Items {
usr, _ := s.userService.GetUserByID(ctx, notification.UserID)
cust, _ := s.customerService.GetByID(ctx, notification.UserID)
@@ -250,21 +250,9 @@ func (s *notificationService) GetNotifications(ctx context.Context, req *SearchF
})
}
// Calculate total pages
totalPages := int(total) / pagination.Limit
if int(total)%pagination.Limit > 0 {
totalPages++
}
return &NotificationListResponse{
Notifications: notificationsResponse,
Meta: &response.Meta{
Total: int(total),
Limit: pagination.Limit,
Offset: pagination.Offset,
Page: (pagination.Offset / pagination.Limit) + 1,
Pages: totalPages,
},
Meta: pagination.ListMeta(page.TotalCount, page.NextCursor, page.HasMore, page.PageOffset),
}, nil
}