From 5b1312ce64045940745012f719ad953664d4cf5a Mon Sep 17 00:00:00 2001 From: Lukas Plank Date: Thu, 28 Nov 2024 06:01:22 +0100 Subject: [PATCH] feat: use query parameter model for SPARQLModelAdapter.query Using a query parameter model for SPARQLModelAdapter.query has many advantages, e.g. enhanced OpenAPI/Swagger definitions for FastAPI code and runtime validation for query parameters. Also, the query parameter model defines a single extension interface for query parameters. Closes #150. --- rdfproxy/__init__.py | 2 +- rdfproxy/adapter.py | 25 +++++++++++++------------ rdfproxy/utils/models.py | 12 +++++++++++- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/rdfproxy/__init__.py b/rdfproxy/__init__.py index caaad1e..6b95c77 100644 --- a/rdfproxy/__init__.py +++ b/rdfproxy/__init__.py @@ -1,4 +1,4 @@ from rdfproxy.adapter import SPARQLModelAdapter # noqa: F401 from rdfproxy.mapper import ModelBindingsMapper # noqa: F401 from rdfproxy.utils._types import SPARQLBinding # noqa: F401 -from rdfproxy.utils.models import Page # noqa: F401 +from rdfproxy.utils.models import Page, QueryParameters # noqa: F401 diff --git a/rdfproxy/adapter.py b/rdfproxy/adapter.py index 9836b9b..ef93ad3 100644 --- a/rdfproxy/adapter.py +++ b/rdfproxy/adapter.py @@ -7,7 +7,7 @@ from SPARQLWrapper import JSON, SPARQLWrapper from rdfproxy.mapper import ModelBindingsMapper from rdfproxy.utils._types import _TModelInstance -from rdfproxy.utils.models import Page +from rdfproxy.utils.models import Page, QueryParameters from rdfproxy.utils.sparql_utils import ( calculate_offset, construct_count_query, @@ -42,19 +42,14 @@ def __init__( ) self.sparql_wrapper.setReturnFormat(JSON) - def query( - self, - *, - page: int = 1, - size: int = 100, - ) -> Page[_TModelInstance]: + def query(self, query_parameters: QueryParameters) -> Page[_TModelInstance]: """Run a query against an endpoint and return a Page model object.""" count_query: str = construct_count_query(query=self._query, model=self._model) items_query: str = construct_items_query( query=self._query, model=self._model, - limit=size, - offset=calculate_offset(page, size), + limit=query_parameters.size, + offset=calculate_offset(query_parameters.page, query_parameters.size), ) items_query_bindings: Iterator[dict] = query_with_wrapper( @@ -65,9 +60,15 @@ def query( items: list[_TModelInstance] = mapper.get_models() total: int = self._get_count(count_query) - pages: int = math.ceil(total / size) - - return Page(items=items, page=page, size=size, total=total, pages=pages) + pages: int = math.ceil(total / query_parameters.size) + + return Page( + items=items, + page=query_parameters.page, + size=query_parameters.size, + total=total, + pages=pages, + ) def _get_count(self, query: str) -> int: """Run a count query and return the count result. diff --git a/rdfproxy/utils/models.py b/rdfproxy/utils/models.py index d4ec9e4..9eef6a9 100644 --- a/rdfproxy/utils/models.py +++ b/rdfproxy/utils/models.py @@ -2,7 +2,7 @@ from typing import Generic -from pydantic import BaseModel +from pydantic import BaseModel, Field from rdfproxy.utils._types import _TModelInstance @@ -21,3 +21,13 @@ class Page(BaseModel, Generic[_TModelInstance]): size: int total: int pages: int + + +class QueryParameters(BaseModel): + """Query parameter model for SPARQLModelAdapter.query. + + See https://fastapi.tiangolo.com/tutorial/query-param-models/ + """ + + page: int = Field(default=1, gt=0) + size: int = Field(default=100, ge=1)