Przemek Lewandowski
@haxoza
Data is converted from the form most convenient for entities and use cases to the format most convenient for some external agency such as the Database or the Web.
Adapter
Use case
from typing import List
class Invoice:
def __init__(self, number: str, lines: List[InvoiceLine]):
self.number = number
self.lines = lines
self._total_net_value = None
def validate(self):
pass
@property
def total_net_value(self):
pass
@total_net_value.setter
def total_net_value(self, value):
pass
class InvoiceLine:
def __init__(self, description: str, net_value: int):
self.description = description
self.net_value = net_value
def validate(self):
pass
from typing import Iterable, Dict, Optional, ContextManager
from core.domain.invoice import Invoice
class InvoiceUseCase:
def __init__(self, repository: InvoiceRepository):
self.repository = repository
def get_list(self, filters: Optional[Dict[str, str]]) -> Iterable[Invoice]:
return self.repository.get_list(filters)
def create(self, invoice: Invoice) -> Invoice:
for line in invoice.lines:
line.validate()
invoice.validate()
with self.repository.atomic():
self._validate_invoice_number(invoice)
invoice = self.repository.save(invoice)
return invoice
def _validate_invoice_number(self, invoice: Invoice):
pass
from typing import Iterable, Dict, Optional, ContextManager
from core.domain.invoice import Invoice
class InvoiceRepository:
def get_list(self, filters) -> Iterable[Invoice]:
raise NotImplementedError()
def save(self, invoice: Invoice) -> Invoice:
raise NotImplementedError()
def atomic(self) -> ContextManager:
raise NotImplementedError()
from typing import Iterable, NamedTuple
class InvoiceLineData(NamedTuple):
description: str
net_value: int
class InvoiceData(NamedTuple):
number: str
lines: Iterable[InvoiceLineData]
from typing import Iterable, Dict, Optional, NamedTuple
from core.domain.invoice import Invoice
from core.usecases.invoice import InvoiceUseCase
class InvoiceAdapter:
def __init__(self, repository: InvoiceRepository):
self.usecase = InvoiceUseCase(repository)
def get_list(self, filters: Optional[Dict[str, str]]) -> Iterable[InvoiceData]:
invoices = self.usecase.get_list(filters)
invoices_data = []
for invoice in invoices:
invoices_data.append(self._invoice_to_data(invoice))
return invoices_data
def create(self, invoice_data: InvoiceData) -> InvoiceData:
invoice = self._data_to_invoice(invoice_data)
invoice = self.usecase.create(invoice)
return self._invoice_to_data(invoice)
@classmethod
def _invoice_to_data(cls, invoice: Invoice) -> InvoiceData:
pass
@classmethod
def _data_to_invoice(cls, invoice_data: InvoiceData) -> Invoice:
pass
import json
from flask import request
from flask.ext.restful import Resource, Api
from core.adapters import InvoiceAdapter
from database import InvoiceRepository
class InvoiceResource(Resource):
default_length = 100
def __init__(self, *args, **kwargs):
self.super().__init__(*args, **kwargs)
self.adapter = InvoiceAdapter(InvoiceRepository())
def get(self, number=None):
if number:
return self.get_one(number)
return self.get_list()
def get_one(self, number):
invoice = self.adapter.get_list({'number': number})
return json.dumps(invoice)
def get_list(self):
invoices = self.adapter.get_list()
return json.dumps(invoices)
api = Api()
api.add_resource(InvoiceResource, '/invoices/<int:number>', '/invoices')