UPDATE refactor project structure
parent
4ba1a31dee
commit
cbcebdffb5
|
@ -3,7 +3,7 @@
|
|||
[alembic]
|
||||
# path to migration scripts
|
||||
# Use forward slashes (/) also on windows to provide an os agnostic path
|
||||
script_location = ./src/fastfood_two/storage/pg_storage/migrations
|
||||
script_location = ./src/fastfood_two/infrastructure/pg_storage/migrations
|
||||
|
||||
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
|
||||
# Uncomment the line below if you want the files to be prepended with date and time
|
||||
|
|
|
@ -283,23 +283,23 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.112.0"
|
||||
version = "0.112.2"
|
||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "fastapi-0.112.0-py3-none-any.whl", hash = "sha256:3487ded9778006a45834b8c816ec4a48d522e2631ca9e75ec5a774f1b052f821"},
|
||||
{file = "fastapi-0.112.0.tar.gz", hash = "sha256:d262bc56b7d101d1f4e8fc0ad2ac75bb9935fec504d2b7117686cec50710cf05"},
|
||||
{file = "fastapi-0.112.2-py3-none-any.whl", hash = "sha256:db84b470bd0e2b1075942231e90e3577e12a903c4dc8696f0d206a7904a7af1c"},
|
||||
{file = "fastapi-0.112.2.tar.gz", hash = "sha256:3d4729c038414d5193840706907a41839d839523da6ed0c2811f1168cac1798c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
|
||||
starlette = ">=0.37.2,<0.38.0"
|
||||
starlette = ">=0.37.2,<0.39.0"
|
||||
typing-extensions = ">=4.8.0"
|
||||
|
||||
[package.extras]
|
||||
all = ["email_validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
|
||||
standard = ["email_validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"]
|
||||
all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
|
||||
standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "filelock"
|
||||
|
@ -415,13 +415,13 @@ license = ["ukkonen"]
|
|||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.7"
|
||||
version = "3.8"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
|
||||
{file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
|
||||
{file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"},
|
||||
{file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1031,13 +1031,13 @@ sqlcipher = ["sqlcipher3_binary"]
|
|||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.37.2"
|
||||
version = "0.38.2"
|
||||
description = "The little ASGI library that shines."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"},
|
||||
{file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"},
|
||||
{file = "starlette-0.38.2-py3-none-any.whl", hash = "sha256:4ec6a59df6bbafdab5f567754481657f7ed90dc9d69b0c9ff017907dd54faeff"},
|
||||
{file = "starlette-0.38.2.tar.gz", hash = "sha256:c7c0441065252160993a1a37cf2a73bb64d271b17303e0b0c1eb7191cfb12d75"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
|
@ -3,7 +3,7 @@ import uvicorn
|
|||
|
||||
def main():
|
||||
uvicorn.run(
|
||||
"fastfood_two.app.main:app_factory",
|
||||
"fastfood_two.presentation.fastapi_backend.main:app_factory",
|
||||
host="0.0.0.0",
|
||||
port=8000,
|
||||
factory=True,
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
import logging
|
||||
|
||||
from fastapi import FastAPI
|
||||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
||||
|
||||
from fastfood_two.app.depends.config import get_settings
|
||||
from fastfood_two.app.depends.session import (
|
||||
create_engine,
|
||||
create_session_maker,
|
||||
get_session,
|
||||
)
|
||||
from fastfood_two.common.logger import configure_logger
|
||||
from fastfood_two.config import Config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
configure_logger(level=logging.INFO)
|
||||
|
||||
|
||||
def init_dependencies(app: FastAPI) -> None:
|
||||
"""Initialize FastAPI dependencies.
|
||||
|
||||
:param app: FastAPI application
|
||||
:type app: FastAPI
|
||||
"""
|
||||
|
||||
app.dependency_overrides[Config] = get_settings
|
||||
|
||||
app.dependency_overrides[AsyncEngine] = create_engine
|
||||
app.dependency_overrides[async_sessionmaker[AsyncSession]] = create_session_maker
|
||||
app.dependency_overrides[AsyncSession] = get_session
|
||||
|
||||
logger.info("Dependencies initialized")
|
|
@ -1,6 +1,6 @@
|
|||
from dataclasses import dataclass
|
||||
|
||||
from fastfood_two.storage.pg_storage.config import PostgresConfig
|
||||
from fastfood_two.infrastructure.pg_storage.config import PostgresConfig
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
|
@ -0,0 +1,8 @@
|
|||
from typing import Protocol
|
||||
|
||||
from fastfood_two.application.contracts.responses import MenuResponse
|
||||
|
||||
|
||||
class MenuGateway(Protocol):
|
||||
async def get_all_menus(self) -> list[MenuResponse]:
|
||||
raise NotImplementedError
|
|
@ -5,5 +5,5 @@ from uuid import UUID
|
|||
@dataclass(frozen=True)
|
||||
class MenuResponse:
|
||||
id: UUID
|
||||
name: str
|
||||
title: str
|
||||
description: str
|
|
@ -0,0 +1,12 @@
|
|||
from fastfood_two.application.abstractions.interactor import Interactor
|
||||
from fastfood_two.application.contracts.gateways import MenuGateway
|
||||
from fastfood_two.application.contracts.responses import MenuResponse
|
||||
|
||||
|
||||
class GetAllMenus(Interactor[None, list[MenuResponse]]):
|
||||
def __init__(self, gateway: MenuGateway) -> None:
|
||||
self._menu_gateway = gateway
|
||||
|
||||
async def __call__(self, request=None) -> list[MenuResponse]:
|
||||
menus = await self._menu_gateway.get_all_menus()
|
||||
return menus
|
|
@ -0,0 +1,15 @@
|
|||
from sqlalchemy import text
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood_two.application.contracts.responses import MenuResponse
|
||||
from fastfood_two.infrastructure.pg_storage.mappers.menu_mapper import entity_to_dto
|
||||
|
||||
|
||||
class MenuGatewayImpl:
|
||||
def __init__(self, session: AsyncSession) -> None:
|
||||
self._session = session
|
||||
|
||||
async def get_all_menus(self) -> list[MenuResponse]:
|
||||
query = text("SELECT * FROM menu;")
|
||||
menus = await self._session.execute(query)
|
||||
return [entity_to_dto(menu) for menu in menus.scalars().all()]
|
|
@ -0,0 +1,14 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from fastfood_two.application.contracts.responses import MenuResponse
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from fastfood_two.infrastructure.pg_storage.models import Menu
|
||||
|
||||
|
||||
def entity_to_dto(menu: "Menu") -> MenuResponse:
|
||||
return MenuResponse(
|
||||
id=menu.id,
|
||||
title=menu.title,
|
||||
description=menu.description or "",
|
||||
)
|
|
@ -3,12 +3,15 @@ from logging.config import fileConfig
|
|||
from alembic import context
|
||||
from sqlalchemy import engine_from_config, pool
|
||||
|
||||
from fastfood_two.app.depends.config import get_settings
|
||||
from fastfood_two.storage.pg_storage.models import Base
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
|
||||
config.set_main_option("sqlalchemy.url", f"{get_settings().db.url}?async_fallback=True")
|
||||
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
if config.config_file_name is not None:
|
|
@ -0,0 +1,49 @@
|
|||
"""init
|
||||
|
||||
Revision ID: b108cf5ea628
|
||||
Revises:
|
||||
Create Date: 2024-08-31 06:45:06.377821
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "b108cf5ea628"
|
||||
down_revision: Union[str, None] = None
|
||||
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.create_table(
|
||||
"menu",
|
||||
sa.Column("id", sa.UUID(), nullable=False),
|
||||
sa.Column("title", sa.String(), nullable=False),
|
||||
sa.Column("description", sa.String(), nullable=True),
|
||||
sa.Column("parent", sa.UUID(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["parent"], ["menu.id"], ondelete="CASCADE"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"dish",
|
||||
sa.Column("id", sa.UUID(), nullable=False),
|
||||
sa.Column("title", sa.String(), nullable=False),
|
||||
sa.Column("description", sa.String(), nullable=True),
|
||||
sa.Column("price", sa.Float(), nullable=False),
|
||||
sa.Column("parent_submenu", sa.UUID(), nullable=False),
|
||||
sa.ForeignKeyConstraint(["parent_submenu"], ["menu.id"], ondelete="CASCADE"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table("dish")
|
||||
op.drop_table("menu")
|
||||
# ### end Alembic commands ###
|
|
@ -1,14 +1,10 @@
|
|||
from .base import Base
|
||||
from .menu_model import Menu
|
||||
from .submenu_model import SubMenu
|
||||
from .dish_model import Dish
|
||||
from .common_attrs import uuidpk, str_25
|
||||
|
||||
__all__ = [
|
||||
"Base",
|
||||
"Menu",
|
||||
"SubMenu",
|
||||
"Dish",
|
||||
"uuidpk",
|
||||
"str_25",
|
||||
]
|
|
@ -3,7 +3,8 @@ import uuid
|
|||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from . import Base, str_25, uuidpk
|
||||
from .base import Base
|
||||
from .common_attrs import str_25, uuidpk
|
||||
|
||||
|
||||
class Dish(Base):
|
||||
|
@ -14,4 +15,4 @@ class Dish(Base):
|
|||
description: Mapped[str | None]
|
||||
price: Mapped[float]
|
||||
|
||||
parent_submenu: Mapped[uuid.UUID] = mapped_column(ForeignKey("submenu.id", ondelete="CASCADE"))
|
||||
parent_submenu: Mapped[uuid.UUID] = mapped_column(ForeignKey("menu.id", ondelete="CASCADE"))
|
|
@ -0,0 +1,22 @@
|
|||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from .base import Base
|
||||
from .common_attrs import str_25, uuidpk
|
||||
|
||||
|
||||
class Menu(Base):
|
||||
__tablename__ = "menu"
|
||||
|
||||
id: Mapped[uuidpk]
|
||||
title: Mapped[str_25]
|
||||
description: Mapped[str | None]
|
||||
|
||||
parent: Mapped[uuidpk | None] = mapped_column(ForeignKey("menu.id", ondelete="CASCADE"), nullable=True)
|
||||
|
||||
submenus: Mapped[list["Menu"]] = relationship(
|
||||
"Menu",
|
||||
backref="menu",
|
||||
lazy="selectin",
|
||||
cascade="all, delete",
|
||||
)
|
|
@ -0,0 +1,42 @@
|
|||
import logging
|
||||
|
||||
from fastapi import FastAPI
|
||||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
||||
|
||||
from fastfood_two.application.common.logger import configure_logger
|
||||
from fastfood_two.application.config import Config
|
||||
from fastfood_two.application.contracts.gateways import MenuGateway
|
||||
from fastfood_two.application.usecases.menu.get_all_menus import GetAllMenus
|
||||
from fastfood_two.presentation.fastapi_backend.depends.config import get_settings
|
||||
from fastfood_two.presentation.fastapi_backend.depends.gateways import get_menu_gateway
|
||||
from fastfood_two.presentation.fastapi_backend.depends.session import (
|
||||
create_engine,
|
||||
create_session_maker,
|
||||
get_session,
|
||||
)
|
||||
from fastfood_two.presentation.fastapi_backend.depends.usecases import (
|
||||
get_all_menus_usecase,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
configure_logger(level=logging.INFO)
|
||||
|
||||
|
||||
def init_dependencies(app: FastAPI) -> None:
|
||||
"""Initialize FastAPI dependencies.
|
||||
|
||||
:param app: FastAPI application
|
||||
:type app: FastAPI
|
||||
"""
|
||||
|
||||
app.dependency_overrides[Config] = get_settings
|
||||
|
||||
app.dependency_overrides[AsyncEngine] = create_engine
|
||||
app.dependency_overrides[async_sessionmaker[AsyncSession]] = create_session_maker
|
||||
app.dependency_overrides[AsyncSession] = get_session
|
||||
|
||||
app.dependency_overrides[MenuGateway] = get_menu_gateway
|
||||
|
||||
app.dependency_overrides[GetAllMenus] = get_all_menus_usecase
|
||||
|
||||
logger.info("Dependencies initialized")
|
|
@ -1,8 +1,8 @@
|
|||
import os
|
||||
from functools import lru_cache
|
||||
|
||||
from fastfood_two.config import Config
|
||||
from fastfood_two.storage.pg_storage.config import PostgresConfig
|
||||
from fastfood_two.application.config import Config
|
||||
from fastfood_two.infrastructure.pg_storage.config import PostgresConfig
|
||||
|
||||
|
||||
@lru_cache()
|
|
@ -0,0 +1,12 @@
|
|||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood_two.application.contracts.gateways import MenuGateway
|
||||
from fastfood_two.infrastructure.menu_gateway import MenuGatewayImpl
|
||||
from fastfood_two.presentation.fastapi_backend.depends.stub import Stub
|
||||
|
||||
|
||||
def get_menu_gateway(session: Annotated[AsyncSession, Depends(Stub(AsyncSession))]) -> MenuGateway:
|
||||
return MenuGatewayImpl(session=session)
|
|
@ -10,8 +10,8 @@ from sqlalchemy.ext.asyncio import (
|
|||
create_async_engine,
|
||||
)
|
||||
|
||||
from fastfood_two.common.stub import Stub
|
||||
from fastfood_two.config import Config
|
||||
from fastfood_two.application.config import Config
|
||||
from fastfood_two.presentation.fastapi_backend.depends.stub import Stub
|
||||
|
||||
|
||||
@lru_cache()
|
|
@ -0,0 +1,11 @@
|
|||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
|
||||
from fastfood_two.application.contracts.gateways import MenuGateway
|
||||
from fastfood_two.application.usecases.menu.get_all_menus import GetAllMenus
|
||||
from fastfood_two.presentation.fastapi_backend.depends.stub import Stub
|
||||
|
||||
|
||||
def get_all_menus_usecase(gateway: Annotated[MenuGateway, Depends(Stub(MenuGateway))]) -> GetAllMenus:
|
||||
return GetAllMenus(gateway=gateway)
|
|
@ -4,10 +4,10 @@ from typing import AsyncGenerator
|
|||
|
||||
from fastapi import FastAPI
|
||||
|
||||
from fastfood_two.app.dependencies import init_dependencies
|
||||
from fastfood_two.app.error_handlers import init_errorhandlers
|
||||
from fastfood_two.app.routers import init_routers
|
||||
from fastfood_two.common.logger import configure_logger
|
||||
from fastfood_two.application.common.logger import configure_logger
|
||||
from fastfood_two.presentation.fastapi_backend.dependencies import init_dependencies
|
||||
from fastfood_two.presentation.fastapi_backend.error_handlers import init_errorhandlers
|
||||
from fastfood_two.presentation.fastapi_backend.routers_init import init_routers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
configure_logger(level=logging.INFO)
|
|
@ -0,0 +1,21 @@
|
|||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from fastfood_two.application.contracts.responses import MenuResponse
|
||||
from fastfood_two.application.usecases.menu.get_all_menus import GetAllMenus
|
||||
from fastfood_two.presentation.fastapi_backend.depends.stub import Stub
|
||||
|
||||
router = APIRouter(prefix="/menu", tags=["Menu"])
|
||||
|
||||
|
||||
@router.get("/", response_model=list[MenuResponse])
|
||||
async def get_all_menus(
|
||||
usecase: Annotated[GetAllMenus, Depends(Stub(GetAllMenus))],
|
||||
) -> list[MenuResponse]:
|
||||
"""Get all menus.
|
||||
|
||||
Endpoint returns list of all available food menus
|
||||
"""
|
||||
menus = await usecase()
|
||||
return menus
|
|
@ -1,9 +1,13 @@
|
|||
from fastapi import APIRouter, FastAPI
|
||||
|
||||
from fastfood_two.routers.dish import router as dish_router
|
||||
from fastfood_two.routers.menu import router as menu_router
|
||||
from fastfood_two.routers.submenu import router as submenu_router
|
||||
from fastfood_two.routers.summary import router as summary_router
|
||||
from fastfood_two.presentation.fastapi_backend.routers.dish import router as dish_router
|
||||
from fastfood_two.presentation.fastapi_backend.routers.menu import router as menu_router
|
||||
from fastfood_two.presentation.fastapi_backend.routers.submenu import (
|
||||
router as submenu_router,
|
||||
)
|
||||
from fastfood_two.presentation.fastapi_backend.routers.summary import (
|
||||
router as summary_router,
|
||||
)
|
||||
|
||||
|
||||
def init_routers(app: FastAPI) -> None:
|
|
@ -1,10 +0,0 @@
|
|||
from fastapi import APIRouter
|
||||
|
||||
from fastfood_two.contracts.responses import MenuResponse
|
||||
|
||||
router = APIRouter(prefix="/menu", tags=["Menu"])
|
||||
|
||||
|
||||
@router.get("/", response_model=list[MenuResponse])
|
||||
async def get_all_menus() -> list[MenuResponse]:
|
||||
return []
|
|
@ -1,18 +0,0 @@
|
|||
from sqlalchemy.orm import Mapped, relationship
|
||||
|
||||
from . import Base, str_25, uuidpk
|
||||
|
||||
|
||||
class Menu(Base):
|
||||
__tablename__ = "menu"
|
||||
|
||||
id: Mapped[uuidpk]
|
||||
title: Mapped[str_25]
|
||||
description: Mapped[str | None]
|
||||
|
||||
submenus: Mapped[list["SubMenu"]] = relationship(
|
||||
"SubMenu",
|
||||
backref="menu",
|
||||
lazy="selectin",
|
||||
cascade="all, delete",
|
||||
)
|
|
@ -1,22 +0,0 @@
|
|||
import uuid
|
||||
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.orm.properties import ForeignKey
|
||||
|
||||
from . import Base, str_25, uuidpk
|
||||
|
||||
|
||||
class SubMenu(Base):
|
||||
__tablename__ = "submenu"
|
||||
|
||||
id: Mapped[uuidpk]
|
||||
title: Mapped[str_25]
|
||||
description: Mapped[str | None]
|
||||
|
||||
parent_menu: Mapped[uuid.UUID] = mapped_column(ForeignKey("menu.id", ondelete="CASCADE"))
|
||||
dishes: Mapped[list["Dish"]] = relationship(
|
||||
"Dish",
|
||||
backref="submenu",
|
||||
lazy="selectin",
|
||||
cascade="all, delete",
|
||||
)
|
|
@ -1,8 +0,0 @@
|
|||
from fastfood_two.common.interactor import Interactor
|
||||
from fastfood_two.contracts.menu_contracts import MenusResponse
|
||||
|
||||
|
||||
class GetAllMenus(Interactor[None, MenusResponse]):
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
async def __call__(self, request=None) -> MenusResponse: ...
|
Loading…
Reference in New Issue