сделал слои для содержимого наборов линз в апи

This commit is contained in:
Андрей Дувакин 2025-02-20 20:47:30 +05:00
parent a7e6bb3f59
commit 24405f1e06
10 changed files with 382 additions and 5 deletions

View File

@ -0,0 +1,42 @@
from typing import Sequence, Optional
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.domain.models import SetContent
class SetContentRepository:
def __init__(self, db: AsyncSession):
self.db = db
async def get_all(self) -> Sequence[SetContent]:
stmt = select(SetContent)
result = await self.db.execute(stmt)
return result.scalars().all()
async def get_by_id(self, set_content_id: int) -> Optional[SetContent]:
stmt = select(SetContent).filter(SetContent.id == set_content_id)
result = await self.db.execute(stmt)
return result.scalars().first()
async def get_by_set_id(self, set_id: int) -> Sequence[SetContent]:
stmt = select(SetContent).filter(SetContent.set_id == set_id)
result = await self.db.execute(stmt)
return result.scalars().all()
async def create(self, set_content: SetContent) -> SetContent:
self.db.add(set_content)
await self.db.commit()
await self.db.refresh(set_content)
return set_content
async def update(self, set_content: SetContent) -> SetContent:
await self.db.merge(set_content)
await self.db.commit()
return set_content
async def delete(self, set_content: SetContent) -> SetContent:
await self.db.delete(set_content)
await self.db.commit()
return set_content

View File

