cursor pagination

This commit is contained in:
Mazyar
2026-05-16 15:51:18 +03:30
parent bcb345103f
commit 70f581da09
7 changed files with 405 additions and 111 deletions
+19 -3
View File
@@ -157,7 +157,8 @@ func (h *TenderHandler) Delete(c echo.Context) error {
// @Param languages query []string false "Filter by languages (comma-separated)"
// @Param buyer_organization_id query string false "Filter by buyer organization ID"
// @Param limit query int false "Number of items per page (default: 20, max: 100)"
// @Param offset query int false "Number of items to skip (default: 0)"
// @Param offset query int false "Number of items to skip (default: 0). Prefer cursor for deep pages."
// @Param cursor query string false "Opaque cursor from previous page meta.next_cursor"
// @Param sort_by query string false "Sort by field"
// @Param sort_order query string false "Sort order (asc or desc)"
// @Success 200 {object} response.APIResponse{data=map[string]interface{}}
@@ -179,6 +180,9 @@ func (h *TenderHandler) Search(c echo.Context) error {
// Call service
tenders, err := h.service.Search(c.Request().Context(), form, response.NewPagination(c))
if err != nil {
if isInvalidPaginationCursor(err) {
return response.ValidationError(c, "Invalid pagination cursor", err.Error())
}
return response.InternalServerError(c, "Failed to list tenders")
}
@@ -219,7 +223,8 @@ func (h *TenderHandler) Search(c echo.Context) error {
// @Param languages query []string false "Filter by languages (comma-separated)"
// @Param buyer_organization_id query string false "Filter by buyer organization ID"
// @Param limit query int false "Number of items per page (default: 20, max: 100)"
// @Param offset query int false "Number of items to skip (default: 0)"
// @Param offset query int false "Number of items to skip (default: 0). Prefer cursor for deep pages."
// @Param cursor query string false "Opaque cursor from previous page meta.next_cursor"
// @Param sort_by query string false "Sort by field"
// @Param sort_order query string false "Sort order (asc or desc)"
// @Success 200 {object} response.APIResponse{data=SearchResponse}
@@ -256,6 +261,9 @@ func (h *TenderHandler) GetPublicTenders(c echo.Context) error {
result, err := h.service.Search(c.Request().Context(), form, response.NewPagination(c))
if err != nil {
if isInvalidPaginationCursor(err) {
return response.ValidationError(c, "Invalid pagination cursor", err.Error())
}
return response.InternalServerError(c, "Failed to retrieve tenders")
}
@@ -292,7 +300,8 @@ func (h *TenderHandler) GetPublicTenders(c echo.Context) error {
// @Param languages query []string false "Filter by languages (comma-separated)"
// @Param buyer_organization_id query string false "Filter by buyer organization ID"
// @Param limit query int false "Number of items per page (default: 20, max: 100)"
// @Param offset query int false "Number of items to skip (default: 0)"
// @Param offset query int false "Number of items to skip (default: 0). Prefer cursor for deep pages."
// @Param cursor query string false "Opaque cursor from previous page meta.next_cursor"
// @Param sort_by query string false "Sort by field"
// @Param sort_order query string false "Sort order (asc or desc)"
// @Success 200 {object} response.APIResponse{data=SearchResponse}
@@ -328,6 +337,9 @@ func (h *TenderHandler) RecommendTenders(c echo.Context) error {
result, err := h.service.Recommend(c.Request().Context(), form, response.NewPagination(c))
if err != nil {
if isInvalidPaginationCursor(err) {
return response.ValidationError(c, "Invalid pagination cursor", err.Error())
}
return response.InternalServerError(c, "Failed to retrieve tenders")
}
@@ -651,3 +663,7 @@ func (h *TenderHandler) GetAllAISummaries(c echo.Context) error {
return response.Success(c, summaries, "AI summaries retrieved successfully")
}
func isInvalidPaginationCursor(err error) bool {
return errors.Is(err, orm.ErrInvalidCursor)
}