Skip to content

Commit

Permalink
refactor projection errors
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidBadura committed Dec 29, 2023
1 parent b38fc14 commit fdd83f4
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 50 deletions.
1 change: 1 addition & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@

<rule ref="PatchlevelCodingStandard">
<exclude name="Generic.Files.LineLength.TooLong"/>
<exclude name="SlevomatCodingStandard.PHP.RequireExplicitAssertion.RequiredExplicitAssertion"/>
</rule>
</ruleset>
6 changes: 3 additions & 3 deletions src/Console/Command/ProjectionStatusCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$projection->id()->version(),
$projection->position(),
$projection->status()->value,
$projection->errorMessage(),
$projection->projectionError()?->errorMessage,
],
[...$projections],
),
Expand All @@ -84,12 +84,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$projection->id()->version(),
$projection->position(),
$projection->status()->value,
$projection->errorMessage(),
$projection->projectionError()?->errorMessage,
],
],
);

$errorObject = $projection->errorObject();
$errorObject = $projection->projectionError()?->errorObject;

if ($errorObject instanceof Throwable) {
$io->throwable($errorObject);
Expand Down
25 changes: 7 additions & 18 deletions src/Projection/Projection/Projection.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@

namespace Patchlevel\EventSourcing\Projection\Projection;

use Throwable;

final class Projection
{
public function __construct(
private readonly ProjectionId $id,
private ProjectionStatus $status = ProjectionStatus::New,
private int $position = 0,
private string|null $errorMessage = null,
private Throwable|null $errorObject = null,
private ProjectionError|null $error = null,
) {
}

Expand All @@ -32,14 +29,9 @@ public function position(): int
return $this->position;
}

public function errorMessage(): string|null
{
return $this->errorMessage;
}

public function errorObject(): Throwable|null
public function projectionError(): ProjectionError|null
{
return $this->errorObject;
return $this->error;
}

public function incrementPosition(): void
Expand All @@ -55,8 +47,7 @@ public function isNew(): bool
public function booting(): void
{
$this->status = ProjectionStatus::Booting;
$this->errorMessage = null;
$this->errorObject = null;
$this->error = null;
}

public function isBooting(): bool
Expand All @@ -67,8 +58,7 @@ public function isBooting(): bool
public function active(): void
{
$this->status = ProjectionStatus::Active;
$this->errorMessage = null;
$this->errorObject = null;
$this->error = null;
}

public function isActive(): bool
Expand All @@ -86,11 +76,10 @@ public function isOutdated(): bool
return $this->status === ProjectionStatus::Outdated;
}

public function error(Throwable|string|null $error = null): void
public function error(ProjectionError|null $error = null): void
{
$this->status = ProjectionStatus::Error;
$this->errorMessage = $error instanceof Throwable ? $error->getMessage() : $error;
$this->errorObject = $error instanceof Throwable ? $error : null;
$this->error = $error;
}

public function isError(): bool
Expand Down
21 changes: 21 additions & 0 deletions src/Projection/Projection/ProjectionError.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Projection\Projection;

use Throwable;

final class ProjectionError
{
public function __construct(
public readonly string $errorMessage,
public readonly Throwable|null $errorObject = null,
) {
}

public static function fromThrowable(Throwable $error): self
{
return new self($error->getMessage(), $error);
}
}
51 changes: 31 additions & 20 deletions src/Projection/Projection/Store/DoctrineStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,23 @@
use Doctrine\DBAL\Types\Types;
use Patchlevel\EventSourcing\Projection\Projection\Projection;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionCollection;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionError;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionId;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionNotFound;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionStatus;
use Patchlevel\EventSourcing\Schema\SchemaConfigurator;

use function array_map;

