Skip to content

Commit ba670c1

Browse files
committed
Move seasons business logic to the services
1 parent 02c7755 commit ba670c1

File tree

6 files changed

+106
-18
lines changed

6 files changed

+106
-18
lines changed
Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
from typing import Annotated
22

3-
from fastapi import APIRouter, Depends, HTTPException, Path, status
3+
from fastapi import APIRouter, Path, status
44
from fastapi_pagination import Page
5-
from sqlalchemy.ext.asyncio.session import AsyncSession
65

76
from futuramaapi.repositories import INT32
8-
from futuramaapi.repositories.session import get_async_session
9-
from futuramaapi.routers.exceptions import ModelNotFoundError, NotFoundResponse
10-
11-
from .schemas import Season
7+
from futuramaapi.routers.exceptions import NotFoundResponse
8+
from futuramaapi.routers.services.seasons.get_season import (
9+
GetSeasonResponse,
10+
GetSeasonService,
11+
)
12+
from futuramaapi.routers.services.seasons.list_seasons import (
13+
ListSeasonResponse,
14+
ListSeasonsService,
15+
)
1216

1317
router = APIRouter(
1418
prefix="/seasons",
@@ -24,7 +28,7 @@
2428
"model": NotFoundResponse,
2529
},
2630
},
27-
response_model=Season,
31+
response_model=GetSeasonResponse,
2832
name="season",
2933
)
3034
async def get_season(
@@ -34,30 +38,25 @@ async def get_season(
3438
le=INT32,
3539
),
3640
],
37-
session: AsyncSession = Depends(get_async_session), # noqa: B008
38-
) -> Season:
41+
) -> GetSeasonResponse:
3942
"""Retrieve specific season.
4043
4144
Utilize this endpoint to retrieve detailed information about a specific Futurama season by providing its unique ID.
4245
The response includes details such as the list of seasons, season ID, and more.
4346
4447
Can be used to gain in-depth insights into a particular season of Futurama.
4548
"""
46-
try:
47-
return await Season.get(session, season_id)
48-
except ModelNotFoundError:
49-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) from None
49+
service: GetSeasonService = GetSeasonService(pk=season_id)
50+
return await service()
5051

5152

5253
@router.get(
5354
"",
5455
status_code=status.HTTP_200_OK,
55-
response_model=Page[Season],
56+
response_model=Page[ListSeasonResponse],
5657
name="seasons",
5758
)
58-
async def get_seasons(
59-
session: AsyncSession = Depends(get_async_session), # noqa: B008
60-
) -> Page[Season]:
59+
async def get_seasons() -> Page[ListSeasonResponse]:
6160
"""Retrieve specific seasons.
6261
6362
Access a comprehensive list of all Futurama seasons using this endpoint,
@@ -67,4 +66,5 @@ async def get_seasons(
6766
This endpoint is valuable for those interested in exploring the entirety of Futurama's seasons or implementing
6867
features like season browsing on your site.
6968
"""
70-
return await Season.paginate(session)
69+
service: ListSeasonsService = ListSeasonsService()
70+
return await service()

futuramaapi/routers/services/__init__.py

Whitespace-only changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from abc import ABC, abstractmethod
2+
from collections.abc import Sequence
3+
from typing import Any
4+
5+
from futuramaapi.helpers.pydantic import BaseModel
6+
7+
8+
class BaseService(BaseModel, ABC):
9+
context: dict[str, Any] | None = None
10+
11+
@abstractmethod
12+
async def __call__(self, *args, **kwargs) -> BaseModel | Sequence[BaseModel] | None:
13+
pass

futuramaapi/routers/services/seasons/__init__.py

Whitespace-only changes.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from abc import ABC
2+
3+
from fastapi import HTTPException, status
4+
from pydantic import Field
5+
from sqlalchemy import Select, select
6+
from sqlalchemy.exc import NoResultFound
7+
from sqlalchemy.orm import selectinload
8+
9+
from futuramaapi.helpers.pydantic import BaseModel
10+
from futuramaapi.repositories.models import SeasonModel
11+
from futuramaapi.repositories.session import session_manager
12+
from futuramaapi.routers.services._base import BaseService
13+
14+
15+
class GetSeasonResponse(BaseModel):
16+
class Episode(BaseModel):
17+
id: int
18+
name: str
19+
broadcast_number: int = Field(alias="number")
20+
production_code: str = Field(
21+
examples=[
22+
"1ACV01",
23+
],
24+
)
25+
26+
id: int
27+
episodes: list[Episode]
28+
29+
30+
class GetSeasonService(BaseService, ABC):
31+
pk: int
32+
33+
@property
34+
def statement(self) -> Select:
35+
return select(SeasonModel).where(SeasonModel.id == self.pk).options(selectinload(SeasonModel.episodes))
36+
37+
async def __call__(self, *args, **kwargs) -> GetSeasonResponse:
38+
async with session_manager.session() as session:
39+
try:
40+
season_model: SeasonModel = (await session.execute(self.statement)).scalars().one()
41+
except NoResultFound:
42+
raise HTTPException(
43+
detail="Season not found",
44+
status_code=status.HTTP_404_NOT_FOUND,
45+
) from None
46+
47+
return GetSeasonResponse.model_validate(season_model)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from abc import ABC
2+
3+
from fastapi_pagination import Page
4+
from fastapi_pagination.ext.sqlalchemy import paginate
5+
from sqlalchemy import Select, select
6+
from sqlalchemy.orm import selectinload
7+
8+
from futuramaapi.repositories.models import SeasonModel
9+
from futuramaapi.repositories.session import session_manager
10+
from futuramaapi.routers.services._base import BaseService
11+
from futuramaapi.routers.services.seasons.get_season import GetSeasonResponse
12+
13+
14+
class ListSeasonResponse(GetSeasonResponse):
15+
pass
16+
17+
18+
class ListSeasonsService(BaseService, ABC):
19+
@property
20+
def statement(self) -> Select:
21+
return select(SeasonModel).filter().options(selectinload(SeasonModel.episodes))
22+
23+
async def __call__(self, *args, **kwargs) -> Page[ListSeasonResponse]:
24+
async with session_manager.session() as session:
25+
return await paginate(
26+
session,
27+
self.statement,
28+
)

0 commit comments

Comments
 (0)