@ -0,0 +1,70 @@
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from app.database.session import get_db
from app.domain.entities.set_content import SetContentEntity
from app.infrastructure.dependencies import get_current_user
from app.infrastructure.set_content_service import SetContentService
router = APIRouter()
@router.get(
'/set_content/{set_id}/',
response_model=list[SetContentEntity],
summary='Get all set content by set ID',
description='Returns a list of set content by set ID',
)
async def get_set_content_by_set_id(
set_id: int,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
set_content_service = SetContentService(db)
return await set_content_service.get_content_by_set_id(set_id)
@router.post(
'/set_content/',
response_model=SetContentEntity,
summary='Create a new set content',
description='Create a new set content',
)
async def create_set_content(
set_content: SetContentEntity,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
set_content_service = SetContentService(db)
return await set_content_service.create_set_content(set_content)
@router.put(
'/set_content/{set_content_id}/',
response_model=SetContentEntity,
summary='Update a set content',
description='Update a set content',
)
async def update_set_content(
set_content_id: int,
set_content: SetContentEntity,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
set_content_service = SetContentService(db)
return await set_content_service.update_set_content(set_content_id, set_content)
@router.delete(
'/set_content/{set_content_id}/',
response_model=SetContentEntity,
summary='Delete set content',
description='Delete an existing set content',
)
async def delete_set_content(
set_content_id: int,
db: AsyncSession = Depends(get_db),
user=Depends(get_current_user),
):
set_content_service = SetContentService(db)
return await set_content_service.delete_set_content(set_content_id)

View File

@ -51,7 +51,7 @@ async def update_set(
user=Depends(get_current_user), user=Depends(get_current_user),
): ):
sets_service = SetsService(db) sets_service = SetsService(db)
return sets_service.update_set(set_id, _set) return await sets_service.update_set(set_id, _set)
@router.delete( @router.delete(

View File

@ -0,0 +1,32 @@
"""добавил тип линзы у содержимого отчета
Revision ID: 15df0d2bfad5
Revises: a5c09be17888
Create Date: 2025-02-20 19:51:20.196094
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '15df0d2bfad5'
down_revision: Union[str, None] = 'a5c09be17888'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('set_contents', sa.Column('type_id', sa.Integer(), nullable=False))
op.create_foreign_key(None, 'set_contents', 'lens_types', ['type_id'], ['id'])
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'set_contents', type_='foreignkey')
op.drop_column('set_contents', 'type_id')
# ### end Alembic commands ###

View File

@ -0,0 +1,29 @@
"""сделал у содержания набора тип стороны enum
Revision ID: a5c09be17888
Revises: 0249759985c3
Create Date: 2025-02-20 19:39:57.756998
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'a5c09be17888'
down_revision: Union[str, None] = '0249759985c3'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.execute("ALTER TABLE set_contents ALTER COLUMN side TYPE sideenum USING CASE "
"WHEN side = 0 THEN 'LEFT'::sideenum "
"WHEN side = 1 THEN 'RIGHT'::sideenum END")
def downgrade() -> None:
op.execute("ALTER TABLE set_contents ALTER COLUMN side TYPE INTEGER USING CASE "
"WHEN side = 'LEFT' THEN 0 "
"WHEN side = 'RIGHT' THEN 1 END")

View File

@ -15,4 +15,5 @@ class SetContentEntity(BaseModel):
side: str side: str
count: int count: int
type_id: int
set_id: int set_id: int

View File

@ -1,7 +1,8 @@
from sqlalchemy import Column, Integer, ForeignKey from sqlalchemy import Column, Integer, ForeignKey, Enum
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from app.domain.models.base import BaseModel from app.domain.models.base import BaseModel
from app.domain.models.lens import SideEnum
class SetContent(BaseModel): class SetContent(BaseModel):
@ -14,9 +15,11 @@ class SetContent(BaseModel):
preset_refraction = Column(Integer, nullable=False) preset_refraction = Column(Integer, nullable=False)
diameter = Column(Integer, nullable=False) diameter = Column(Integer, nullable=False)
periphery_toricity = Column(Integer, nullable=False) periphery_toricity = Column(Integer, nullable=False)
side = Column(Integer, nullable=False) side = Column(Enum(SideEnum), nullable=False)
count = Column(Integer, nullable=False) count = Column(Integer, nullable=False)
type_id = Column(Integer, ForeignKey('lens_types.id'), nullable=False)
set_id = Column(Integer, ForeignKey('sets.id'), nullable=False) set_id = Column(Integer, ForeignKey('sets.id'), nullable=False)
type = relationship('LensType', back_populates='lenses')
set = relationship('Set', back_populates='contents') set = relationship('Set', back_populates='contents')

View File

@ -1,4 +1,4 @@
from typing import Optional, Any, Coroutine from typing import Optional
from fastapi import HTTPException from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
@ -41,7 +41,7 @@ class LensesService:
if not lens_type: if not lens_type:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, status_code=status.HTTP_400_BAD_REQUEST,
detail='The lens type with this ID was not found' detail='The lens type with this ID was not found',
) )
try: try:

View File

@ -0,0 +1,198 @@
from typing import Optional
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from starlette import status
from app.application.lens_types_repository import LensTypesRepository
from app.application.set_content_repository import SetContentRepository
from app.application.sets_repository import SetsRepository
from app.domain.entities.set_content import SetContentEntity
from app.domain.models import SetContent
from app.domain.models.lens import SideEnum
class SetContentService:
def __init__(self, db: AsyncSession):
self.set_content_repository = SetContentRepository(db)
self.set_repository = SetsRepository(db)
self.lens_types_repository = LensTypesRepository(db)
async def get_all_set_content(self) -> list[SetContentEntity]:
set_content = await self.set_content_repository.get_all()
return [
SetContentEntity(
id=content.id,
tor=content.tor,
trial=content.trial,
esa=content.esa,
fvc=content.fvc,
preset_refraction=content.preset_refraction,
diameter=content.diameter,
periphery_toricity=content.periphery_toricity,
side=content.side,
count=content.count,
type_id=content.type_id,
set_id=content.set_id,
)
for content in set_content
]
async def get_content_by_set_id(self, set_id: int) -> Optional[list[SetContentEntity]]:
_set = self.set_repository.get_by_id(set_id)
if not _set:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The set with this ID was not found',
)
set_content = await self.set_content_repository.get_by_set_id(set_id)
return [
SetContentEntity(
id=content.id,
tor=content.tor,
trial=content.trial,
esa=content.esa,
fvc=content.fvc,
preset_refraction=content.preset_refraction,
diameter=content.diameter,
periphery_toricity=content.periphery_toricity,
side=content.side,
count=content.count,
type_id=content.type_id,
set_id=content.set_id,
)
for content in set_content
]
async def create_set_content(self, set_content: SetContentEntity) -> SetContentEntity:
lens_type = await self.lens_types_repository.get_by_id(set_content.type_id)
if not lens_type:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The lens type with this ID was not found',
)
_set = self.set_repository.get_by_id(set_content.set_id)
if not _set:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The set with this ID was not found',
)
try:
side_enum = SideEnum(set_content.side)
except ValueError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Invalid side value: {set_content.side}. Must be 'левая' or 'правая'."
)
set_content_model = SetContent(
tor=set_content.tor,
trial=set_content.trial,
esa=set_content.esa,
fvc=set_content.fvc,
preset_refraction=set_content.preset_refraction,
diameter=set_content.diameter,
periphery_toricity=set_content.periphery_toricity,
side=side_enum,
count=set_content.count,
type_id=set_content.type_id,
set_id=set_content.set_id,
)
await self.set_content_repository.create(set_content_model)
return SetContentEntity(
id=set_content_model.id,
tor=set_content_model.tor,
trial=set_content_model.trial,
esa=set_content_model.esa,
fvc=set_content_model.fvc,
preset_refraction=set_content_model.preset_refraction,
diameter=set_content_model.diameter,
periphery_toricity=set_content_model.periphery_toricity,
side=set_content_model.side.value,
count=set_content_model.count,
type_id=set_content_model.type_id,
set_id=set_content_model.set_id,
)
async def update_set_content(self, set_content_id: int, set_content: SetContentEntity):
set_content_model = await self.set_content_repository.get_by_id(set_content_id)
if not set_content_model:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Set content not found")
_set = await self.set_repository.get_by_id(set_content.set_id)
if not _set:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='The set with this ID was not found',
)
try:
side_enum = SideEnum(set_content_model.side)
except ValueError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Invalid side value: {set_content_model.side}. Must be 'левая' or 'правая'."
)
set_content_model.tor = set_content.tor
set_content_model.trial = set_content.trial
set_content_model.esa = set_content.esa
set_content_model.fvc = set_content.fvc
set_content_model.preset_refraction = set_content.preset_refraction
set_content_model.diameter = set_content.diameter
set_content_model.periphery_toricity = set_content.periphery_toricity
set_content_model.side = side_enum
set_content_model.count = set_content.count
set_content_model.type_id = set_content.type_id
set_content_model.set_id = set_content.set_id
await self.set_content_repository.update(set_content_model)
return SetContentEntity(
id=set_content_model.id,
tor=set_content_model.tor,
trial=set_content_model.trial,
esa=set_content_model.esa,
fvc=set_content_model.fvc,
preset_refraction=set_content_model.preset_refraction,
diameter=set_content_model.diameter,
periphery_toricity=set_content_model.periphery_toricity,
side=set_content_model.side.value,
count=set_content_model.count,
type_id=set_content_model.type_id,
set_id=set_content_model.set_id,
)
async def delete_set_content(self, set_content_id: int) -> Optional[SetContentEntity]:
set_content = await self.set_content_repository.get_by_id(set_content_id)
if not set_content:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Set content not found")
result = await self.set_content_repository.delete(set_content)
return SetContentEntity(
id=result.id,
tor=result.tor,
trial=result.trial,
esa=result.esa,
fvc=result.fvc,
preset_refraction=result.preset_refraction,
diameter=result.diameter,
periphery_toricity=result.periphery_toricity,
side=result.side.value,
count=result.count,
type_id=result.type_id,
set_id=result.set_id,
)

