Skip to content

Commit

Permalink
add option-type approach for result handling
Browse files Browse the repository at this point in the history
  • Loading branch information
yceruto committed Aug 5, 2024
1 parent 402b828 commit 2971735
Show file tree
Hide file tree
Showing 14 changed files with 60 additions and 33 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"php": ">=8.2",
"psr/container": "^2.0",
"psr/log": "^3.0",
"symfony/service-contracts": "^3.4"
"symfony/service-contracts": "^3.4",
"yceruto/option-type": "^1.0"
},
"require-dev": {
"vimeo/psalm": "^5.0",
Expand Down
14 changes: 9 additions & 5 deletions src/Envelope/Envelope.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

use OpenSolid\Bus\Envelope\Stamp\HandledStamp;
use OpenSolid\Bus\Envelope\Stamp\Stamps;
use Std\Type\None;
use Std\Type\Option;
use Std\Type\Some;

/**
* A message envelope that wraps a message and its stamps.
Expand All @@ -33,16 +36,17 @@ public static function wrap(Message $message, array $stamps = []): self
return new self($message, $stamps);
}

public function unwrap(): mixed
public function unwrap(): Option
{
$results = $this->stamps
->filter(HandledStamp::class, fn (HandledStamp $stamp): bool => null !== $stamp->result)
->map(HandledStamp::class, fn (HandledStamp $stamp): mixed => $stamp->result);
->map(HandledStamp::class, fn (HandledStamp $stamp): mixed => $stamp->result)
;

return match (\count($results)) {
0 => null,
1 => $results[0],
default => $results,
0 => new None(),
1 => new Some($results[0]),
default => new Some($results),
};
}

Expand Down
19 changes: 12 additions & 7 deletions src/Envelope/Stamp/Stamps.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@

namespace OpenSolid\Bus\Envelope\Stamp;

use Std\Type\None;
use Std\Type\Option;
use Std\Type\OptionFactory;
use Std\Type\Some;

/**
* A collection of stamps.
*
Expand Down Expand Up @@ -53,25 +58,25 @@ public function has(string $class): bool
/**
* @param class-string<T> $class
*
* @return T|null
* @return None|Some<T>
*/
public function first(string $class): ?Stamp
public function first(string $class): None|Some
{
return $this->collection[$class][0] ?? null;
return OptionFactory::from($this->collection[$class][0] ?? null);
}

/**
* @param class-string<T> $class
*
* @return T|null
* @return None|Some<T>
*/
public function last(string $class): ?Stamp
public function last(string $class): Option
{
if ([] === $stamps = $this->collection[$class] ?? []) {
return null;
return new None();
}

return $this->collection[$class][\count($stamps) - 1];
return new Some($this->collection[$class][\count($stamps) - 1]);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/LazyMessageBus.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
namespace OpenSolid\Bus;

use OpenSolid\Bus\Envelope\Message;
use Std\Type\None;

/**
* A bus responsible for dispatching messages lazily to their handlers.
* The messages are stored in an internal queue and dispatched when the bus is flushed.
*/
interface LazyMessageBus extends MessageBus, FlushableMessageBus
{
public function dispatch(Message $message): null;
public function dispatch(Message $message): None;
}
3 changes: 2 additions & 1 deletion src/MessageBus.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
namespace OpenSolid\Bus;

use OpenSolid\Bus\Envelope\Message;
use Std\Type\Option;

/**
* A bus responsible for dispatching messages to their handlers
* and returning a result.
*/
interface MessageBus
{
public function dispatch(Message $message): mixed;
public function dispatch(Message $message): Option;
}
5 changes: 3 additions & 2 deletions src/NativeLazyMessageBus.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace OpenSolid\Bus;

use OpenSolid\Bus\Envelope\Message;
use Std\Type\None;
use Symfony\Contracts\Service\ResetInterface;

final class NativeLazyMessageBus implements LazyMessageBus, ResetInterface
Expand All @@ -25,11 +26,11 @@ public function __construct(
) {
}

public function dispatch(Message $message): null
public function dispatch(Message $message): None
{
$this->messages[] = $message;

return null;
return new None();
}

public function flush(): void
Expand Down
3 changes: 2 additions & 1 deletion src/NativeMessageBus.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use OpenSolid\Bus\Envelope\Message;
use OpenSolid\Bus\Middleware\Middleware;
use OpenSolid\Bus\Middleware\MiddlewareStack;
use Std\Type\Option;

final readonly class NativeMessageBus implements MessageBus
{
Expand All @@ -30,7 +31,7 @@ public function __construct(iterable $middlewares)
$this->middlewares = new MiddlewareStack($middlewares);
}

public function dispatch(Message $message): mixed
public function dispatch(Message $message): Option
{
$envelope = Envelope::wrap($message);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public function testMultipleMessageHandlingProcess(): void
$middleware = $container->get('handling_middleware');
$middleware->handle($envelope, new NoneMiddleware());

$this->assertIsArray($envelope->unwrap());
$this->assertCount(2, $envelope->unwrap());
$this->assertTrue($envelope->unwrap()->isSome());
$this->assertCount(2, $envelope->unwrap()->unwrap());
}

public function testInvalidSingleMessageHandlingProcess(): void
Expand Down
14 changes: 9 additions & 5 deletions tests/Envelope/EnvelopeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,29 @@ public function testNullResult(): void
{
$envelope = Envelope::wrap(new MyMessage());

$this->assertNull($envelope->unwrap());
$result = $envelope->unwrap();

$this->assertTrue($result->isNone());
}

public function testSingleResult(): void
{
$envelope = Envelope::wrap(new MyMessage());

$envelope->stamps->add(new HandledStamp(true));

$this->assertTrue($envelope->unwrap());
$result = $envelope->unwrap();

$this->assertTrue($result->isSome());
}

public function testMultipleResults(): void
{
$envelope = Envelope::wrap(new MyMessage());

$envelope->stamps->add(new HandledStamp(true));
$envelope->stamps->add(new HandledStamp(false));

$this->assertSame([true, false], $envelope->unwrap());
$result = $envelope->unwrap();

$this->assertSame([true, false], $result->unwrap());
}
}
8 changes: 4 additions & 4 deletions tests/Envelope/Stamp/StampsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public function testFirst(): void

$first = $stamps->first(HandledStamp::class);

$this->assertNotNull($first);
$this->assertTrue($first->result);
$this->assertNotNull($first->unwrap());
$this->assertTrue($first->unwrap()->result);
}

