Skip to content

Commit efb2da8

Browse files
committed
Add support for EventsCritereon and ToIndexCriteroen in InMemoryStore. Also add IndexHeader, EventIdHeader and RecordedOnHeader to the messages in the InMemoryStore and fixed FromIndexCriteroen and transactional behaviour.
1 parent 0cfe743 commit efb2da8

File tree

7 files changed

+509
-73
lines changed

7 files changed

+509
-73
lines changed

baseline.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,6 @@
159159
<code><![CDATA[$dateTimeType->convertToPHPValue($data['recorded_on'], $platform)]]></code>
160160
</MixedArgument>
161161
</file>
162-
<file src="src/Store/InMemoryStore.php">
163-
<MixedPropertyTypeCoercion>
164-
<code><![CDATA[$this->messages]]></code>
165-
</MixedPropertyTypeCoercion>
166-
</file>
167162
<file src="src/Store/StreamDoctrineDbalStore.php">
168163
<DeprecatedMethod>
169164
<code><![CDATA[setPrimaryKey]]></code>

deptrac-baseline.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,12 @@ deptrac:
1414
- Patchlevel\EventSourcing\Aggregate\AggregateRoot
1515
Patchlevel\EventSourcing\Attribute\Subscriber:
1616
- Patchlevel\EventSourcing\Subscription\RunMode
17+
Patchlevel\EventSourcing\Store\DoctrineDbalStore:
18+
- Patchlevel\EventSourcing\Aggregate\AggregateHeader
19+
Patchlevel\EventSourcing\Store\DoctrineDbalStoreStream:
20+
- Patchlevel\EventSourcing\Aggregate\AggregateHeader
21+
Patchlevel\EventSourcing\Store\InMemoryStore:
22+
- Patchlevel\EventSourcing\Aggregate\AggregateHeader
23+
- Patchlevel\EventSourcing\Metadata\Event\EventRegistry
24+
Patchlevel\EventSourcing\Store\MissingEventRegistry:
25+
- Patchlevel\EventSourcing\Metadata\Event\EventRegistry

deptrac.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,6 @@ deptrac:
186186
- Cryptography
187187
- MetadataAggregate
188188
Store:
189-
- Aggregate
190-
- Attribute
191189
- Clock
192190
- Message
193191
- Metadata

src/Store/Header/IndexHeader.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44

55
namespace Patchlevel\EventSourcing\Store\Header;
66

