diff --git a/pyfastapi/repositories/base.py b/pyfastapi/repositories/base.py index 96065f2..b2b302b 100644 --- a/pyfastapi/repositories/base.py +++ b/pyfastapi/repositories/base.py @@ -1,6 +1,5 @@ from abc import ABC -from typing import Annotated, Tuple, List, Type -from toolz.functoolz import curry # type: ignore +from typing import Annotated, Tuple, List, Type, TypeVar from fastapi import Depends from pydantic import BaseModel @@ -11,19 +10,17 @@ from pyfastapi.models.base import Base from pyfastapi.schemas.base import BaseEnum +T = TypeVar("T", bound=Base) + class BaseRepository(ABC): def __init__(self, db: Annotated[Session, Depends(get_db)]): self.db = db -@curry # type: ignore def extract_query( - model: Type[BaseModel], use_like_list: List[str], q: BaseModel, stmt: Select[Tuple[Base]] -) -> Select[Tuple[Base]]: - """ - because of the @curry, return type is being ignored and is using Any - """ + model: Type[T], use_like_list: List[str], q: BaseModel, stmt: Select[Tuple[T]] +) -> Select[Tuple[T]]: stmt_ = stmt for attr, value in q: if value is not None: @@ -34,23 +31,18 @@ def extract_query( return stmt_ -@curry # type: ignore def extract_sort( - model: Type[BaseModel], enum: Type[BaseEnum], sort: str, stmt: Select[Tuple[Type[Base]]] -) -> Select[Tuple[Type[Base]]]: - """ - because of the @curry, return type is being ignored and is using Any - """ - if sort: - stmt_ = stmt - first_char = sort[0] - sort_key = sort[1:] if first_char in ["-", "+"] else sort - - if sort_key in enum: - if sort[0] == "-": - stmt_ = stmt_.order_by(getattr(model, sort_key).desc()) - else: - stmt_ = stmt_.order_by(getattr(model, sort_key).asc()) - return stmt_ - else: + model: Type[T], enum: Type[BaseEnum], sort: str, stmt: Select[Tuple[T]] +) -> Select[Tuple[T]]: + if not sort: + return stmt + + first_char = sort[0] + sort_key = sort[1:] if first_char in ["-", "+"] else sort + + if sort_key not in enum: return stmt + + if sort[0] == "-": + return stmt.order_by(getattr(model, sort_key).desc()) + return stmt.order_by(getattr(model, sort_key).asc()) diff --git a/pyfastapi/repositories/country.py b/pyfastapi/repositories/country.py index 04dade1..75ebfc6 100644 --- a/pyfastapi/repositories/country.py +++ b/pyfastapi/repositories/country.py @@ -1,4 +1,3 @@ -from toolz.functoolz import compose # type: ignore from fastapi_pagination import LimitOffsetPage from fastapi_pagination.ext.sqlalchemy import paginate from sqlalchemy.orm import joinedload @@ -15,10 +14,8 @@ def get_country(self, code: str) -> Country | None: return self.db.execute(stmt).scalar_one_or_none() def get_countries(self, q: QueryCountrySchema, sort: str) -> LimitOffsetPage[Country]: - f = compose( - extract_query(Country, ["name"], q), - extract_sort(Country, SortCountryEnum, sort) - ) - stmt = f(select(Country)) + stmt = select(Country) + stmt = extract_sort(Country, SortCountryEnum, sort, stmt) + stmt = extract_query(Country, ["name"], q, stmt) country_list: LimitOffsetPage[Country] = paginate(self.db, stmt) return country_list diff --git a/pyfastapi/repositories/person.py b/pyfastapi/repositories/person.py index 0c417fd..23e26c1 100644 --- a/pyfastapi/repositories/person.py +++ b/pyfastapi/repositories/person.py @@ -1,4 +1,3 @@ -from toolz .functoolz import compose # type: ignore from fastapi_pagination import LimitOffsetPage from fastapi_pagination.ext.sqlalchemy import paginate from sqlalchemy.dialects.sqlite import insert @@ -16,11 +15,9 @@ def get_person(self, id_: int) -> Person | None: return self.db.execute(stmt).scalar_one_or_none() def get_persons(self, q: QueryPersonSchema, sort: str) -> LimitOffsetPage[Person]: - f = compose( - extract_query(Person, ["first_name", "last_name"], q), - extract_sort(Person, SortPersonEnum, sort) - ) - stmt = f(select(Person)) + stmt = select(Person) + stmt = extract_sort(Person, SortPersonEnum, sort, stmt) + stmt = extract_query(Person, ["first_name", "last_name"], q, stmt) person_list: LimitOffsetPage[Person] = paginate(self.db, stmt) return person_list diff --git a/pyproject.toml b/pyproject.toml index 41db957..9f80f49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,6 @@ dependencies = [ "fastapi-pagination>=0.12.14,<0.13", "sqlalchemy>=2.0.25,<3", "alembic>=1.13.1,<2", - "toolz>=0.12.1,<0.13", ] [dependency-groups] diff --git a/tests/unit_tests/repositories/test_base.py b/tests/unit_tests/repositories/test_base.py index 4f36d1d..60463a0 100644 --- a/tests/unit_tests/repositories/test_base.py +++ b/tests/unit_tests/repositories/test_base.py @@ -23,24 +23,21 @@ def setUpClass(cls) -> None: cls.repo = CountryRepository(Session()) def test_country(self) -> None: - val = extract_sort(Country, SortCountryEnum, "name")(select(Country)) + val = extract_sort(Country, SortCountryEnum, "name", select(Country)) print("val", val) def test_person(self) -> None: - val = extract_sort(Person, SortPersonEnum, "id")(select(Person)) + val = extract_sort(Person, SortPersonEnum, "id", select(Person)) print("person", val) class TestCountryRepository(TestCase): def generate_from_sqlalchemy(self, sort_key_: str) -> str: - stmt_ = extract_sort(Country, SortCountryEnum, sort_key_)(select(Country)) + stmt_ = extract_sort(Country, SortCountryEnum, sort_key_, select(Country)) return str(stmt_) def get_extract_query(self, q: QueryCountrySchema) -> Select[Tuple[Country]]: - """ - ignore because it returns any - """ - return extract_query(Country, ["name"], q)(select(Country)) # type: ignore + return extract_query(Country, ["name"], q, select(Country)) def test_country_extract_sort_if_part_of_enum_asc(self) -> None: def generate_sql(sort_key_: str) -> str: @@ -95,14 +92,11 @@ def test_country_extract_query_not_in_enum(self) -> None: class TestPersonRepository(TestCase): def generate_from_sqlalchemy(self, sort_key_: str) -> str: - stmt_ = extract_sort(Person, SortPersonEnum, sort_key_)(select(Person)) + stmt_ = extract_sort(Person, SortPersonEnum, sort_key_, select(Person)) return str(stmt_) def get_extract_query(self, q: QueryPersonSchema) -> Select[Tuple[Person]]: - """ - ignore because it returns any - """ - return extract_query(Person, ["first_name", "last_name"], q)(select(Person)) # type: ignore + return extract_query(Person, ["first_name", "last_name"], q, select(Person)) # extract sort def test_person_extract_sort_if_part_of_enum_asc(self) -> None: diff --git a/uv.lock b/uv.lock index e8168e1..a0a9c26 100644 --- a/uv.lock +++ b/uv.lock @@ -196,7 +196,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/2f/461615adc53ba81e99471303b15ac6b2a6daa8d2a0f7f77fd15605e16d5b/greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be", size = 273085, upload-time = "2023-12-21T22:03:01.176Z" }, { url = "https://files.pythonhosted.org/packages/e9/55/2c3cfa3cdbb940cf7321fbcf544f0e9c74898eed43bf678abf416812d132/greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e", size = 660514, upload-time = "2023-12-21T22:29:28.62Z" }, { url = "https://files.pythonhosted.org/packages/38/77/efb21ab402651896c74f24a172eb4d7479f9f53898bd5e56b9e20bb24ffd/greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676", size = 674295, upload-time = "2023-12-21T22:26:24.101Z" }, - { url = "https://files.pythonhosted.org/packages/74/3a/92f188ace0190f0066dca3636cf1b09481d0854c46e92ec5e29c7cefe5b1/greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc", size = 669395, upload-time = "2023-12-21T22:31:35.992Z" }, { url = "https://files.pythonhosted.org/packages/63/0f/847ed02cdfce10f0e6e3425cd054296bddb11a17ef1b34681fa01a055187/greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230", size = 670455, upload-time = "2023-12-21T22:03:16.291Z" }, { url = "https://files.pythonhosted.org/packages/bd/37/56b0da468a85e7704f3b2bc045015301bdf4be2184a44868c71f6dca6fe2/greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf", size = 625692, upload-time = "2023-12-21T22:03:06.294Z" }, { url = "https://files.pythonhosted.org/packages/7c/68/b5f4084c0a252d7e9c0d95fc1cfc845d08622037adb74e05be3a49831186/greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305", size = 1152597, upload-time = "2023-12-21T22:31:00.412Z" }, @@ -500,7 +499,6 @@ dependencies = [ { name = "fastapi", extra = ["all"] }, { name = "fastapi-pagination" }, { name = "sqlalchemy" }, - { name = "toolz" }, ] [package.dev-dependencies] @@ -520,7 +518,6 @@ requires-dist = [ { name = "fastapi", extras = ["all"], specifier = ">=0.109.0,<0.110" }, { name = "fastapi-pagination", specifier = ">=0.12.14,<0.13" }, { name = "sqlalchemy", specifier = ">=2.0.25,<3" }, - { name = "toolz", specifier = ">=0.12.1,<0.13" }, ] [package.metadata.requires-dev] @@ -694,15 +691,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/03/13/c60c738da2fb69d60ee1dc5631e8d152352003cc0bc4ce39582bdd90e293/starlette-0.35.1-py3-none-any.whl", hash = "sha256:50bbbda9baa098e361f398fda0928062abbaf1f54f4fadcbe17c092a01eb9a25", size = 71076, upload-time = "2024-01-11T19:58:58.451Z" }, ] -[[package]] -name = "toolz" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3e/bf/5e12db234df984f6df3c7f12f1428aa680ba4e101f63f4b8b3f9e8d2e617/toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d", size = 66550, upload-time = "2024-01-24T03:28:28.047Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/8a/d82202c9f89eab30f9fc05380daae87d617e2ad11571ab23d7c13a29bb54/toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85", size = 56121, upload-time = "2024-01-24T03:28:25.97Z" }, -] - [[package]] name = "typing-extensions" version = "4.9.0"