Skip to main content

Provides basic DDD primitives

Project description

Classic Domain

Основывается на книге Эрика Эванса "Domain Driven Design: tackling complexity in the heart of software".

Предоставляет базовый примитив для описания языка предметной области - Criteria (Критерий).

Критерий нужен для описания выборки объектов. Есть два пути использования - через определение класса, и через декоратор.

Установка

pip install classic-domain

Критерии-классы

Представим себе, что у нас класс, олицетворяющий понятие из предметной области - задачу:

Также, представим себе, что в предметной области задача называется открытой, если нет времени завершения и просроченной, если больше работа не завершена больше какого-то количества дней.

Также представим, что нам необходимо получать из некоторого хранилища задачи, соответствующие этим критериям.

Задачу можно описать обычным датаклассом, а состояния задач - критериями. У критериев можно определить метод is_satisfied_by, которые будут определять, подходит ли объект под этот критерий или нет:

from datetime import datetime
from dataclasses import dataclass
from typing import Optional

from classic.domain import Criteria


@dataclass
class Task:
    created_at: datetime
    finished_at: Optional[datetime] = None


@dataclass
class Open(Criteria[Task]):
    """Критерий для открытых задач"""

    def is_satisfied_by(self, candidate: Task) -> bool:
        return candidate.finished_at is None

    
@dataclass
class Obsolete(Criteria[Task]):
    """Критерий для просроченных задач"""
    days_to_work: int

    def is_satisfied_by(self, candidate: Task) -> bool:
        return (
            candidate.finished_at is not None and
            (candidate.created_at - candidate.finished_at).days > self.days_to_work
        )

Затем описанные критерии можно использовать в разных сценариях.

Прямое использование

from datetime import datetime

some_task = Task(created_at=datetime(2025, 1, 1))
is_open = Open()

is_open.is_satisfied_by(some_task)
# True

Булева алгебра

Критерии можно связать логическими условиями:

from datetime import datetime

some_task = Task(created_at=datetime(2025, 1, 1))
some_crit = Open() | Obsolete(3)

some_crit.is_satisfied_by(some_task)
# True

Фильтрация

У критерия метод __call__ определен как алиас для is_satisfied_by. Это придает лаконичности при использовании критерия для фильтрации списка:

from datetime import datetime

tasks = [
    Task(created_at=datetime(2025, 1, 1)),
    Task(created_at=datetime(2025, 1, 1),
         finished_at=datetime(2025, 1, 5)),
    Task(created_at=datetime(2025, 1, 1),
         finished_at=datetime(2025, 1, 2)),
] 
some_crit = Open() | Obsolete(3)

filtered_tasks = filter(some_crit, tasks)
# True

Критерии-методы

Критерии можно определить как методы у класса (например, у самой сущности), используя декоратор criteria:

from datetime import datetime
from dataclasses import dataclass
from typing import Optional

from classic.domain import criteria


@dataclass
class Task:
    created_at: datetime
    finished_at: Optional[datetime] = None
    
    @criteria
    def open(self) -> bool:
        return self.finished_at is None
    
    @criteria
    def obsolete(self, days_to_work: int) -> bool:
        return (
            self.finished_at is not None and
            (self.created_at - self.finished_at).days > days_to_work
        )

У таких критериев есть две группы сценариев использования, использование на инстансах, и использование на классах.

Далее будут примеры с инстансами, аналогичные примерам выше.

Прямое использование

from datetime import datetime

some_task = Task(created_at=datetime(2025, 1, 1))

some_task.open()
# True

Булева алгебра:

from datetime import datetime

some_task = Task(created_at=datetime(2025, 1, 1))

some_task.open() or some_task.obsolete()
# True

Обратите внимание, что булева алгебра используется с and, 'or' и not.

Критерии-методы с классами

Критериев-методы можно использовать без инстансов, обращаясь к классам. При таком применении не произойдет проверки критерия. Полученный объект-критерий предоставляет собой отложенное условие:

from datetime import datetime

is_open = Task.open()  # Отложенная проверка

some_task = Task(created_at=datetime(2025, 1, 1))

is_open.is_satisfied_by(some_task)
# True

Фильтрация

Отложенные критерии также можно использовать для фильтрации списка:

from datetime import datetime

some_crit = Task.open() | Task.obsolete()

tasks = [
    Task(created_at=datetime(2025, 1, 1)),
    Task(created_at=datetime(2025, 1, 1),
         finished_at=datetime(2025, 1, 5)),
    Task(created_at=datetime(2025, 1, 1),
         finished_at=datetime(2025, 1, 2)),
]

filtered_tasks = filter(some_crit, tasks)
# True

Критерии-функции

Также можно использовать декоратор criteria на обычных функциях. Все свойства таких критериев абсолютно аналогичны варианту с методами:

from datetime import datetime
from dataclasses import dataclass
from typing import Optional

from classic.domain import criteria


@dataclass
class Task:
    created_at: datetime
    finished_at: Optional[datetime] = None
    

@criteria
def task_open(task: Task) -> bool:
    return task.finished_at is None


@criteria
def task_is_obsolete(task: Task, days_to_work: int) -> bool:
    return (
        task.finished_at is not None and
        (task.created_at - task.finished_at).days > days_to_work
    )

Выборки в БД

Также, критерии можно использовать для построения запросов к БД.

Этот раздел будет заполнен позднее, по мере готовности classic-db-tools

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

classic_domain-0.0.1.tar.gz (9.4 kB view details)

Uploaded Source

File details

Details for the file classic_domain-0.0.1.tar.gz.

File metadata

  • Download URL: classic_domain-0.0.1.tar.gz
  • Upload date:
  • Size: 9.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.13

File hashes

Hashes for classic_domain-0.0.1.tar.gz
Algorithm Hash digest
SHA256 bb1dc3122fbb7dcfc5f7034eb1642171cc1e6705d7a0a211c94f9af6fd6b812f
MD5 005213022e6c1bd74aae7f8279aa751a
BLAKE2b-256 b0fe3b64f12c323696032afdda25536a195c599b767d5be1a3dd2418cbb1c7f2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page