7-
/**
8-
* @psalm-immutable
9-
* @experimental
10-
*/
7+
/** @psalm-immutable */
118
final class IndexHeader
129
{
1310
/** @param positive-int $index */

src/Store/InMemoryStore.php

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,30 @@
66

77
use Closure;
88
use Patchlevel\EventSourcing\Aggregate\AggregateHeader;
9+
use Patchlevel\EventSourcing\Clock\SystemClock;
910
use Patchlevel\EventSourcing\Message\HeaderNotFound;
1011
use Patchlevel\EventSourcing\Message\Message;
12+
use Patchlevel\EventSourcing\Metadata\Event\EventRegistry;
1113
use Patchlevel\EventSourcing\Store\Criteria\AggregateIdCriterion;
1214
use Patchlevel\EventSourcing\Store\Criteria\AggregateNameCriterion;
1315
use Patchlevel\EventSourcing\Store\Criteria\ArchivedCriterion;
1416
use Patchlevel\EventSourcing\Store\Criteria\Criteria;
17+
use Patchlevel\EventSourcing\Store\Criteria\EventsCriterion;
1518
use Patchlevel\EventSourcing\Store\Criteria\FromIndexCriterion;
1619
use Patchlevel\EventSourcing\Store\Criteria\FromPlayheadCriterion;
1720
use Patchlevel\EventSourcing\Store\Criteria\StreamCriterion;
21+
use Patchlevel\EventSourcing\Store\Criteria\ToIndexCriterion;
22+
use Patchlevel\EventSourcing\Store\Header\EventIdHeader;
23+
use Patchlevel\EventSourcing\Store\Header\IndexHeader;
1824
use Patchlevel\EventSourcing\Store\Header\PlayheadHeader;
25+
use Patchlevel\EventSourcing\Store\Header\RecordedOnHeader;
1926
use Patchlevel\EventSourcing\Store\Header\StreamNameHeader;
27+
use Psr\Clock\ClockInterface;
28+
use Ramsey\Uuid\Uuid;
29+
use Throwable;
2030

2131
use function array_filter;
2232
use function array_map;
23-
use function array_push;
2433
use function array_reverse;
2534
use function array_slice;
2635
use function array_unique;
@@ -35,10 +44,16 @@
3544

3645
final class InMemoryStore implements StreamStore
3746
{
38-
/** @param array<positive-int|0, Message> $messages */
47+
/** @var array<0|positive-int, Message> */
48+
private array $messages = [];
49+
50+
/** @param list<Message> $messages */
3951
public function __construct(
40-
private array $messages = [],
52+
array $messages = [],
53+
private readonly EventRegistry|null $eventRegistry = null,
54+
private readonly ClockInterface $clock = new SystemClock(),
4155
) {
56+
$this->save(...$messages);
4257
}
4358

4459
public function load(
@@ -71,7 +86,27 @@ public function count(Criteria|null $criteria = null): int
7186

7287
public function save(Message ...$messages): void
7388
{
74-
array_push($this->messages, ...$messages);
89+
$this->transactional(function () use ($messages): void {
90+
$count = count($this->messages);
91+
92+
foreach ($messages as $message) {
93+
$count++;
94+
95+
if (!$message->hasHeader(IndexHeader::class)) {
96+
$message = $message->withHeader(new IndexHeader($count));
97+
}
98+
99+
if (!$message->hasHeader(EventIdHeader::class)) {
100+
$message = $message->withHeader(new EventIdHeader(Uuid::uuid7()->toString()));
101+
}
102+
103+
if (!$message->hasHeader(RecordedOnHeader::class)) {
104+
$message = $message->withHeader(new RecordedOnHeader($this->clock->now()));
105+
}
106+
107+
$this->messages[] = $message;
108+
}
109+
});
75110
}
76111

77112
/**
@@ -81,7 +116,14 @@ public function save(Message ...$messages): void
81116
*/
82117
public function transactional(Closure $function): void
83118
{
84-
$function();
119+
$messages = $this->messages;
120+
try {
121+
$function();
122+
} catch (Throwable $e) {
123+
$this->messages = $messages;
124+
125+
throw $e;
126+
}
85127
}
86128

87129
/** @return list<string> */
@@ -134,9 +176,11 @@ private function filter(Criteria|null $criteria): array
134176
return $this->messages;
135177
}
136178

179+
$eventRegistry = $this->eventRegistry;
180+
137181
return array_filter(
138182
$this->messages,
139-
static function (Message $message, int $index) use ($criteria): bool {
183+
static function (Message $message) use ($criteria, $eventRegistry): bool {
140184
foreach ($criteria->all() as $criterion) {
141185
switch ($criterion::class) {
142186
case AggregateIdCriterion::class:
@@ -222,7 +266,35 @@ static function (Message $message, int $index) use ($criteria): bool {
222266

223267
break;
224268
case FromIndexCriterion::class:
225-
if ($index < $criterion->fromIndex) {
269+
try {
270+
$index = $message->header(IndexHeader::class)->index;
271+
} catch (HeaderNotFound) {
272+
return false;
273+
}
274+
275+
if ($index <= $criterion->fromIndex) {
276+
return false;
277+
}
278+
279+
break;
280+
case ToIndexCriterion::class:
281+
try {
282+
$index = $message->header(IndexHeader::class)->index;
283+
} catch (HeaderNotFound) {
284+
return false;
285+
}
286+
287+
if ($index >= $criterion->toIndex) {
288+
return false;
289+
}
290+
291+
break;
292+
case EventsCriterion::class:
293+
if ($eventRegistry === null) {
294+
throw new MissingEventRegistry($criterion::class);
295+
}
296+
297+
if (!in_array($eventRegistry->eventName($message->event()::class), $criterion->events)) {
226298
return false;
227299
}
228300

src/Store/MissingEventRegistry.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Patchlevel\EventSourcing\Store;
6+
7+
use Patchlevel\EventSourcing\Metadata\Event\EventRegistry;
8+
use RuntimeException;
9+
10+
use function sprintf;
11+
12+
final class MissingEventRegistry extends RuntimeException
13+
{
14+
/** @param class-string $criterionClass */
15+
public function __construct(string $criterionClass)
16+
{
17+
parent::__construct(sprintf('criterion %s not supported without an %s given', $criterionClass, EventRegistry::class));
18+
}
19+
}

0 commit comments

Comments
 (0)