Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.11.4
113 changes: 62 additions & 51 deletions workout_api/atleta/controller.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
from datetime import datetime
from uuid import uuid4
from fastapi import APIRouter, Body, HTTPException, status
from fastapi import APIRouter, Body, HTTPException, status, Query
from pydantic import UUID4
from sqlalchemy.exc import IntegrityError
from sqlalchemy.future import select
from fastapi_pagination import Page, add_pagination, paginate

from workout_api.atleta.schemas import AtletaIn, AtletaOut, AtletaUpdate
from workout_api.atleta.models import AtletaModel
from workout_api.categorias.models import CategoriaModel
from workout_api.centro_treinamento.models import CentroTreinamentoModel

from workout_api.contrib.dependencies import DatabaseDependency
from sqlalchemy.future import select

router = APIRouter()


@router.post(
'/',
'/',
summary='Criar um novo atleta',
status_code=status.HTTP_201_CREATED,
response_model=AtletaOut
response_model=AtletaOut,
)
async def post(
db_session: DatabaseDependency,
atleta_in: AtletaIn = Body(...)
db_session: DatabaseDependency,
atleta_in: AtletaIn = Body(...),
):
categoria_nome = atleta_in.categoria.nome
centro_treinamento_nome = atleta_in.centro_treinamento.nome
Expand All @@ -32,7 +34,7 @@ async def post(

if not categoria:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
status_code=status.HTTP_400_BAD_REQUEST,
detail=f'A categoria {categoria_nome} não foi encontrada.'
)

Expand All @@ -42,101 +44,110 @@ async def post(

if not centro_treinamento:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
status_code=status.HTTP_400_BAD_REQUEST,
detail=f'O centro de treinamento {centro_treinamento_nome} não foi encontrado.'
)
try:
atleta_out = AtletaOut(id=uuid4(), created_at=datetime.utcnow(), **atleta_in.model_dump())
atleta_model = AtletaModel(**atleta_out.model_dump(exclude={'categoria', 'centro_treinamento'}))

atleta_model.categoria_id = categoria.pk_id
atleta_model.centro_treinamento_id = centro_treinamento.pk_id

atleta_out = AtletaOut(id=uuid4(), created_at=datetime.now(), **atleta_in.model_dump())
atleta_model = AtletaModel(**atleta_out.model_dump(exclude={'categoria', 'centro_treinamento'}))
atleta_model.categoria_id = categoria.pk_id
atleta_model.centro_treinamento_id = centro_treinamento.pk_id

try:
db_session.add(atleta_model)
await db_session.commit()
except Exception:
except IntegrityError:
await db_session.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail='Ocorreu um erro ao inserir os dados no banco'
status_code=303,
detail=f"Já existe um atleta cadastrado com o cpf: {atleta_in.cpf}"
)

return atleta_out


@router.get(
'/',
'/',
summary='Consultar todos os Atletas',
status_code=status.HTTP_200_OK,
response_model=list[AtletaOut],
response_model=Page[AtletaOut],
)
async def query(db_session: DatabaseDependency) -> list[AtletaOut]:
atletas: list[AtletaOut] = (await db_session.execute(select(AtletaModel))).scalars().all()

return [AtletaOut.model_validate(atleta) for atleta in atletas]
async def query(
db_session: DatabaseDependency,
nome: str | None = Query(None, description="Filtrar por nome"),
cpf: str | None = Query(None, description="Filtrar por CPF"),
):
query_stmt = select(AtletaModel)
if nome:
query_stmt = query_stmt.filter_by(nome=nome)
if cpf:
query_stmt = query_stmt.filter_by(cpf=cpf)

atletas = (await db_session.execute(query_stmt)).scalars().all()
return paginate(atletas)


@router.get(
'/{id}',
'/{id}',
summary='Consulta um Atleta pelo id',
status_code=status.HTTP_200_OK,
response_model=AtletaOut,
)
async def get(id: UUID4, db_session: DatabaseDependency) -> AtletaOut:
atleta: AtletaOut = (
await db_session.execute(select(AtletaModel).filter_by(id=id))
).scalars().first()

atleta = (await db_session.execute(select(AtletaModel).filter_by(id=id))).scalars().first()
if not atleta:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
status_code=status.HTTP_404_NOT_FOUND,
detail=f'Atleta não encontrado no id: {id}'
)

return atleta


@router.patch(
'/{id}',
'/{id}',
summary='Editar um Atleta pelo id',
status_code=status.HTTP_200_OK,
response_model=AtletaOut,
)
async def patch(id: UUID4, db_session: DatabaseDependency, atleta_up: AtletaUpdate = Body(...)) -> AtletaOut:
atleta: AtletaOut = (
await db_session.execute(select(AtletaModel).filter_by(id=id))
).scalars().first()

atleta = (await db_session.execute(select(AtletaModel).filter_by(id=id))).scalars().first()
if not atleta:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
status_code=status.HTTP_404_NOT_FOUND,
detail=f'Atleta não encontrado no id: {id}'
)

atleta_update = atleta_up.model_dump(exclude_unset=True)
for key, value in atleta_update.items():

for key, value in atleta_up.model_dump(exclude_unset=True).items():
setattr(atleta, key, value)

await db_session.commit()
await db_session.refresh(atleta)
try:
await db_session.commit()
await db_session.refresh(atleta)
except IntegrityError:
await db_session.rollback()
raise HTTPException(
status_code=303,
detail=f"Já existe um atleta cadastrado com o cpf: {atleta_up.cpf}"
)

return atleta


