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.2.0.tar.gz (9.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

classic_domain-0.2.0-py3-none-any.whl (8.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: classic_domain-0.2.0.tar.gz
  • Upload date:
  • Size: 9.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for classic_domain-0.2.0.tar.gz
Algorithm Hash digest
SHA256 8c490abc2f5c6605f3a334108f87d57ab79203408cb8ccf33d340a156fded984
MD5 7e9e25881f2851bb10daeb5375c37649
BLAKE2b-256 29896ad54b2a4d4cb2c76452e99d7782c88eb69cf56ae8bfd063bbe20be0432c

See more details on using hashes here.

Provenance

The following attestation bundles were made for classic_domain-0.2.0.tar.gz:

Publisher: publish.yml on variasov/classic-domain

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file classic_domain-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: classic_domain-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 8.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for classic_domain-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 408785e9c8d4ce573417767e09797b75eaa6683b34554d33f67dcccf884942ea
MD5 1caa6c28e363dc2edfd8797aae3eddd7
BLAKE2b-256 126329f0d523a6a286ab992fa99d20c4f7365dd63b499282f5635ce12e3fe40a

See more details on using hashes here.

Provenance

The following attestation bundles were made for classic_domain-0.2.0-py3-none-any.whl:

Publisher: publish.yml on variasov/classic-domain

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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