From 9440b71fb9bd5e0b07ce5275746b72066957d9ad Mon Sep 17 00:00:00 2001 From: Christoph Blessing <33834216+cblessing24@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:07:13 +0100 Subject: [PATCH 1/3] Remove unused event --- link/domain/commands.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/link/domain/commands.py b/link/domain/commands.py index 61b584f..5aace4f 100644 --- a/link/domain/commands.py +++ b/link/domain/commands.py @@ -37,8 +37,3 @@ class DeleteEntities(Command): """Delete the requested entities.""" requested: frozenset[Identifier] - - -@dataclass(frozen=True) -class ListUnsharedEntities(Command): - """Start the delete process for the requested entities.""" From d616273982b2fe8c38e115426e5cd339774633b7 Mon Sep 17 00:00:00 2001 From: Christoph Blessing <33834216+cblessing24@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:09:51 +0100 Subject: [PATCH 2/3] Add base class for commands dealing with batches --- link/domain/commands.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/link/domain/commands.py b/link/domain/commands.py index 5aace4f..56f33ed 100644 --- a/link/domain/commands.py +++ b/link/domain/commands.py @@ -11,6 +11,13 @@ class Command: """Base class for all commands.""" +@dataclass(frozen=True) +class BatchCommand(Command): + """Base class for all commands dealing with a batch of entities.""" + + requested: frozenset[Identifier] + + @dataclass(frozen=True) class PullEntity(Command): """Pull the requested entity.""" @@ -26,14 +33,10 @@ class DeleteEntity(Command): @dataclass(frozen=True) -class PullEntities(Command): +class PullEntities(BatchCommand): """Pull the requested entities.""" - requested: frozenset[Identifier] - @dataclass(frozen=True) -class DeleteEntities(Command): +class DeleteEntities(BatchCommand): """Delete the requested entities.""" - - requested: frozenset[Identifier] From 0b456819965bf0988a53efde0d0d9e060c700ee7 Mon Sep 17 00:00:00 2001 From: Christoph Blessing <33834216+cblessing24@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:30:20 +0100 Subject: [PATCH 3/3] Raise error when no entites requested --- link/service/ensure.py | 16 ++++++++++++++++ link/service/handlers.py | 3 +++ tests/integration/test_services.py | 15 +++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 link/service/ensure.py diff --git a/link/service/ensure.py b/link/service/ensure.py new file mode 100644 index 0000000..f8186f4 --- /dev/null +++ b/link/service/ensure.py @@ -0,0 +1,16 @@ +"""Contains preconditions that are applied to the handlers.""" +from link.domain.commands import BatchCommand + + +class NoEntitiesRequested(Exception): + """This exception is raised when a batch command that requests no entities is encountered.""" + + def __init__(self, command: BatchCommand) -> None: + """Initialize the exception.""" + self.command = command + + +def requests_entities(command: BatchCommand) -> None: + """Raise an exception if the given command requests no entities.""" + if not command.requested: + raise NoEntitiesRequested(command) diff --git a/link/service/handlers.py b/link/service/handlers.py index b5d5e2e..b25893f 100644 --- a/link/service/handlers.py +++ b/link/service/handlers.py @@ -6,6 +6,7 @@ from link.domain import commands, events from link.domain.state import Processes +from . import ensure from .messagebus import MessageBus from .progress import ProgessDisplay from .uow import UnitOfWork @@ -31,6 +32,7 @@ def delete_entity(command: commands.DeleteEntity, *, uow: UnitOfWork, message_bu def pull(command: commands.PullEntities, *, message_bus: MessageBus) -> None: """Pull entities across the link.""" + ensure.requests_entities(command) message_bus.handle(events.BatchProcessingStarted(Processes.PULL, command.requested)) for identifier in command.requested: message_bus.handle(commands.PullEntity(identifier)) @@ -39,6 +41,7 @@ def pull(command: commands.PullEntities, *, message_bus: MessageBus) -> None: def delete(command: commands.DeleteEntities, *, message_bus: MessageBus) -> None: """Delete shared entities.""" + ensure.requests_entities(command) message_bus.handle(events.BatchProcessingStarted(Processes.DELETE, command.requested)) for identifier in command.requested: message_bus.handle(commands.DeleteEntity(identifier)) diff --git a/tests/integration/test_services.py b/tests/integration/test_services.py index 26cf739..9a9390e 100644 --- a/tests/integration/test_services.py +++ b/tests/integration/test_services.py @@ -7,6 +7,7 @@ from link.domain import commands, events from link.domain.state import Components, Processes, State, states +from link.service.ensure import NoEntitiesRequested from link.service.handlers import delete, delete_entity, pull, pull_entity from link.service.messagebus import CommandHandlers, EventHandlers, MessageBus from link.service.uow import UnitOfWork @@ -171,3 +172,17 @@ def test_pulled_entity_ends_in_correct_state(state: EntityConfig, expected: type pull_service(commands.PullEntities(frozenset(create_identifiers("1")))) with uow: assert uow.entities.create_entity(create_identifier("1")).state is expected + + +@pytest.mark.parametrize( + ("create_service", "command_cls"), + [(create_pull_service, commands.PullEntities), (create_delete_service, commands.DeleteEntities)], +) +def test_requesting_no_entities_raises_error( + create_service: Callable[[UnitOfWork], Callable[[commands.BatchCommand], None]], + command_cls: type[commands.BatchCommand], +) -> None: + uow = create_uow(**STATES[0]) + service = create_service(uow) + with pytest.raises(NoEntitiesRequested): + service(command_cls(frozenset()))