Changes:
add Readme per layer move db calls to interface_adapters implement product example add tests add __init__ files for easier to read importsuebung_entities
parent
b3ff7894c6
commit
53523d46b2
|
|
@ -2,3 +2,5 @@
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
|
||||||
|
/env
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
# ENTITIES
|
||||||
|
Entities encapsulate enterprise-wide Critical Business Rules. An entity can be an
|
||||||
|
object with methods, or it can be a set of data structures and functions. It doesn’t
|
||||||
|
matter so long as the entities can be used by many different applications in the
|
||||||
|
enterprise.
|
||||||
|
If you don’t have an enterprise and are writing just a single application, then these
|
||||||
|
entities are the business objects of the application. They encapsulate the most general
|
||||||
|
and high-level rules. They are the least likely to change when something external
|
||||||
|
changes. For example, you would not expect these objects to be affected by a change
|
||||||
|
to page navigation or security. No operational change to any particular application
|
||||||
|
should affect the entity layer.
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
|
||||||
|
module = importlib.import_module(f".{module_name}", __name__)
|
||||||
|
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||||
|
if obj.__module__ == module.__name__:
|
||||||
|
globals()[name] = obj
|
||||||
|
__all__.append(name)
|
||||||
|
|
@ -3,8 +3,8 @@ from typing import List
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
#dependency imports
|
#dependency imports
|
||||||
from entities.cart_item import CartItem
|
from .cart_item import CartItem
|
||||||
from entities.product import Product
|
from .product import Product
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Cart:
|
class Cart:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
# FRAMEWORKS AND DRIVERS
|
||||||
|
The outermost layer of the model in Figure 22.1 is generally composed of
|
||||||
|
frameworks and tools such as the database and the web framework. Generally you
|
||||||
|
don’t write much code in this layer, other than glue code that communicates to the
|
||||||
|
next circle inward.
|
||||||
|
The frameworks and drivers layer is where all the details go. The web is a detail. The
|
||||||
|
database is a detail. We keep these things on the outside where they can do little
|
||||||
|
harm.
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# INTERFACE ADAPTERS
|
||||||
|
The software in the interface adapters layer is a set of adapters that convert data from
|
||||||
|
the format most convenient for the use cases and entities, to the format most
|
||||||
|
convenient for some external agency such as the database or the web. It is this layer,
|
||||||
|
for example, that will wholly contain the MVC architecture of a GUI. The
|
||||||
|
presenters, views, and controllers all belong in the interface adapters layer. The
|
||||||
|
models are likely just data structures that are passed from the controllers to the use
|
||||||
|
cases, and then back from the use cases to the presenters and views.
|
||||||
|
Similarly, data is converted, in this layer, from the form most convenient for entities
|
||||||
|
and use cases, to the form most convenient for whatever persistence framework is
|
||||||
|
being used (i.e., the database). No code inward of this circle should know anything at
|
||||||
|
all about the database. If the database is a SQL database, then all SQL should be
|
||||||
|
restricted to this layer—and in particular to the parts of this layer that have to do with
|
||||||
|
the database.
|
||||||
|
Also in this layer is any other adapter necessary to convert data from some external
|
||||||
|
form, such as an external service, to the internal form used by the use cases and
|
||||||
|
entities.
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
|
||||||
|
module = importlib.import_module(f".{module_name}", __name__)
|
||||||
|
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||||
|
if obj.__module__ == module.__name__:
|
||||||
|
globals()[name] = obj
|
||||||
|
__all__.append(name)
|
||||||
|
|
@ -8,21 +8,16 @@ from fastapi.templating import Jinja2Templates
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
#dependency imports
|
#dependency imports
|
||||||
from use_cases.view_cart import ViewCart
|
from use_cases import ViewCart
|
||||||
from interface_adapters.dtos.view_cart_response import ViewCartResponseDTO, CartItemDTO
|
from interface_adapters.dtos import ViewCartRequestDTO, ViewCartResponseDTO, CartItemDTO
|
||||||
from interface_adapters.dtos.view_cart_request import ViewCartRequestDTO
|
from interface_adapters.repositories import SQLCartRepository
|
||||||
from interface_adapters.repositories.cart_repository import CartRepository
|
|
||||||
|
|
||||||
#from interface_adapters.mocks.cart_db import CartDatabase
|
|
||||||
from framework_driver.db.db_cart import CartDatabase
|
|
||||||
|
|
||||||
# Set up templates
|
# Set up templates
|
||||||
templates = Jinja2Templates(directory="framework_driver/ui/templates")
|
templates = Jinja2Templates(directory="framework_driver/ui/templates")
|
||||||
|
|
||||||
# Initialize components
|
# Initialize components
|
||||||
cart_database = CartDatabase() # Concrete database implementation
|
cart_repository = SQLCartRepository()
|
||||||
cart_repository = CartRepository(cart_database) # Repository depends on gateway
|
view_cart_use_case = ViewCart(cart_repository)
|
||||||
view_cart_use_case = ViewCart(cart_repository) # Use case depends on repository
|
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
@ -35,7 +30,7 @@ async def view_cart(request_dto: ViewCartRequestDTO):
|
||||||
raise HTTPException(status_code=404, detail="Cart not found")
|
raise HTTPException(status_code=404, detail="Cart not found")
|
||||||
|
|
||||||
response_dto = ViewCartResponseDTO(
|
response_dto = ViewCartResponseDTO(
|
||||||
items=[CartItemDTO(product_id=item.product_id, quantity=item.quantity, price=item.price) for item in cart.items],
|
items=[CartItemDTO(product_id=item.product_id, name=item.name, quantity=item.quantity, price=item.price) for item in cart.items],
|
||||||
total_price=sum(item.price * item.quantity for item in cart.items)
|
total_price=sum(item.price * item.quantity for item in cart.items)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
#python imports
|
||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
from fastapi import FastAPI, Request
|
||||||
|
from fastapi.responses import HTMLResponse
|
||||||
|
from fastapi.templating import Jinja2Templates
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
#dependency imports
|
||||||
|
from use_cases import ViewProduct
|
||||||
|
from interface_adapters.dtos import ViewProductRequestDTO, ViewProductResponseDTO, ProductDTO
|
||||||
|
from interface_adapters.repositories import SQLProductRepository
|
||||||
|
|
||||||
|
# Initialize components
|
||||||
|
product_repository = SQLProductRepository()
|
||||||
|
view_product_use_case = ViewProduct(product_repository)
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/view_product", response_model=ViewProductResponseDTO)
|
||||||
|
async def view_product(request_dto: ViewProductRequestDTO):
|
||||||
|
|
||||||
|
product = view_product_use_case.execute(request_dto.product_id)
|
||||||
|
|
||||||
|
if not product:
|
||||||
|
raise HTTPException(status_code=404, detail="Product not found")
|
||||||
|
|
||||||
|
response_dto = ViewProductResponseDTO(
|
||||||
|
product=ProductDTO(id=product.id, name=product.name, description=product.description, price=product.price)
|
||||||
|
)
|
||||||
|
|
||||||
|
return response_dto
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
|
||||||
|
module = importlib.import_module(f".{module_name}", __name__)
|
||||||
|
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||||
|
if obj.__module__ == module.__name__:
|
||||||
|
globals()[name] = obj
|
||||||
|
__all__.append(name)
|
||||||
|
|
@ -4,6 +4,7 @@ from typing import List, Optional
|
||||||
|
|
||||||
class CartItemDTO(BaseModel):
|
class CartItemDTO(BaseModel):
|
||||||
product_id: int
|
product_id: int
|
||||||
|
name: str
|
||||||
quantity: int
|
quantity: int
|
||||||
price: float
|
price: float
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
#python imports
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
class ViewProductRequestDTO(BaseModel):
|
||||||
|
product_id: int
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#python imports
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
class ProductDTO(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
price: float
|
||||||
|
|
||||||
|
class ViewProductResponseDTO(BaseModel):
|
||||||
|
product: ProductDTO
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
|
||||||
|
module = importlib.import_module(f".{module_name}", __name__)
|
||||||
|
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||||
|
if obj.__module__ == module.__name__:
|
||||||
|
globals()[name] = obj
|
||||||
|
__all__.append(name)
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
#python imports
|
|
||||||
from typing import Optional, List
|
|
||||||
|
|
||||||
class CartDatabaseInterface:
|
|
||||||
def fetch_cart_items(self, user_id: int) -> Optional[List[dict]]:
|
|
||||||
"""
|
|
||||||
Abstract method to fetch cart items from the database for a given user ID.
|
|
||||||
"""
|
|
||||||
raise NotImplementedError("fetch_cart_items must be implemented by a subclass")
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
#python imports
|
|
||||||
from typing import Optional, List
|
|
||||||
|
|
||||||
#dependency imports
|
|
||||||
from use_cases.cart_repository_interface import CartRepositoryInterface
|
|
||||||
from interface_adapters.repositories.cart_database_interface import CartDatabaseInterface
|
|
||||||
|
|
||||||
class CartRepository(CartRepositoryInterface):
|
|
||||||
def __init__(self, database_gateway: CartDatabaseInterface):
|
|
||||||
self.database_gateway = database_gateway
|
|
||||||
|
|
||||||
def fetch_cart_by_user_id(self, user_id: int) -> Optional[List[dict]]:
|
|
||||||
return self.database_gateway.fetch_cart_items(user_id)
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import sqlite3
|
#python imports
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
from interface_adapters.repositories.cart_database_interface import CartDatabaseInterface
|
import sqlite3
|
||||||
|
|
||||||
class CartDatabase(CartDatabaseInterface):
|
#dependency imports
|
||||||
|
from use_cases import ICartRepository
|
||||||
|
|
||||||
|
class SQLCartRepository(ICartRepository):
|
||||||
def __init__(self, db_file="framework_driver/db/shop.db"):
|
def __init__(self, db_file="framework_driver/db/shop.db"):
|
||||||
"""Initialize the CartDatabase with a connection to the SQLite database."""
|
"""Initialize the CartDatabase with a connection to the SQLite database."""
|
||||||
self.conn = sqlite3.connect(db_file)
|
self.conn = sqlite3.connect(db_file)
|
||||||
|
|
@ -18,7 +21,7 @@ class CartDatabase(CartDatabaseInterface):
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
def fetch_cart_items(self, user_id: int) -> Optional[List[dict]]:
|
def get_cart_by_user_id(self, user_id: int) -> Optional[List[dict]]:
|
||||||
"""Fetch cart items from the database for a given user ID."""
|
"""Fetch cart items from the database for a given user ID."""
|
||||||
sql = "SELECT product_id, name, quantity, price FROM cart WHERE user_id = ?"
|
sql = "SELECT product_id, name, quantity, price FROM cart WHERE user_id = ?"
|
||||||
try:
|
try:
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
|
#python imports
|
||||||
|
from typing import Optional, List
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
class ProductDatabase:
|
#dependency imports
|
||||||
def __init__(self, db_file):
|
from use_cases import IProductRepository
|
||||||
|
|
||||||
|
class SQLProductRepository(IProductRepository):
|
||||||
|
def __init__(self, db_file="framework_driver/db/shop.db"):
|
||||||
"""Initialize the ProductDatabase with a connection to the SQLite database."""
|
"""Initialize the ProductDatabase with a connection to the SQLite database."""
|
||||||
self.conn = sqlite3.connect(db_file)
|
self.conn = sqlite3.connect(db_file)
|
||||||
|
|
||||||
|
|
@ -22,7 +27,8 @@ class ProductDatabase:
|
||||||
try:
|
try:
|
||||||
c = self.conn.cursor()
|
c = self.conn.cursor()
|
||||||
c.execute(sql, (product_id,))
|
c.execute(sql, (product_id,))
|
||||||
return c.fetchone()
|
r = c.fetchone()
|
||||||
|
return {'id':r[0], 'name':str(r[1]), 'description':str(r[2]), 'price':r[3]}
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
print(e)
|
print(e)
|
||||||
return None
|
return None
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
|
#python imports
|
||||||
|
from typing import Optional, List
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
class UserDatabase:
|
#dependency imports
|
||||||
def __init__(self, db_file):
|
from use_cases import IUserRepository
|
||||||
|
|
||||||
|
class SQLUserRepository(IUserRepository):
|
||||||
|
def __init__(self, db_file="framework_driver/db/shop.db"):
|
||||||
"""Initialize the UserDatabase with a connection to the SQLite database."""
|
"""Initialize the UserDatabase with a connection to the SQLite database."""
|
||||||
self.conn = sqlite3.connect(db_file)
|
self.conn = sqlite3.connect(db_file)
|
||||||
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from interface_adapters.controllers.cart_controller import router as cart_router
|
from interface_adapters.controllers.cart_controller import router as cart_router
|
||||||
|
from interface_adapters.controllers.product_controller import router as product_router
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
|
|
@ -14,6 +15,7 @@ import os
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
app.include_router(cart_router)
|
app.include_router(cart_router)
|
||||||
|
app.include_router(product_router)
|
||||||
|
|
||||||
# Allow CORS for all origins (for simplicity)
|
# Allow CORS for all origins (for simplicity)
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Tests
|
||||||
|
To run tests: python -m unittest discover
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
|
||||||
|
module = importlib.import_module(f".{module_name}", __name__)
|
||||||
|
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||||
|
if obj.__module__ == module.__name__:
|
||||||
|
globals()[name] = obj
|
||||||
|
__all__.append(name)
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
|
||||||
#dependency imports
|
#dependency imports
|
||||||
from interface_adapters.repositories.cart_database_interface import CartDatabaseInterface
|
from use_cases import ICartRepository
|
||||||
|
|
||||||
class CartDatabase(CartDatabaseInterface):
|
class CartDatabase(ICartRepository):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Mock database setup
|
# Mock database setup
|
||||||
self.mock_db = {
|
self.mock_db = {
|
||||||
|
|
@ -17,5 +17,5 @@ class CartDatabase(CartDatabaseInterface):
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
def fetch_cart_items(self, user_id: int) -> Optional[List[dict]]:
|
def get_cart_by_user_id(self, user_id: int) -> Optional[List[dict]]:
|
||||||
return self.mock_db.get(user_id)
|
return self.mock_db.get(user_id)
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
#python imports
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
|
#dependency imports
|
||||||
|
from use_cases import IProductRepository
|
||||||
|
|
||||||
|
class ProductDatabase(IProductRepository):
|
||||||
|
def __init__(self):
|
||||||
|
# Mock database setup
|
||||||
|
self.mock_db = {
|
||||||
|
1: {"id": 1, "name": "Apple", "description": "gsdg", "price": 0.5},
|
||||||
|
2: {"id": 2, "name": "Bread", "description": "sfg", "price": 2.0},
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_product_by_id(self, product_id: int) -> Optional[List[dict]]:
|
||||||
|
return self.mock_db.get(product_id)
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
from use_cases import ViewCart
|
||||||
|
from tests.mocks import CartDatabase
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class TestViewCart(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.cart_database = CartDatabase()
|
||||||
|
self.view_cart_use_case = ViewCart(self.cart_database)
|
||||||
|
|
||||||
|
def test_view_cart_valid_id(self):
|
||||||
|
result = self.view_cart_use_case.execute(1)
|
||||||
|
self.assertIsNotNone(result)
|
||||||
|
#self.assertEqual(result['id'], 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
from use_cases import ViewProduct
|
||||||
|
from tests.mocks import ProductDatabase
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class TestViewProduct(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.product_database = ProductDatabase()
|
||||||
|
self.view_product_use_case = ViewProduct(self.product_database)
|
||||||
|
|
||||||
|
def test_view_product_valid_id(self):
|
||||||
|
result = self.view_product_use_case.execute(1)
|
||||||
|
self.assertIsNotNone(result)
|
||||||
|
#self.assertEqual(result['id'], 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
# USE CASES
|
||||||
|
The software in the use cases layer contains application-specific business rules. It
|
||||||
|
encapsulates and implements all of the use cases of the system. These use cases
|
||||||
|
orchestrate the flow of data to and from the entities, and direct those entities to use
|
||||||
|
their Critical Business Rules to achieve the goals of the use case.
|
||||||
|
We do not expect changes in this layer to affect the entities. We also do not expect
|
||||||
|
this layer to be affected by changes to externalities such as the database, the UI, or
|
||||||
|
any of the common frameworks. The use cases layer is isolated from such concerns.
|
||||||
|
We do, however, expect that changes to the operation of the application will affect
|
||||||
|
the use cases and, therefore, the software in this layer. If the details of a use case
|
||||||
|
change, then some code in this layer will certainly be affected.
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
|
||||||
|
module = importlib.import_module(f".{module_name}", __name__)
|
||||||
|
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||||
|
if obj.__module__ == module.__name__:
|
||||||
|
globals()[name] = obj
|
||||||
|
__all__.append(name)
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
|
class ICartRepository:
|
||||||
|
def get_cart_by_user_id(self, user_id: int) -> Optional[List[dict]]:
|
||||||
|
"""
|
||||||
|
Abstract method to fetch cart data by user ID.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("get_cart_by_user_id must be implemented by a subclass")
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
from typing import Optional, List
|
|
||||||
|
|
||||||
class CartRepositoryInterface:
|
|
||||||
def fetch_cart_by_user_id(self, user_id: int) -> Optional[List[dict]]:
|
|
||||||
"""
|
|
||||||
Abstract method to fetch cart data by user ID.
|
|
||||||
"""
|
|
||||||
raise NotImplementedError("fetch_cart_by_user_id must be implemented by a subclass")
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
|
class IProductRepository:
|
||||||
|
def get_product_by_id(self, product_id: int):
|
||||||
|
"""
|
||||||
|
Abstract method to fetch product data by user ID.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("get_product_by_id must be implemented by a subclass")
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
|
class IUserRepository:
|
||||||
|
def get_user_by_id(self, user_id: int):
|
||||||
|
"""
|
||||||
|
Abstract method to fetch user data by user ID.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("get_user_by_id must be implemented by a subclass")
|
||||||
|
|
@ -2,18 +2,18 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
#dependency imports
|
#dependency imports
|
||||||
from entities.cart import Cart, CartItem
|
from entities import Cart, CartItem
|
||||||
from use_cases.cart_repository_interface import CartRepositoryInterface
|
from .cart_repository import ICartRepository
|
||||||
|
|
||||||
class ViewCart:
|
class ViewCart:
|
||||||
def __init__(self, cart_repository: CartRepositoryInterface):
|
def __init__(self, cart_repository: ICartRepository):
|
||||||
self.cart_repository = cart_repository
|
self.cart_repository = cart_repository
|
||||||
|
|
||||||
def execute(self, user_id: int) -> Optional[Cart]:
|
def execute(self, user_id: int) -> Optional[Cart]:
|
||||||
"""
|
"""
|
||||||
Fetches the cart data from the repository, converts it to Cart entity.
|
Fetches the cart data from the repository, converts it to Cart entity.
|
||||||
"""
|
"""
|
||||||
cart_data = self.cart_repository.fetch_cart_by_user_id(user_id)
|
cart_data = self.cart_repository.get_cart_by_user_id(user_id)
|
||||||
if not cart_data:
|
if not cart_data:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#python imports
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
#dependency imports
|
||||||
|
from entities import Product
|
||||||
|
from .product_repository import IProductRepository
|
||||||
|
|
||||||
|
class ViewProduct:
|
||||||
|
def __init__(self, product_repository: IProductRepository):
|
||||||
|
self.product_repository = product_repository
|
||||||
|
|
||||||
|
def execute(self, product_id: int) -> Optional[Product]:
|
||||||
|
"""
|
||||||
|
Fetches the product data from the repository, converts it to Product entity.
|
||||||
|
"""
|
||||||
|
product_data = self.product_repository.get_product_by_id(product_id)
|
||||||
|
if not product_data:
|
||||||
|
return None
|
||||||
|
return Product(**product_data)
|
||||||
Loading…
Reference in New Issue