Compare commits

...

7 Commits

9 changed files with 175 additions and 109 deletions

View File

@ -4,8 +4,8 @@ from fastapi import Depends
from sqlalchemy import delete, select, update from sqlalchemy import delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from fastfood import models
from fastfood.dbase import get_async_session from fastfood.dbase import get_async_session
from fastfood.models import Dish
from fastfood.schemas import Dish_db from fastfood.schemas import Dish_db
@ -13,20 +13,20 @@ class DishRepository:
def __init__(self, session: AsyncSession = Depends(get_async_session)): def __init__(self, session: AsyncSession = Depends(get_async_session)):
self.db = session self.db = session
async def get_dishes(self, menu_id: UUID, submenu_id: UUID): async def get_dishes(self, menu_id: UUID, submenu_id: UUID) -> list[Dish]:
query = select(models.Dish).where( query = select(Dish).where(
models.Dish.parent_submenu == submenu_id, Dish.parent_submenu == submenu_id,
) )
dishes = await self.db.execute(query) dishes = await self.db.execute(query)
return dishes.scalars().all() return [x for x in dishes.scalars().all()]
async def create_dish_item( async def create_dish_item(
self, self,
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
dish_data: Dish_db, dish_data: Dish_db,
): ) -> Dish:
new_dish = models.Dish(**dish_data.model_dump()) new_dish = Dish(**dish_data.model_dump())
new_dish.parent_submenu = submenu_id new_dish.parent_submenu = submenu_id
self.db.add(new_dish) self.db.add(new_dish)
await self.db.commit() await self.db.commit()
@ -38,8 +38,8 @@ class DishRepository:
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
dish_id: UUID, dish_id: UUID,
): ) -> Dish | None:
query = select(models.Dish).where(models.Dish.id == dish_id) query = select(Dish).where(Dish.id == dish_id)
submenu = await self.db.execute(query) submenu = await self.db.execute(query)
return submenu.scalars().one_or_none() return submenu.scalars().one_or_none()
@ -49,15 +49,11 @@ class DishRepository:
submenu_id: UUID, submenu_id: UUID,
dish_id: UUID, dish_id: UUID,
dish_data: Dish_db, dish_data: Dish_db,
): ) -> Dish:
query = ( query = update(Dish).where(Dish.id == dish_id).values(**dish_data.model_dump())
update(models.Dish)
.where(models.Dish.id == dish_id)
.values(**dish_data.model_dump())
)
await self.db.execute(query) await self.db.execute(query)
await self.db.commit() await self.db.commit()
qr = select(models.Dish).where(models.Dish.id == dish_id) qr = select(Dish).where(Dish.id == dish_id)
updated_submenu = await self.db.execute(qr) updated_submenu = await self.db.execute(qr)
return updated_submenu.scalars().one() return updated_submenu.scalars().one()
@ -66,7 +62,8 @@ class DishRepository:
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
dish_id: UUID, dish_id: UUID,
): ) -> int:
query = delete(models.Dish).where(models.Dish.id == dish_id) query = delete(Dish).where(Dish.id == dish_id)
await self.db.execute(query) await self.db.execute(query)
await self.db.commit() await self.db.commit()
return 200

View File

