mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-02-05 15:33:10 -05:00
feat: re-write get all routes to use pagination (#1424)
rewrite get_all routes to use a pagination pattern to allow for better implementations of search, filter, and sorting on the frontend or by any client without fetching all the data. Additionally we added a CI check for running the Nuxt built to confirm that no TS errors were present. Finally, I had to remove the header support for the Shopping lists as the browser caching based off last_updated header was not allowing it to read recent updates due to how we're handling the updated_at property in the database with nested fields. This will have to be looked at in the future to reimplement. I'm unsure how many other routes have a similar issue. Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
import enum
|
||||
from typing import Generic, TypeVar
|
||||
from typing import Any, Generic, TypeVar
|
||||
from urllib.parse import parse_qs, urlencode, urlsplit, urlunsplit
|
||||
|
||||
from humps import camelize
|
||||
from pydantic import BaseModel
|
||||
from pydantic.generics import GenericModel
|
||||
|
||||
from mealie.schema._mealie import MealieModel
|
||||
|
||||
DataT = TypeVar("DataT", bound=BaseModel)
|
||||
|
||||
|
||||
@@ -12,11 +16,11 @@ class OrderDirection(str, enum.Enum):
|
||||
desc = "desc"
|
||||
|
||||
|
||||
class PaginationQuery(BaseModel):
|
||||
class PaginationQuery(MealieModel):
|
||||
page: int = 1
|
||||
per_page: int = 50
|
||||
order_by: str = "created_at"
|
||||
order_direction: OrderDirection = OrderDirection.desc
|
||||
per_page: int = 50
|
||||
|
||||
|
||||
class PaginationBase(GenericModel, Generic[DataT]):
|
||||
@@ -24,4 +28,45 @@ class PaginationBase(GenericModel, Generic[DataT]):
|
||||
per_page: int = 10
|
||||
total: int = 0
|
||||
total_pages: int = 0
|
||||
data: list[DataT]
|
||||
items: list[DataT]
|
||||
next: str | None
|
||||
previous: str | None
|
||||
|
||||
def _set_next(self, route: str, query_params: dict[str, Any]) -> None:
|
||||
if self.page >= self.total_pages:
|
||||
self.next = None
|
||||
return
|
||||
|
||||
# combine params with base route
|
||||
query_params["page"] = self.page + 1
|
||||
self.next = PaginationBase.merge_query_parameters(route, query_params)
|
||||
|
||||
def _set_prev(self, route: str, query_params: dict[str, Any]) -> None:
|
||||
if self.page <= 1:
|
||||
self.previous = None
|
||||
return
|
||||
|
||||
# combine params with base route
|
||||
query_params["page"] = self.page - 1
|
||||
self.previous = PaginationBase.merge_query_parameters(route, query_params)
|
||||
|
||||
def set_pagination_guides(self, route: str, query_params: dict[str, Any] | None) -> None:
|
||||
if not query_params:
|
||||
query_params = {}
|
||||
|
||||
query_params = camelize(query_params)
|
||||
|
||||
# sanitize user input
|
||||
self.page = max(self.page, 1)
|
||||
self._set_next(route, query_params)
|
||||
self._set_prev(route, query_params)
|
||||
|
||||
@staticmethod
|
||||
def merge_query_parameters(url: str, params: dict[str, Any]):
|
||||
scheme, netloc, path, query_string, fragment = urlsplit(url)
|
||||
|
||||
query_params = parse_qs(query_string)
|
||||
query_params.update(params)
|
||||
new_query_string = urlencode(query_params, doseq=True)
|
||||
|
||||
return urlunsplit((scheme, netloc, path, new_query_string, fragment))
|
||||
|
||||
Reference in New Issue
Block a user