/** @psalm-type Data = array{
* name: string,
* version: int,
* position: int,
* status: string,
* error_message: string|null,
* error_object: string|null
* }
*/
final class DoctrineStore implements ProjectionStore, SchemaConfigurator
{
public function __construct(
Expand All @@ -32,7 +42,7 @@ public function get(ProjectionId $projectionId): Projection
->where('name = :name AND version = :version')
->getSQL();

/** @var array{name: string, version: int, position: int, status: string, error_message: string|null}|false $result */
/** @var Data|false $result */
$result = $this->connection->fetchAssociative($sql, [
'name' => $projectionId->name(),
'version' => $projectionId->version(),
Expand All @@ -42,12 +52,7 @@ public function get(ProjectionId $projectionId): Projection
throw new ProjectionNotFound($projectionId);
}

return new Projection(
$projectionId,
ProjectionStatus::from($result['status']),
$result['position'],
$result['error_message'],
);
return $this->createProjection($result);
}

public function all(): ProjectionCollection
Expand All @@ -57,39 +62,45 @@ public function all(): ProjectionCollection
->from($this->projectionTable)
->getSQL();

/** @var list<array{name: string, version: int, position: int, status: string, error_message: string|null, error_object: string|null}> $result */
/** @var list<Data> $result */
$result = $this->connection->fetchAllAssociative($sql);

return new ProjectionCollection(
array_map(
static function (array $data) {
return new Projection(
new ProjectionId($data['name'], $data['version']),
ProjectionStatus::from($data['status']),
$data['position'],
$data['error_message'],
ErrorSerializer::unserialize($data['error_object']),
);
},
fn (array $data) => $this->createProjection($data),
$result,
),
);
}

/** @param Data $row */
private function createProjection(array $row): Projection
{
return new Projection(
new ProjectionId($row['name'], $row['version']),
ProjectionStatus::from($row['status']),
$row['position'],
$row['error_message'] ? new ProjectionError(
$row['error_message'],
ErrorSerializer::unserialize($row['error_object']),
) : null,
);
}

public function save(Projection ...$projections): void
{
$this->connection->transactional(
function (Connection $connection) use ($projections): void {
foreach ($projections as $projection) {
$errorObject = ErrorSerializer::serialize($projection->errorObject());
$errorObject = ErrorSerializer::serialize($projection->projectionError()?->errorObject);

try {
$effectedRows = (int)$connection->update(
$this->projectionTable,
[
'position' => $projection->position(),
'status' => $projection->status()->value,
'error_message' => $projection->errorMessage(),
'error_message' => $projection->projectionError()?->errorMessage,
'error_object' => $errorObject,
],
[
Expand All @@ -109,7 +120,7 @@ function (Connection $connection) use ($projections): void {
'version' => $projection->id()->version(),
'position' => $projection->position(),
'status' => $projection->status()->value,
'error_message' => $projection->errorMessage(),
'error_message' => $projection->projectionError()?->errorMessage,
'error_object' => $errorObject,
],
);
Expand Down
5 changes: 3 additions & 2 deletions src/Projection/Projectionist/DefaultProjectionist.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Patchlevel\EventSourcing\Projection\Projection\Projection;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionCollection;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionCriteria;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionError;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionId;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionStatus;
use Patchlevel\EventSourcing\Projection\Projection\Store\ProjectionStore;
Expand Down Expand Up @@ -88,7 +89,7 @@ public function boot(
$e->getMessage(),
));

$projection->error($e);
$projection->error(ProjectionError::fromThrowable($e));
$this->projectionStore->save($projection);

if ($throwByError) {
Expand Down Expand Up @@ -400,7 +401,7 @@ private function handleMessage(Message $message, Projection $projection, bool $t
),
);

$projection->error($e);
$projection->error(ProjectionError::fromThrowable($e));
$this->projectionStore->save($projection);

if ($throwByError) {
Expand Down
6 changes: 3 additions & 3 deletions tests/Unit/Projection/Projection/ProjectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Patchlevel\EventSourcing\Tests\Unit\Projection\Projection;

use Patchlevel\EventSourcing\Projection\Projection\Projection;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionError;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionId;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionStatus;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -68,16 +69,15 @@ public function testError(): void

$exception = new RuntimeException('test');

$projection->error($exception);
$projection->error(ProjectionError::fromThrowable($exception));

self::assertEquals(ProjectionStatus::Error, $projection->status());
self::assertFalse($projection->isNew());
self::assertFalse($projection->isBooting());
self::assertFalse($projection->isActive());
self::assertTrue($projection->isError());
self::assertFalse($projection->isOutdated());
self::assertEquals('test', $projection->errorMessage());
self::assertEquals($exception, $projection->errorObject());
self::assertEquals(new ProjectionError('test', $exception), $projection->projectionError());
}

public function testOutdated(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Patchlevel\EventSourcing\Projection\Projection\Projection;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionCollection;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionCriteria;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionError;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionId;
use Patchlevel\EventSourcing\Projection\Projection\ProjectionStatus;
use Patchlevel\EventSourcing\Projection\Projection\Store\ProjectionStore;
Expand Down Expand Up @@ -255,8 +256,7 @@ public function create(): void
$projector->targetProjection(),
ProjectionStatus::Error,
0,
'ERROR',
$projector->exception,
new ProjectionError('ERROR', $projector->exception),
),
],
$projectionStore->savedProjections,
Expand Down Expand Up @@ -467,8 +467,7 @@ public function handle(Message $message): void
$projector->targetProjection(),
ProjectionStatus::Error,
0,
'ERROR',
$projector->exception,
new ProjectionError('ERROR', $projector->exception),
),
],
$projectionStore->savedProjections,
Expand Down

0 comments on commit fdd83f4

Please sign in to comment.