@ -5,30 +5,31 @@ from sqlalchemy import delete, distinct, func, select, update
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import aliased from sqlalchemy.orm import aliased
from fastfood import models, schemas from fastfood import schemas
from fastfood.dbase import get_async_session from fastfood.dbase import get_async_session
from fastfood.models import Dish, Menu, SubMenu
class MenuRepository: class MenuRepository:
def __init__(self, session: AsyncSession = Depends(get_async_session)): def __init__(self, session: AsyncSession = Depends(get_async_session)):
self.db = session self.db = session
async def get_menus(self): async def get_menus(self) -> list[Menu]:
query = select(models.Menu) query = select(Menu)
menus = await self.db.execute(query) menus = await self.db.execute(query)
return menus.scalars().all() return [x for x in menus.scalars().all()]
async def create_menu_item(self, menu: schemas.MenuBase): async def create_menu_item(self, menu: schemas.MenuBase) -> Menu:
new_menu = models.Menu(**menu.model_dump()) new_menu = Menu(**menu.model_dump())
self.db.add(new_menu) self.db.add(new_menu)
await self.db.commit() await self.db.commit()
await self.db.refresh(new_menu) await self.db.refresh(new_menu)
return new_menu return new_menu
async def get_menu_item(self, menu_id: UUID): async def get_menu_item(self, menu_id: UUID) -> Menu | None:
m = aliased(models.Menu) m = aliased(Menu)
s = aliased(models.SubMenu) s = aliased(SubMenu)
d = aliased(models.Dish) d = aliased(Dish)
query = ( query = (
select( select(
@ -51,19 +52,16 @@ class MenuRepository:
self, self,
menu_id: UUID, menu_id: UUID,
menu: schemas.MenuBase, menu: schemas.MenuBase,
): ) -> Menu:
query = ( query = update(Menu).where(Menu.id == menu_id).values(**menu.model_dump())
update(models.Menu)
.where(models.Menu.id == menu_id)
.values(**menu.model_dump())
)
await self.db.execute(query) await self.db.execute(query)
await self.db.commit() await self.db.commit()
qr = select(models.Menu).where(models.Menu.id == menu_id) qr = select(Menu).where(Menu.id == menu_id)
updated_menu = await self.db.execute(qr) updated_menu = await self.db.execute(qr)
return updated_menu return updated_menu.scalar_one()
async def delete_menu_item(self, menu_id: UUID): async def delete_menu_item(self, menu_id: UUID) -> int:
query = delete(models.Menu).where(models.Menu.id == menu_id) query = delete(Menu).where(Menu.id == menu_id)
await self.db.execute(query) await self.db.execute(query)
await self.db.commit() await self.db.commit()
return 200

View File

@ -5,40 +5,45 @@ from sqlalchemy import delete, distinct, func, select, update
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import aliased from sqlalchemy.orm import aliased
from fastfood import models, schemas
from fastfood.dbase import get_async_session from fastfood.dbase import get_async_session
from fastfood.models import Dish, SubMenu
from fastfood.schemas import MenuBase
class SubMenuRepository: class SubMenuRepository:
def __init__(self, session: AsyncSession = Depends(get_async_session)): def __init__(self, session: AsyncSession = Depends(get_async_session)):
self.db = session self.db = session
async def get_submenus(self, menu_id: UUID): async def get_submenus(self, menu_id: UUID) -> list[SubMenu]:
query = select(models.SubMenu).where( query = select(SubMenu).where(
models.SubMenu.parent_menu == menu_id, SubMenu.parent_menu == menu_id,
) )
submenus = await self.db.execute(query) submenus = await self.db.execute(query)
return submenus return [x for x in submenus.scalars().all()]
async def create_submenu_item( async def create_submenu_item(
self, self,
menu_id: UUID, menu_id: UUID,
submenu: schemas.MenuBase, submenu: MenuBase,
): ) -> SubMenu:
new_submenu = models.SubMenu(**submenu.model_dump()) new_submenu = SubMenu(**submenu.model_dump())
new_submenu.parent_menu = menu_id new_submenu.parent_menu = menu_id
self.db.add(new_submenu) self.db.add(new_submenu)
await self.db.commit() await self.db.commit()
await self.db.refresh(new_submenu) await self.db.refresh(new_submenu)
return new_submenu
full_sub = await self.get_submenu_item(menu_id, new_submenu.id)
if full_sub is None:
raise TypeError
return full_sub
async def get_submenu_item( async def get_submenu_item(
self, self,
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
): ) -> SubMenu | None:
s = aliased(models.SubMenu) s = aliased(SubMenu)
d = aliased(models.Dish) d = aliased(Dish)
query = ( query = (
select(s, func.count(distinct(d.id)).label('dishes_count')) select(s, func.count(distinct(d.id)).label('dishes_count'))
.join(d, s.id == d.parent_submenu, isouter=True) .join(d, s.id == d.parent_submenu, isouter=True)
@ -55,22 +60,23 @@ class SubMenuRepository:
self, self,
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
submenu_data: schemas.MenuBase, submenu_data: MenuBase,
): ) -> SubMenu:
query = ( query = (
update(models.SubMenu) update(SubMenu)
.where(models.SubMenu.id == submenu_id) .where(SubMenu.id == submenu_id)
.values(**submenu_data.model_dump()) .values(**submenu_data.model_dump())
) )
await self.db.execute(query) await self.db.execute(query)
await self.db.commit() await self.db.commit()
qr = select(models.SubMenu).where(models.SubMenu.id == submenu_id) qr = select(SubMenu).where(SubMenu.id == submenu_id)
updated_submenu = await self.db.execute(qr) updated_submenu = await self.db.execute(qr)
return updated_submenu return updated_submenu.scalar_one()
async def delete_submenu_item(self, menu_id: UUID, submenu_id: UUID): async def delete_submenu_item(self, menu_id: UUID, submenu_id: UUID) -> int:
query = delete(models.SubMenu).where( query = delete(SubMenu).where(
models.SubMenu.id == submenu_id, SubMenu.id == submenu_id,
) )
await self.db.execute(query) await self.db.execute(query)
await self.db.commit() await self.db.commit()
return 200

View File

@ -17,7 +17,7 @@ async def get_dishes(
submenu_id: UUID, submenu_id: UUID,
dish: DishService = Depends(), dish: DishService = Depends(),
background_tasks: BackgroundTasks = BackgroundTasks(), background_tasks: BackgroundTasks = BackgroundTasks(),
): ) -> list[Dish]:
result = await dish.read_dishes(menu_id, submenu_id) result = await dish.read_dishes(menu_id, submenu_id)
return result return result

View File

@ -2,7 +2,7 @@ from uuid import UUID
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
from fastfood.schemas import Menu, MenuBase, MenuRead from fastfood.schemas import MenuBase, MenuRead
from fastfood.service.menu import MenuService from fastfood.service.menu import MenuService
router = APIRouter( router = APIRouter(
@ -11,7 +11,7 @@ router = APIRouter(
) )
@router.get('/', response_model=list[Menu]) @router.get('/', response_model=list[MenuRead])
async def get_menus( async def get_menus(
menu: MenuService = Depends(), menu: MenuService = Depends(),
background_tasks: BackgroundTasks = BackgroundTasks(), background_tasks: BackgroundTasks = BackgroundTasks(),
@ -19,7 +19,7 @@ async def get_menus(
return await menu.read_menus() return await menu.read_menus()
@router.post('/', status_code=201, response_model=Menu) @router.post('/', status_code=201, response_model=MenuRead)
async def add_menu( async def add_menu(
menu: MenuBase, menu: MenuBase,
responce: MenuService = Depends(), responce: MenuService = Depends(),
@ -52,7 +52,7 @@ async def update_menu(
menu_id=menu_id, menu_id=menu_id,
menu_data=menu, menu_data=menu,
) )
return result.scalars().one() return result
@router.delete('/{menu_id}') @router.delete('/{menu_id}')

View File

@ -1,4 +1,3 @@
from typing import Optional
from uuid import UUID from uuid import UUID
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
@ -12,14 +11,14 @@ router = APIRouter(
) )
@router.get('/', response_model=Optional[list[SubMenuRead]]) @router.get('/', response_model=list[SubMenuRead])
async def get_submenus( async def get_submenus(
menu_id: UUID, menu_id: UUID,
submenu: SubmenuService = Depends(), submenu: SubmenuService = Depends(),
background_tasks: BackgroundTasks = BackgroundTasks(), background_tasks: BackgroundTasks = BackgroundTasks(),
): ):
result = await submenu.read_submenus(menu_id=menu_id) result = await submenu.read_submenus(menu_id=menu_id)
return result.scalars().all() return result
@router.post('/', status_code=201, response_model=SubMenuRead) @router.post('/', status_code=201, response_model=SubMenuRead)
@ -54,7 +53,7 @@ async def get_submenu(
@router.patch( @router.patch(
'/{submenu_id}', '/{submenu_id}',
response_model=MenuBase, response_model=SubMenuRead,
) )
async def update_submenu( async def update_submenu(
menu_id: UUID, menu_id: UUID,
@ -68,7 +67,7 @@ async def update_submenu(
submenu_id=submenu_id, submenu_id=submenu_id,
submenu_data=submenu_data, submenu_data=submenu_data,
) )
return result.scalars().one() return result
@router.delete('/{submenu_id}') @router.delete('/{submenu_id}')

View File

@ -6,7 +6,7 @@ from fastapi import BackgroundTasks, Depends
from fastfood.dbase import get_async_redis_client from fastfood.dbase import get_async_redis_client
from fastfood.repository.dish import DishRepository from fastfood.repository.dish import DishRepository
from fastfood.repository.redis import RedisRepository from fastfood.repository.redis import RedisRepository
from fastfood.schemas import Dish_db, DishBase from fastfood.schemas import Dish, Dish_db, DishBase
class DishService: class DishService:
@ -15,26 +15,26 @@ class DishService:
dish_repo: DishRepository = Depends(), dish_repo: DishRepository = Depends(),
redis_client: redis.Redis = Depends(get_async_redis_client), redis_client: redis.Redis = Depends(get_async_redis_client),
background_tasks: BackgroundTasks = None, background_tasks: BackgroundTasks = None,
): ) -> None:
self.dish_repo = dish_repo self.dish_repo = dish_repo
self.cache_client = RedisRepository(redis_client) self.cache_client = RedisRepository(redis_client)
self.background_tasks = background_tasks self.background_tasks = background_tasks
async def read_dishes(self, menu_id: UUID, submenu_id: UUID): async def read_dishes(self, menu_id: UUID, submenu_id: UUID) -> list[Dish]:
data = await self.dish_repo.get_dishes(menu_id, submenu_id) data = await self.dish_repo.get_dishes(menu_id, submenu_id)
response = [] response = []
for row in data: for row in data:
dish = row.__dict__ dish = row.__dict__
dish['price'] = str(dish['price']) dish['price'] = str(dish['price'])
response.append(dish) response.append(Dish(**dish))
return data return response
async def create_dish( async def create_dish(
self, self,
menu_id: UUID, menu_id: UUID,
submenu_id: UUID, submenu_id: UUID,
dish_data: DishBase, dish_data: DishBase,
): ) -> Dish:
dish = Dish_db(**dish_data.model_dump()) dish = Dish_db(**dish_data.model_dump())
data = await self.dish_repo.create_dish_item( data = await self.dish_repo.create_dish_item(
menu_id, menu_id,
@ -43,30 +43,31 @@ class DishService:
) )
response = data.__dict__ response = data.__dict__
response['price'] = str(response['price']) response['price'] = str(response['price'])
return response return Dish(**response)
async def read_dish(self, menu_id: UUID, submenu_id: UUID, dish_id: UUID): async def read_dish(
self, menu_id: UUID, submenu_id: UUID, dish_id: UUID
) -> Dish | None:
data = await self.dish_repo.get_dish_item(menu_id, submenu_id, dish_id) data = await self.dish_repo.get_dish_item(menu_id, submenu_id, dish_id)
if data is None: if data is None:
return return None
response = data.__dict__ response = data.__dict__
response['price'] = str(response['price']) response['price'] = str(response['price'])
return Dish(**response)
return response
async def update_dish( async def update_dish(
self, menu_id: UUID, submenu_id: UUID, dish_id, dish_data: DishBase self, menu_id: UUID, submenu_id: UUID, dish_id, dish_data: DishBase
): ) -> Dish:
dish = Dish_db(**dish_data.model_dump()) dish = Dish_db(**dish_data.model_dump())
data = await self.dish_repo.update_dish_item(menu_id, submenu_id, dish_id, dish) data = await self.dish_repo.update_dish_item(menu_id, submenu_id, dish_id, dish)
response = data.__dict__ response = data.__dict__
response['price'] = str(response['price']) response['price'] = str(response['price'])
return response return Dish(**response)
async def del_dish(self, menu_id: UUID, submenu_id: UUID, dish_id: UUID): async def del_dish(self, menu_id: UUID, submenu_id: UUID, dish_id: UUID) -> int:
data = await self.dish_repo.delete_dish_item( response = await self.dish_repo.delete_dish_item(
menu_id, menu_id,
submenu_id, submenu_id,
dish_id, dish_id,
) )
return data return response

View File

@ -6,7 +6,7 @@ from fastapi import BackgroundTasks, Depends
from fastfood.dbase import get_async_redis_client from fastfood.dbase import get_async_redis_client
from fastfood.repository.menu import MenuRepository from fastfood.repository.menu import MenuRepository
from fastfood.repository.redis import RedisRepository from fastfood.repository.redis import RedisRepository
from fastfood.schemas import MenuBase from fastfood.schemas import MenuBase, MenuRead
class MenuService: class MenuService:
@ -15,27 +15,68 @@ class MenuService:
menu_repo: MenuRepository = Depends(), menu_repo: MenuRepository = Depends(),
redis_client: redis.Redis = Depends(get_async_redis_client), redis_client: redis.Redis = Depends(get_async_redis_client),
background_tasks: BackgroundTasks = None, background_tasks: BackgroundTasks = None,
): ) -> None:
self.menu_repo = menu_repo self.menu_repo = menu_repo
self.cache_client = RedisRepository(redis_client) self.cache_client = RedisRepository(redis_client)
self.background_tasks = background_tasks self.background_tasks = background_tasks
async def read_menus(self): async def read_menus(self) -> list[MenuRead]:
data = await self.menu_repo.get_menus() data = await self.menu_repo.get_menus()
return data menus = []
for r in data:
menu = r.__dict__
menu = {k: v for k, v in menu.items() if not k.startswith('_')}
dishes_conter = 0
for sub in r.submenus:
dishes_conter += len(sub.dishes)
async def create_menu(self, menu_data: MenuBase): menu['submenus_count'] = len(menu.pop('submenus'))
menu['dishes_count'] = dishes_conter
menu = MenuRead(**menu)
menus.append(menu)
return menus
async def create_menu(self, menu_data: MenuBase) -> MenuRead:
data = await self.menu_repo.create_menu_item(menu_data) data = await self.menu_repo.create_menu_item(menu_data)
return data menu = data.__dict__
menu = {k: v for k, v in menu.items() if not k.startswith('_')}
dishes_conter = 0
async def read_menu(self, menu_id: UUID): for sub in data.submenus:
dishes_conter += len(sub.dishes)
menu['submenus_count'] = len(menu.pop('submenus'))
menu['dishes_count'] = dishes_conter
return MenuRead(**menu)
async def read_menu(self, menu_id: UUID) -> MenuRead | None:
data = await self.menu_repo.get_menu_item(menu_id) data = await self.menu_repo.get_menu_item(menu_id)
return data if data is None:
return None
menu = data.__dict__
menu = {k: v for k, v in menu.items() if not k.startswith('_')}
dishes_conter = 0
async def update_menu(self, menu_id: UUID, menu_data): for sub in data.submenus:
dishes_conter += len(sub.dishes)
menu['submenus_count'] = len(menu.pop('submenus'))
menu['dishes_count'] = dishes_conter
return MenuRead(**menu)
async def update_menu(self, menu_id: UUID, menu_data) -> MenuRead:
data = await self.menu_repo.update_menu_item(menu_id, menu_data) data = await self.menu_repo.update_menu_item(menu_id, menu_data)
return data menu = data.__dict__
menu = {k: v for k, v in menu.items() if not k.startswith('_')}
dishes_conter = 0
async def del_menu(self, menu_id: UUID): for sub in data.submenus:
dishes_conter += len(sub.dishes)
menu['submenus_count'] = len(menu.pop('submenus'))
menu['dishes_count'] = dishes_conter
return MenuRead(**menu)
async def del_menu(self, menu_id: UUID) -> int:
data = await self.menu_repo.delete_menu_item(menu_id) data = await self.menu_repo.delete_menu_item(menu_id)
return data return data

View File

@ -6,7 +6,7 @@ from fastapi import BackgroundTasks, Depends
from fastfood.dbase import get_async_redis_client from fastfood.dbase import get_async_redis_client
from fastfood.repository.redis import RedisRepository from fastfood.repository.redis import RedisRepository
from fastfood.repository.submenu import SubMenuRepository from fastfood.repository.submenu import SubMenuRepository
from fastfood.schemas import MenuBase from fastfood.schemas import MenuBase, SubMenuRead
class SubmenuService: class SubmenuService:
@ -15,34 +15,58 @@ class SubmenuService:
submenu_repo: SubMenuRepository = Depends(), submenu_repo: SubMenuRepository = Depends(),
redis_client: redis.Redis = Depends(get_async_redis_client), redis_client: redis.Redis = Depends(get_async_redis_client),
background_tasks: BackgroundTasks = None, background_tasks: BackgroundTasks = None,
): ) -> None:
self.submenu_repo = submenu_repo self.submenu_repo = submenu_repo
self.cache_client = RedisRepository(redis_client) self.cache_client = RedisRepository(redis_client)
self.background_tasks = background_tasks self.background_tasks = background_tasks
async def read_submenus(self, menu_id: UUID): async def read_submenus(self, menu_id: UUID) -> list[SubMenuRead]:
data = await self.submenu_repo.get_submenus(menu_id=menu_id) data = await self.submenu_repo.get_submenus(menu_id=menu_id)
return data submenus = []
for r in data:
submenu = r.__dict__
subq = await self.submenu_repo.get_submenu_item(menu_id, r.id)
if subq is not None:
submenu['dishes_count'] = len(subq.dishes)
submenu = SubMenuRead(**submenu)
submenus.append(submenu)
return submenus
async def create_submenu(self, menu_id: UUID, submenu_data: MenuBase): async def create_submenu(
self, menu_id: UUID, submenu_data: MenuBase
) -> SubMenuRead:
data = await self.submenu_repo.create_submenu_item( data = await self.submenu_repo.create_submenu_item(
menu_id, menu_id,
submenu_data, submenu_data,
) )
return data menu = data.__dict__
menu = {k: v for k, v in menu.items() if not k.startswith('_')}
menu['dishes_count'] = len(menu.pop('dishes'))
menu = SubMenuRead(**menu)
return menu
async def read_menu(self, menu_id: UUID, submenu_id: UUID): async def read_menu(self, menu_id: UUID, submenu_id: UUID) -> SubMenuRead | None:
data = await self.submenu_repo.get_submenu_item(menu_id, submenu_id) data = await self.submenu_repo.get_submenu_item(menu_id, submenu_id)
return data if data is None:
return None
menu = data.__dict__
menu = {k: v for k, v in menu.items() if not k.startswith('_')}
menu['dishes_count'] = len(menu.pop('dishes'))
menu = SubMenuRead(**menu)
return menu
async def update_submenu( async def update_submenu(
self, menu_id: UUID, submenu_id: UUID, submenu_data: MenuBase self, menu_id: UUID, submenu_id: UUID, submenu_data: MenuBase
): ) -> SubMenuRead:
data = await self.submenu_repo.update_submenu_item( data = await self.submenu_repo.update_submenu_item(
menu_id, submenu_id, submenu_data menu_id, submenu_id, submenu_data
) )
return data menu = data.__dict__
menu = {k: v for k, v in menu.items() if not k.startswith('_')}
menu['dishes_count'] = len(menu.pop('dishes'))
menu = SubMenuRead(**menu)
return menu
async def del_menu(self, menu_id: UUID, submenu_id: UUID): async def del_menu(self, menu_id: UUID, submenu_id: UUID) -> int:
data = await self.submenu_repo.delete_submenu_item(menu_id, submenu_id) return await self.submenu_repo.delete_submenu_item(menu_id, submenu_id)
return data