View File

@ -6,6 +6,7 @@ from app.controllers.lens_types_router import router as lens_types_router
from app.controllers.lenses_router import router as lenses_router from app.controllers.lenses_router import router as lenses_router
from app.controllers.patients_router import router as patients_router from app.controllers.patients_router import router as patients_router
from app.controllers.register_routes import router as register_router from app.controllers.register_routes import router as register_router
from app.controllers.set_content_router import router as set_content_router
from app.controllers.sets_router import router as sets_router from app.controllers.sets_router import router as sets_router
from app.settings import settings from app.settings import settings
@ -27,6 +28,7 @@ def start_app():
api_app.include_router(lenses_router, prefix=settings.APP_PREFIX, tags=['lenses']) api_app.include_router(lenses_router, prefix=settings.APP_PREFIX, tags=['lenses'])
api_app.include_router(lens_types_router, prefix=settings.APP_PREFIX, tags=['lens_types']) api_app.include_router(lens_types_router, prefix=settings.APP_PREFIX, tags=['lens_types'])
api_app.include_router(sets_router, prefix=settings.APP_PREFIX, tags=['sets']) api_app.include_router(sets_router, prefix=settings.APP_PREFIX, tags=['sets'])
api_app.include_router(set_content_router, prefix=settings.APP_PREFIX, tags=['set_content'])
return api_app return api_app