Commit af379da3 authored by Mickaël Bourgier's avatar Mickaël Bourgier
Browse files

Add RevertableEvent, RevertEvent and SkipRevertedStream

parent 08beb503
<?php
namespace Webf\ProjectionBundle\Event;
interface RevertEventInterface extends EventInterface
{
public function getRevertedEventId(): string;
}
<?php
namespace Webf\ProjectionBundle\Event;
interface RevertableEventInterface extends EventInterface
{
public function getId(): string;
}
<?php
namespace Webf\ProjectionBundle\Stream;
use Webf\ProjectionBundle\Event\EventInterface;
use Webf\ProjectionBundle\Event\RevertableEventInterface;
use Webf\ProjectionBundle\Event\RevertEventInterface;
class SkipRevertedStream implements StreamInterface
{
private StreamInterface $innerStream;
private StreamInterface $revertStream;
private ?array $revertedEvents = null;
public function __construct(
StreamInterface $innerStream,
StreamInterface $revertStream
) {
$this->innerStream = $innerStream;
$this->revertStream = $revertStream;
}
public function getEventTypes(): array
{
return $this->innerStream->getEventTypes();
}
public function nextEvent(): ?EventInterface
{
if (null === $this->revertedEvents) {
$this->collectRevertedEvents();
}
while (null !== ($event = $this->innerStream->nextEvent())) {
if ($event instanceof RevertEventInterface) {
continue;
}
if (!$event instanceof RevertableEventInterface || !key_exists($event->getId(), $this->revertedEvents)) {
return $event;
}
}
return null;
}
private function collectRevertedEvents(): void
{
$this->revertedEvents = [];
while (null !== ($event = $this->revertStream->nextEvent())) {
if ($event instanceof RevertEventInterface) {
$this->revertedEvents[$event->getRevertedEventId()] = $event;
}
}
}
}
<?php
namespace Tests\Event\Stub;
use DateTimeImmutable;
use Webf\ProjectionBundle\Event\RevertEventInterface;
class RevertEventStub extends EventStub implements RevertEventInterface
{
private string $revertedEventId;
public function __construct(
string $revertedEventId,
DateTimeImmutable $date = null
) {
parent::__construct('__revert__', $date);
$this->revertedEventId = $revertedEventId;
}
public function getRevertedEventId(): string
{
return $this->revertedEventId;
}
}
<?php
namespace Tests\Event\Stub;
use DateTimeImmutable;
use Webf\ProjectionBundle\Event\RevertableEventInterface;
class RevertableEventStub extends EventStub implements RevertableEventInterface
{
private string $id;
public function __construct(
string $id,
string $type,
DateTimeImmutable $date = null
) {
parent::__construct($type, $date);
$this->id = $id;
}
public function getId(): string
{
return $this->id;
}
}
<?php
namespace Tests\Stream;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use Tests\Event\Stub\EventStub;
use Tests\Event\Stub\RevertableEventStub;
use Tests\Event\Stub\RevertEventStub;
use Tests\Stream\Stub\StreamStub;
use Webf\ProjectionBundle\Stream\SkipRevertedStream;
use Webf\ProjectionBundle\Stream\StreamInterface;
/**
* @internal
* @covers \Webf\ProjectionBundle\Stream\SkipRevertedStream
*/
class SkipRevertedStreamTest extends TestCase
{
public function test_get_event_types_returns_event_types_of_inner_stream()
{
$eventTypes = ['a', 'b', 'c'];
$innerStream = new StreamStub($eventTypes);
$revertStream = new StreamStub($eventTypes);
$stream = new SkipRevertedStream($innerStream, $revertStream);
$this->assertEquals($eventTypes, $stream->getEventTypes());
}
public function test_next_event_does_not_return_reverted_events()
{
$innerStream = $this->createMock(StreamInterface::class);
$innerStream
->expects($this->exactly(7))
->method('nextEvent')
->willReturnOnConsecutiveCalls(
$e1 = new RevertableEventStub('1', 'a', new DateTimeImmutable('-10 hours')),
$e2 = new RevertableEventStub('2', 'a', new DateTimeImmutable('-8 hours')),
$e3 = new EventStub('a', new DateTimeImmutable('-6 hours')),
$e4 = new RevertableEventStub('4', 'a', new DateTimeImmutable('-4 hours')),
$e5 = new RevertableEventStub('5', 'a', new DateTimeImmutable('-2 hours')),
$e6 = new RevertableEventStub('6', 'a', new DateTimeImmutable('now')),
null
)
;
$revertStream = StreamStub::fromEvents([
new RevertEventStub('4', new DateTimeImmutable('-3 hours')),
new RevertEventStub('2', new DateTimeImmutable('-1 hours')),
]);
$stream = new SkipRevertedStream($innerStream, $revertStream);
$events = [];
while (null !== ($event = $stream->nextEvent())) {
$events[] = $event;
}
$this->assertEquals([$e1, $e3, $e5, $e6], $events);
}
public function test_inner_stream_and_revert_stream_can_be_the_same_copy()
{
$events = [
$e1 = new RevertableEventStub('1', 'a', new DateTimeImmutable('-10 hours')),
$e2 = new RevertableEventStub('2', 'a', new DateTimeImmutable('-8 hours')),
$e3 = new EventStub('a', new DateTimeImmutable('-6 hours')),
$e4 = new RevertableEventStub('4', 'a', new DateTimeImmutable('-4 hours')),
$e5 = new RevertEventStub('4', new DateTimeImmutable('-3 hours')),
$e6 = new RevertableEventStub('5', 'a', new DateTimeImmutable('-2 hours')),
$e7 = new RevertEventStub('2', new DateTimeImmutable('-1 hours')),
$e8 = new RevertableEventStub('6', 'a', new DateTimeImmutable('now')),
];
$stream = new SkipRevertedStream(
StreamStub::fromEvents($events),
StreamStub::fromEvents($events)
);
$events = [];
while (null !== ($event = $stream->nextEvent())) {
$events[] = $event;
}
$this->assertEquals([$e1, $e3, $e6, $e8], $events);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment