-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #643 from patchlevel/pipeline
Add pipe & reducer
- Loading branch information
Showing
22 changed files
with
1,310 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Patchlevel\EventSourcing\Message; | ||
|
||
use Generator; | ||
use IteratorAggregate; | ||
use Patchlevel\EventSourcing\Message\Translator\ChainTranslator; | ||
use Patchlevel\EventSourcing\Message\Translator\Translator; | ||
use Traversable; | ||
|
||
use function array_values; | ||
use function iterator_to_array; | ||
|
||
/** @implements IteratorAggregate<int, Message> */ | ||
final class Pipe implements IteratorAggregate | ||
{ | ||
private Translator $translator; | ||
|
||
/** @param iterable<Message> $messages */ | ||
public function __construct( | ||
private readonly iterable $messages, | ||
Translator ...$translators, | ||
) { | ||
$this->translator = new ChainTranslator($translators); | ||
} | ||
|
||
/** @return Traversable<Message> */ | ||
public function getIterator(): Traversable | ||
{ | ||
return $this->createGenerator( | ||
$this->messages, | ||
$this->translator, | ||
); | ||
} | ||
|
||
/** @return list<Message> */ | ||
public function toArray(): array | ||
{ | ||
return array_values( | ||
iterator_to_array($this->getIterator()), | ||
); | ||
} | ||
|
||
/** | ||
* @param iterable<Message> $messages | ||
* | ||
* @return Generator<Message> | ||
*/ | ||
private function createGenerator(iterable $messages, Translator $translator): Generator | ||
{ | ||
foreach ($messages as $message) { | ||
foreach ($translator($message) as $translatedMessage) { | ||
yield $translatedMessage; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Patchlevel\EventSourcing\Message; | ||
|
||
use Closure; | ||
|
||
/** | ||
* @template STATE of array<array-key, mixed> | ||
* @template OUT of array<array-key, mixed> = STATE | ||
*/ | ||
final class Reducer | ||
{ | ||
/** @var STATE */ | ||
private array $initState = []; | ||
|
||
/** @var array<class-string, list<Closure(Message, STATE): STATE>> */ | ||
private array $handlers = []; | ||
|
||
/** @var list<Closure(Message, STATE): STATE> */ | ||
private array $anyHandlers = []; | ||
|
||
/** @var (Closure(STATE): OUT)|null */ | ||
private Closure|null $finalizeHandler = null; | ||
|
||
/** | ||
* @param STATE $initState | ||
* | ||
* @return $this | ||
*/ | ||
public function initState(array $initState): self | ||
{ | ||
$this->initState = $initState; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param class-string<T1> $event | ||
* @param Closure(Message<T1>, STATE): STATE $closure | ||
* | ||
* @return $this | ||
* | ||
* @template T1 of object | ||
*/ | ||
public function when(string $event, Closure $closure): self | ||
{ | ||
if (!isset($this->handlers[$event])) { | ||
$this->handlers[$event] = []; | ||
} | ||
|
||
$this->handlers[$event][] = $closure; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param Closure(Message, STATE): STATE $closure | ||
* | ||
* @return $this | ||
*/ | ||
public function any(Closure $closure): self | ||
{ | ||
$this->anyHandlers[] = $closure; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param array<class-string, Closure(Message, STATE): STATE> $map | ||
* | ||
* @return $this | ||
*/ | ||
public function match(array $map): self | ||
{ | ||
foreach ($map as $event => $closure) { | ||
$this->when($event, $closure); | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param Closure(STATE): OUT $closure | ||
* | ||
* @return $this | ||
*/ | ||
public function finalize(Closure $closure): self | ||
{ | ||
$this->finalizeHandler = $closure; | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param iterable<Message> $messages | ||
* | ||
* @return OUT|STATE | ||
* @psalm-return (OUT is STATE ? STATE : OUT) | ||
*/ | ||
public function reduce(iterable $messages): array | ||
{ | ||
$state = $this->initState; | ||
|
||
foreach ($messages as $message) { | ||
$event = $message->event(); | ||
|
||
if (isset($this->handlers[$event::class])) { | ||
foreach ($this->handlers[$event::class] as $handler) { | ||
$state = $handler($message, $state); | ||
} | ||
} | ||
|
||
foreach ($this->anyHandlers as $handler) { | ||
$state = $handler($message, $state); | ||
} | ||
} | ||
|
||
if ($this->finalizeHandler !== null) { | ||
$state = ($this->finalizeHandler)($state); | ||
} | ||
|
||
return $state; | ||
} | ||
} |
Oops, something went wrong.