public function testLast(): void
Expand All @@ -63,8 +63,8 @@ public function testLast(): void

$last = $stamps->last(HandledStamp::class);

$this->assertNotNull($last);
$this->assertFalse($last->result);
$this->assertNotNull($last->unwrap());
$this->assertFalse($last->unwrap()->result);
}

public function testFilter(): void
Expand Down
4 changes: 3 additions & 1 deletion tests/Middleware/HandlingMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ public function testHandle(): void
$envelop = Envelope::wrap($message);
$middleware->handle($envelop, new NoneMiddleware());

$this->assertSame($message, $envelop->unwrap());
$result = $envelop->unwrap();

$this->assertSame($message, $result->unwrap());
}

public function testNoHandlerForObject(): void
Expand Down
4 changes: 3 additions & 1 deletion tests/Middleware/MiddlewareStackTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public function handle(Envelope $envelope, NextMiddleware $next): void
$envelope = Envelope::wrap(new MyMessage());
$stack->handle($envelope);

$this->assertSame(['1', '2', '3'], $envelope->unwrap());
$result = $envelope->unwrap();

$this->assertSame(['1', '2', '3'], $result->unwrap());
}
}
4 changes: 3 additions & 1 deletion tests/NativeLazyMessageBusTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public function testLazyDispatchingDoNotHandleImmediately(): void

$bus = new NativeLazyMessageBus(new NativeMessageBus([$middleware]));

$this->assertNull($bus->dispatch(new MyMessage()));
$result = $bus->dispatch(new MyMessage());

$this->assertTrue($result->isNone());
}

public function testLazyDispatchingHandleWhenFlush(): void
Expand Down
5 changes: 4 additions & 1 deletion tests/NativeMessageBusTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public function testDispatch(): void
]);
$message = new MyMessage();

$this->assertSame($message, $bus->dispatch($message));
$result = $bus->dispatch($message);

$this->assertTrue($result->isSome());
$this->assertSame($message, $result->unwrap());
}
}

0 comments on commit 2971735

Please sign in to comment.