Skip to content

Commit

Permalink
Allow to return new instances of same aggregate (#417)
Browse files Browse the repository at this point in the history
* Allow to return new instances of same aggregate

* treat factory method separately

* test fixes
  • Loading branch information
dgafka authored Dec 5, 2024
1 parent e98b40d commit f23df4f
Show file tree
Hide file tree
Showing 12 changed files with 285 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ classesToResolve: [CalendarWithInternalRecorder::class, MeetingWithInternalRecor
self::assertEquals(
[
new CalendarCreated($calendarId),
new MeetingCreated($meetingId),
new MeetingScheduled($calendarId, $meetingId),
new MeetingCreated($meetingId),
],
$ecotone->getRecordedEvents()
);
Expand Down Expand Up @@ -164,8 +164,8 @@ classesToResolve: [CalendarWithInternalRecorder::class, MeetingWithEventSourcing
self::assertEquals(
[
new CalendarCreated($calendarId),
new MeetingCreated($meetingId),
new MeetingScheduled($calendarId, $meetingId),
new MeetingCreated($meetingId),
],
$ecotone->getRecordedEvents()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public function process(Message $message): ?Message
$resultAggregateEvents = $message->getHeaders()->containsKey(AggregateMessage::RESULT_AGGREGATE_EVENTS) ? $message->getHeaders()->get(AggregateMessage::RESULT_AGGREGATE_EVENTS) : [];
$calledAggregateEvents = $message->getHeaders()->containsKey(AggregateMessage::CALLED_AGGREGATE_EVENTS) ? $message->getHeaders()->get(AggregateMessage::CALLED_AGGREGATE_EVENTS) : [];

$this->publishEvents(SaveAggregateServiceTemplate::buildEcotoneEvents($resultAggregateEvents, $this->calledInterface, $message));
$this->publishEvents(SaveAggregateServiceTemplate::buildEcotoneEvents($calledAggregateEvents, $this->calledInterface, $message));
$this->publishEvents(SaveAggregateServiceTemplate::buildEcotoneEvents($resultAggregateEvents, $this->calledInterface, $message));

$isExecutionResultNull = $message->getHeaders()->containsKey(AggregateMessage::NULL_EXECUTION_RESULT) ? $message->getHeaders()->get(AggregateMessage::NULL_EXECUTION_RESULT) : false;
if ($isExecutionResultNull) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ private function initialize(ClassDefinition $aggregateClassDefinition, string $m
$returnTypeInterface = $interfaceToCallRegistry->getClassDefinitionFor(TypeDescriptor::create($interfaceToCall->getReturnType()->toString()));
if (
$returnTypeInterface->hasClassAnnotation(TypeDescriptor::create(Aggregate::class))
&& $returnTypeInterface->getClassType() !== $aggregateClassDefinition->getClassType()
&& !$interfaceToCall->isFactoryMethod()
) {
$resultClassDefinition = ClassDefinition::createFor($interfaceToCall->getReturnType());
$this->isReturningAggregate = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

namespace Test\Ecotone\Modelling\Fixture\EventSourcedAggregateWithInternalEventRecorder;

use Ecotone\Messaging\Attribute\Parameter\Header;
use Ecotone\Modelling\Attribute\CommandHandler;
use Ecotone\Modelling\Attribute\EventSourcingAggregate;
use Ecotone\Modelling\Attribute\EventSourcingHandler;
use Ecotone\Modelling\Attribute\Identifier;
use Ecotone\Modelling\Attribute\QueryHandler;
use Ecotone\Modelling\WithAggregateEvents;
use Ecotone\Modelling\WithAggregateVersioning;
use Ramsey\Uuid\Uuid;

#[EventSourcingAggregate(true)]
/**
Expand Down Expand Up @@ -38,6 +40,14 @@ public function finish(FinishJob $command): void
$this->recordThat(JobWasFinished::recordWith($command->getId()));
}

#[CommandHandler('job.finish_and_start')]
public function finishAndStartNewJob(FinishJob $command, #[Header('newJobId')] string $newJobId): Job
{
$this->recordThat(JobWasFinished::recordWith($command->getId()));

return self::start(new StartJob($newJobId));
}

#[QueryHandler('job.isInProgress')]
public function isInProgress(): bool
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace Test\Ecotone\Modelling\Unit;

use Ecotone\Lite\EcotoneLite;
use Ecotone\Messaging\Channel\QueueChannel;
use Ecotone\Messaging\Config\ModulePackageList;
use Ecotone\Messaging\Config\ServiceConfiguration;
use Ecotone\Messaging\Handler\ClassDefinition;
use Ecotone\Messaging\Handler\InterfaceToCallRegistry;
use Ecotone\Messaging\Handler\ServiceActivator\MessageProcessorActivatorBuilder;
Expand All @@ -20,16 +23,23 @@
use Ecotone\Modelling\StandardRepository;
use Ecotone\Test\ComponentTestBuilder;
use PHPUnit\Framework\TestCase;
use Ramsey\Uuid\Uuid;
use stdClass;
use Test\Ecotone\Modelling\Fixture\Blog\Article;
use Test\Ecotone\Modelling\Fixture\Blog\PublishArticleCommand;
use Test\Ecotone\Modelling\Fixture\CommandHandler\Aggregate\CreateOrderCommand;
use Test\Ecotone\Modelling\Fixture\CommandHandler\Aggregate\InMemoryStandardRepository;
use Test\Ecotone\Modelling\Fixture\CommandHandler\Aggregate\Order;
use Test\Ecotone\Modelling\Fixture\CommandHandler\Aggregate\OrderWithManualVersioning;
use Test\Ecotone\Modelling\Fixture\EventSourcedAggregateWithInternalEventRecorder\FinishJob;
use Test\Ecotone\Modelling\Fixture\EventSourcedAggregateWithInternalEventRecorder\Job;
use Test\Ecotone\Modelling\Fixture\EventSourcedAggregateWithInternalEventRecorder\JobWasFinished;
use Test\Ecotone\Modelling\Fixture\EventSourcedAggregateWithInternalEventRecorder\JobWasStarted;
use Test\Ecotone\Modelling\Fixture\EventSourcedAggregateWithInternalEventRecorder\StartJob;
use Test\Ecotone\Modelling\Fixture\IncorrectEventSourcedAggregate\NoIdDefinedAfterCallingFactory\NoIdDefinedAfterRecordingEvents;
use Test\Ecotone\Modelling\Fixture\IncorrectEventSourcedAggregate\PublicIdentifierGetMethodForEventSourcedAggregate;
use Test\Ecotone\Modelling\Fixture\IncorrectEventSourcedAggregate\PublicIdentifierGetMethodWithParameters;
use Test\Ecotone\Modelling\Fixture\NoEventsReturnedFromFactoryMethod\Aggregate;
use Test\Ecotone\Modelling\Fixture\Ticket\Ticket;
use Test\Ecotone\Modelling\Fixture\Ticket\TicketWasStartedEvent;

Expand Down Expand Up @@ -437,4 +447,28 @@ public function test_throwing_exception_if_aggregate_identifier_getter_has_param
->build()
;
}

public function test_result_aggregate_are_published_in_order(): void
{
$ecotoneLite = EcotoneLite::bootstrapFlowTesting(
classesToResolve: [Job::class]
);

$jobId = Uuid::uuid4()->toString();
$newJobId = Uuid::uuid4()->toString();

self::assertEquals(
[
JobWasFinished::recordWith($jobId),
JobWasStarted::recordWith($newJobId)
],
$ecotoneLite
->sendCommand(new StartJob($jobId))
->discardRecordedMessages()
->sendCommandWithRoutingKey('job.finish_and_start', new FinishJob($jobId), metadata: [
'newJobId' => $newJobId
])
->getRecordedEvents(),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Test\Ecotone\EventSourcing\Fixture\Calendar;

/**
* licence Apache-2.0
*/
final class CalendarClosed
{
public function __construct(public string $calendarId)
{
}
}
15 changes: 15 additions & 0 deletions packages/PdoEventSourcing/tests/Fixture/Calendar/CloseCalendar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Test\Ecotone\EventSourcing\Fixture\Calendar;

/**
* licence Apache-2.0
*/
final class CloseCalendar
{
public function __construct(public string $calendarId)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,18 @@ public function convertToMeetingCreated(array $payload): MeetingCreated
{
return new MeetingCreated($payload['meetingId'], $payload['calendarId']);
}

#[Converter]
public function convertCalendarClosed(CalendarClosed $event): array
{
return [
'calendarId' => $event->calendarId,
];
}

#[Converter]
public function convertToCalendarClosed(array $payload): CalendarClosed
{
return new CalendarClosed($payload['calendarId']);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Test\Ecotone\EventSourcing\Fixture\Calendar;

/**
* licence Apache-2.0
*/
final class OpenFreshCalendar
{
public function __construct(public string $calendarId, public string $freshCalendarId)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace Test\Ecotone\EventSourcing\Fixture\CalendarProjection;

use Ecotone\EventSourcing\Attribute\Projection;
use Ecotone\Messaging\Support\Assert;
use Ecotone\Modelling\Attribute\EventHandler;
use Ecotone\Modelling\Attribute\QueryHandler;
use Test\Ecotone\EventSourcing\Fixture\Calendar\CalendarCreated;
use Test\Ecotone\EventSourcing\Fixture\Calendar\MeetingCreated;
use Test\Ecotone\EventSourcing\Fixture\Calendar\MeetingScheduled;
use Test\Ecotone\EventSourcing\Fixture\Calendar\MeetingWithEventSourcing;
use Test\Ecotone\EventSourcing\Fixture\EventSourcingCalendarWithInternalRecorder\CalendarWithInternalRecorder;

#[Projection('calendar', [CalendarWithInternalRecorder::class, MeetingWithEventSourcing::class])]
final class CalendarProjection
{
private $calendars = [];

#[EventHandler]
public function whenCalendarCreated(CalendarCreated $event): void
{
$this->calendars[$event->calendarId] = [];
}

#[EventHandler]
public function whenMeetingScheduled(MeetingScheduled $event): void
{
$this->calendars[$event->calendarId][$event->meetingId] = 'scheduled';
}

#[EventHandler]
public function whenMeetingCreated(MeetingCreated $event): void
{
$this->calendars[$event->calendarId][$event->meetingId] = 'created';
}

#[QueryHandler('getCalendar')]
public function getCalendar(string $calendarId): array
{
Assert::keyExists($this->calendars, $calendarId, "Calendar with id {$calendarId} not found");
return $this->calendars[$calendarId];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@
use Ecotone\Modelling\Attribute\QueryHandler;
use Ecotone\Modelling\WithAggregateVersioning;
use Ecotone\Modelling\WithEvents;
use Test\Ecotone\EventSourcing\Fixture\Calendar\CalendarClosed;
use Test\Ecotone\EventSourcing\Fixture\Calendar\CalendarCreated;
use Test\Ecotone\EventSourcing\Fixture\Calendar\CloseCalendar;
use Test\Ecotone\EventSourcing\Fixture\Calendar\CreateCalendar;
use Test\Ecotone\EventSourcing\Fixture\Calendar\Meeting;
use Test\Ecotone\EventSourcing\Fixture\Calendar\MeetingScheduled;
use Test\Ecotone\EventSourcing\Fixture\Calendar\MeetingWithEventSourcing;
use Test\Ecotone\EventSourcing\Fixture\Calendar\MeetingWithInternalRecorder;
use Test\Ecotone\EventSourcing\Fixture\Calendar\OpenFreshCalendar;
use Test\Ecotone\EventSourcing\Fixture\Calendar\ScheduleMeeting;
use Test\Ecotone\EventSourcing\Fixture\Calendar\ScheduleMeetingWithEventSourcing;
use Test\Ecotone\EventSourcing\Fixture\Calendar\ScheduleMeetingWithInternalRecorder;
Expand All @@ -36,6 +39,8 @@ final class CalendarWithInternalRecorder
/** @var array<string> */
private array $meetings;

private bool $isOpen;

#[CommandHandler]
public static function createCalendar(CreateCalendar $command): static
{
Expand Down Expand Up @@ -69,11 +74,28 @@ public function scheduleMeetingWithEventSourcing(ScheduleMeetingWithEventSourcin
return MeetingWithEventSourcing::create($command->meetingId, $this->calendarId);
}

#[CommandHandler]
public function openFreshCalendar(OpenFreshCalendar $command): self
{
$this->recordThat(new CalendarClosed($this->calendarId));

return self::createCalendar(new CreateCalendar($command->freshCalendarId));
}

#[CommandHandler]
public function closeAndReturn(CloseCalendar $command): self
{
$this->recordThat(new CalendarClosed($this->calendarId));

return $this;
}

#[EventSourcingHandler]
public function applyCalendarCreated(CalendarCreated $event): void
{
$this->calendarId = $event->calendarId;
$this->meetings = [];
$this->isOpen = true;
}

#[EventSourcingHandler]
Expand All @@ -82,6 +104,18 @@ public function applyMeetingScheduled(MeetingScheduled $event): void
$this->meetings[] = $event->meetingId;
}

#[EventSourcingHandler]
public function applyCalendarClosed(CalendarClosed $event): void
{
$this->isOpen = false;
}

#[QueryHandler('calendar.isOpen')]
public function isOpen(): bool
{
return $this->isOpen;
}

#[QueryHandler('calendar.meetings')]
public function meetings(): array
{
Expand Down
Loading

0 comments on commit f23df4f

Please sign in to comment.