Last active
May 23, 2019 18:38
-
-
Save and3rson/047c68d0b17f8e8f80a47f958d2c2ff4 to your computer and use it in GitHub Desktop.
Domain models with repositories
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# pylint: disable=too-few-public-methods,missing-docstring,no-self-use | |
# pylint: disable=invalid-name,fixme,unused-variable | |
from typing import List | |
from unittest.mock import Mock | |
# Simulate Django models | |
models = Mock() | |
models.Loan.objects.get.return_value = Mock() | |
models.Loan.objects.filter().__iter__ = Mock(side_effect=lambda: iter([Mock(), Mock()])) | |
models.Document.objects.get.return_value = Mock() | |
models.Document.objects.filter().__iter__ = Mock(side_effect=lambda: iter([Mock()])) | |
models.Page.objects.filter().__iter__ = Mock(side_effect=lambda: iter([Mock(), Mock(), Mock()])) | |
""" | |
NOTES: | |
0. Domain model does not focus on persistence, repositories do | |
1. Each domain model should have at least one repository | |
2. There may be repositories that span across multiple domain models | |
""" | |
class DomainModel: | |
def __init__(self, model): | |
self.model = model # Model can be Django model, some object, list/dict/tuple etc. | |
class LoansRepository: | |
""" | |
Repository of all loans. | |
You can get one loan. You cannot get all of them. | |
""" | |
def get_one(self, loan_pk) -> 'Loan': | |
return Loan(models.Loan.objects.get(pk=loan_pk)) | |
class AccountRepository: | |
""" | |
Repository of all accounts. | |
You can get one account. Loan account is an entity purely within the bounded context of loans. | |
""" | |
def get_one(self, account_pk) -> 'Account': | |
return Account(models.Account.objects.get(pk=account_pk)) | |
class Account(DomainModel): | |
""" | |
Single account within the bounded context of loans. | |
""" | |
@property | |
def loans(self) -> 'AccountLoansRepository': | |
return AccountLoansRepository(self.model.pk) | |
class AccountLoansRepository: | |
""" | |
Repository of loans that belong to a specific account. | |
You can get all or create one that will be linked to context account. | |
""" | |
def __init__(self, account_pk): | |
self.account_pk = account_pk | |
def get_all(self) -> List['Loan']: | |
return list(map(Loan, models.Loan.objects.filter(parties__pk=self.account_pk))) | |
def create_loan(self, **kwargs): | |
# TODO: Implement this | |
# TODO: **kwargs or document domain model instance? | |
pass | |
class Loan(DomainModel): | |
""" | |
Single loan. | |
""" | |
@property | |
def documents(self) -> 'LoanDocumentsRepository': | |
return LoanDocumentsRepository(self.model) | |
class LoanDocumentsRepository: | |
""" | |
Repository of all documents within a loan. | |
You can get all of them or create ("upload") one. | |
""" | |
def __init__(self, loan): | |
self.loan = loan | |
def get_all(self) -> List['Document']: | |
return list(map(Document, models.Document.objects.filter(loan_pk=self.loan.pk))) | |
def add_document(self, **kwargs): | |
# TODO: Implement this | |
# TODO: **kwargs or document domain model instance? | |
pass | |
class DocumentsRepository: | |
""" | |
Repository of all documents. | |
You can get one document. You cannot get all of them. | |
""" | |
def get_one(self, pk) -> 'Document': | |
return Document(models.Document.objects.get(pk=pk)) | |
class Document(DomainModel): | |
""" | |
Single loan document. | |
""" | |
@property | |
def pages(self) -> 'DocumentPagesRepository': | |
return DocumentPagesRepository(self.model) | |
def parse(self, **kwargs): | |
# TODO: Immplement this | |
pass | |
class PagesRepository: | |
""" | |
Repository of all pages. | |
You can get one page. You cannot get all of them. | |
""" | |
def get_one(self, pk) -> 'Page': | |
# We could also move this to DocumentPagesRepository. | |
return Page(models.Page.objects.get(pk=pk)) | |
class DocumentPagesRepository: | |
""" | |
Repository of all pages within a document. | |
You can get all pages. | |
""" | |
def __init__(self, document): | |
self.document = document | |
def get_all(self) -> List['Page']: | |
return list(map(Page, models.Page.objects.filter(document_pk=self.document.pk))) | |
class Page(DomainModel): | |
""" | |
Single document page. | |
""" | |
# Usage example | |
def example(): | |
# Get all loans of account | |
black_mesa = AccountRepository().get_one('0' * 32) | |
print('Black mesa has', len(black_mesa.loans.get_all()), 'loans') | |
# Get all documents within a specific loan | |
some_loan = LoansRepository().get_one('0' * 32) | |
print('Loan has', len(some_loan.documents.get_all()), 'documents') | |
# Get first page of some document | |
document = DocumentsRepository().get_one('0' * 32) | |
print('Document has', len(document.pages.get_all()), 'pages') | |
page = document.pages.get_all()[0] | |
if __name__ == '__main__': | |
example() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment