Skip to content

Instantly share code, notes, and snippets.

@and3rson
Last active May 23, 2019 18:38
Show Gist options
  • Save and3rson/047c68d0b17f8e8f80a47f958d2c2ff4 to your computer and use it in GitHub Desktop.
Save and3rson/047c68d0b17f8e8f80a47f958d2c2ff4 to your computer and use it in GitHub Desktop.
Domain models with repositories
# 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