@router.delete(
'/{id}',
'/{id}',
summary='Deletar um Atleta pelo id',
status_code=status.HTTP_204_NO_CONTENT
status_code=status.HTTP_204_NO_CONTENT,
)
async def delete(id: UUID4, db_session: DatabaseDependency) -> None:
atleta: AtletaOut = (
await db_session.execute(select(AtletaModel).filter_by(id=id))
).scalars().first()

atleta = (await db_session.execute(select(AtletaModel).filter_by(id=id))).scalars().first()
if not atleta:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
status_code=status.HTTP_404_NOT_FOUND,
detail=f'Atleta não encontrado no id: {id}'
)

await db_session.delete(atleta)
await db_session.commit()


# Integrar paginação
add_pagination(router)
7 changes: 6 additions & 1 deletion workout_api/atleta/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@ class AtletaOut(Atleta, OutMixin):

class AtletaUpdate(BaseSchema):
nome: Annotated[Optional[str], Field(None, description='Nome do atleta', example='Joao', max_length=50)]
idade: Annotated[Optional[int], Field(None, description='Idade do atleta', example=25)]
idade: Annotated[Optional[int], Field(None, description='Idade do atleta', example=25)]

class AtletaListOut(BaseSchema):
nome: str
categoria: CategoriaIn
centro_treinamento: CentroTreinamentoAtleta
95 changes: 81 additions & 14 deletions workout_api/categorias/controller.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from uuid import uuid4
from fastapi import APIRouter, Body, HTTPException, status
from fastapi import APIRouter, Body, HTTPException, Query, status
from pydantic import UUID4
from workout_api.categorias.schemas import CategoriaIn, CategoriaOut
from workout_api.categorias.models import CategoriaModel
from sqlalchemy.future import select
from sqlalchemy.exc import IntegrityError
from fastapi_pagination import Page, paginate

from workout_api.categorias.schemas import CategoriaIn, CategoriaOut, CategoriaUpdate
from workout_api.categorias.models import CategoriaModel
from workout_api.contrib.dependencies import DatabaseDependency
from sqlalchemy.future import select

router = APIRouter()


@router.post(
'/',
summary='Criar uma nova Categoria',
Expand All @@ -21,23 +24,37 @@ async def post(
) -> CategoriaOut:
categoria_out = CategoriaOut(id=uuid4(), **categoria_in.model_dump())
categoria_model = CategoriaModel(**categoria_out.model_dump())

db_session.add(categoria_model)
await db_session.commit()
try:
await db_session.commit()
except IntegrityError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"A categoria '{categoria_in.nome}' já existe."
)

return categoria_out


@router.get(
'/',
summary='Consultar todas as Categorias',
status_code=status.HTTP_200_OK,
response_model=list[CategoriaOut],
response_model=Page[CategoriaOut],
)
async def query(db_session: DatabaseDependency) -> list[CategoriaOut]:
categorias: list[CategoriaOut] = (await db_session.execute(select(CategoriaModel))).scalars().all()

return categorias
async def query(
db_session: DatabaseDependency,
nome: str | None = Query(None, description="Filtrar categorias pelo nome"),
) -> Page[CategoriaOut]:
query = select(CategoriaModel)

if nome:
query = query.filter(CategoriaModel.nome.ilike(f"%{nome}%"))

categorias = (await db_session.execute(query)).scalars().all()

return paginate([CategoriaOut.model_validate(c) for c in categorias])


@router.get(
Expand All @@ -57,4 +74,54 @@ async def get(id: UUID4, db_session: DatabaseDependency) -> CategoriaOut:
detail=f'Categoria não encontrada no id: {id}'
)

return categoria
return CategoriaOut.model_validate(categoria)


@router.patch(
'/{id}',
summary='Editar uma Categoria pelo id',
status_code=status.HTTP_200_OK,
response_model=CategoriaOut,
)
async def patch(
id: UUID4,
db_session: DatabaseDependency,
categoria_up: CategoriaUpdate = Body(...),
) -> CategoriaOut:
categoria = (
await db_session.execute(select(CategoriaModel).filter_by(id=id))
).scalars().first()

if not categoria:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f'Categoria não encontrada no id: {id}'
)

for key, value in categoria_up.model_dump(exclude_unset=True).items():
setattr(categoria, key, value)

await db_session.commit()
await db_session.refresh(categoria)

return CategoriaOut.model_validate(categoria)


@router.delete(
'/{id}',
summary='Deletar uma Categoria pelo id',
status_code=status.HTTP_204_NO_CONTENT,
)
async def delete(id: UUID4, db_session: DatabaseDependency) -> None:
categoria = (
await db_session.execute(select(CategoriaModel).filter_by(id=id))
).scalars().first()

if not categoria:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f'Categoria não encontrada no id: {id}'
)

await db_session.delete(categoria)
await db_session.commit()
10 changes: 5 additions & 5 deletions workout_api/categorias/schemas.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from typing import Annotated

from typing import Annotated, Optional
from pydantic import UUID4, Field
from workout_api.contrib.schemas import BaseSchema
from workout_api.contrib.schemas import BaseSchema, OutMixin


class CategoriaIn(BaseSchema):
nome: Annotated[str, Field(description='Nome da categoria', example='Scale', max_length=10)]


class CategoriaOut(CategoriaIn):
class CategoriaOut(CategoriaIn, OutMixin):
id: Annotated[UUID4, Field(description='Identificador da categoria')]

class CategoriaUpdate(BaseSchema):
nome: Annotated[Optional[str], Field(None, description='Nome da categoria', example='Scale', max_length=10)]
Loading