Skip to content

Pass the message to apply methods of projections - #922

Open
DavidBadura wants to merge 1 commit into
4.0.xfrom
projection-apply-message
Open

DavidBadura wants to merge 1 commit into
4.0.xfrom
projection-apply-message

Conversation

@DavidBadura

Copy link
Copy Markdown
Member

Some decisions depend on metadata, like when an event was recorded. The dcb.events examples need this for the username retention period, the price grace period and the opt-in token expiry. Apply methods of a BasicProjection only got the state and the event, so there was no way to get there.

Apply methods can now take the Message as an optional third parameter:

#[Apply]
public function applyGuestIsCheckedIn(?DateTimeImmutable $state, GuestIsCheckedIn $event, Message $message): DateTimeImmutable
{
    return $message->header(RecordedOnHeader::class)->recordedOn;
}

If the third parameter has another type, the projection throws an ApplyMethodDetectionError instead of failing later with a type error.

Decisions sometimes depend on metadata, e.g. when an event was recorded
(retention periods, token expiry). Apply methods of a BasicProjection only got
the state and the event, so there was no way to reach it.

They can now take the Message as an optional third parameter. A third
parameter with a different type is reported as ApplyMethodDetectionError.
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown

Hello 👋

here is the most recent benchmark result:

SplitStreamBench
================

+-------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
|                         | time (kde mode)                                     | memory                                     |
+-------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| subject                 | Tag: <current>     | Tag: base          | time-diff | Tag: <current>  | Tag: base  | memory-diff |
+-------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| benchLoad10000Events () | 2.772ms (±0.00%)   | 3.096ms (±0.00%)   | -10.45%   | 35.774mb        | 36.295mb   | -1.43%      |
| benchSave10000Events () | 475.113ms (±0.00%) | 488.581ms (±0.00%) | -2.76%    | 35.909mb        | 35.909mb   | 0.00%       |
+-------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+

SimpleSetupTaggableStoreBench
=============================

+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
|                                        | time (kde mode)                                     | memory                                     |
+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| subject                                | Tag: <current>     | Tag: base          | time-diff | Tag: <current>  | Tag: base  | memory-diff |
+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| benchLoad1Event ()                     | 1.141ms (±0.00%)   | 1.155ms (±0.00%)   | -1.15%    | 36.312mb        | 36.312mb   | 0.00%       |
| benchLoad10000Events ()                | 75.742ms (±0.00%)  | 76.535ms (±0.00%)  | -1.04%    | 36.312mb        | 36.312mb   | 0.00%       |
| benchSave1Event ()                     | 1.585ms (±0.00%)   | 1.566ms (±0.00%)   | +1.24%    | 36.312mb        | 36.312mb   | 0.00%       |
| benchSave10000Events ()                | 311.431ms (±0.00%) | 311.911ms (±0.00%) | -0.15%    | 36.312mb        | 36.312mb   | 0.00%       |
| benchSave10000Aggregates ()            | 10.513s (±0.00%)   | 10.387s (±0.00%)   | +1.21%    | 36.312mb        | 36.312mb   | 0.00%       |
| benchSave10000AggregatesTransaction () | 7.272s (±0.00%)    | 7.292s (±0.00%)    | -0.27%    | 36.312mb        | 36.312mb   | 0.00%       |
| benchAppend1Event ()                   | 1.788ms (±0.00%)   | 1.759ms (±0.00%)   | +1.70%    | 36.312mb        | 36.312mb   | 0.00%       |
| benchAppend100Events ()                | 8.542ms (±0.00%)   | 8.602ms (±0.00%)   | -0.69%    | 36.312mb        | 36.312mb   | 0.00%       |
+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+

SubscriptionEngineBench
=======================

+---------------------------+-----------------+-----------------+-----------+-----------------+------------+-------------+
|                           | time (kde mode)                               | memory                                     |
+---------------------------+-----------------+-----------------+-----------+-----------------+------------+-------------+
| subject                   | Tag: <current>  | Tag: base       | time-diff | Tag: <current>  | Tag: base  | memory-diff |
+---------------------------+-----------------+-----------------+-----------+-----------------+------------+-------------+
| benchHandle10000Events () | 3.496s (±0.00%) | 3.495s (±0.00%) | +0.02%    | 48.301mb        | 48.301mb   | 0.00%       |
+---------------------------+-----------------+-----------------+-----------+-----------------+------------+-------------+

NoopSubscriptionEngineBench
===========================

+---------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
|                           | time (kde mode)                                     | memory                                     |
+---------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| subject                   | Tag: <current>     | Tag: base          | time-diff | Tag: <current>  | Tag: base  | memory-diff |
+---------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| benchHandle10000Events () | 111.492ms (±0.00%) | 108.791ms (±0.00%) | +2.48%    | 48.301mb        | 48.301mb   | 0.00%       |
+---------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+

SimpleSetupStreamStoreBench
===========================

+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
|                                        | time (kde mode)                                     | memory                                     |
+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| subject                                | Tag: <current>     | Tag: base          | time-diff | Tag: <current>  | Tag: base  | memory-diff |
+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| benchLoad1Event ()                     | 1.302ms (±0.00%)   | 1.298ms (±0.00%)   | +0.25%    | 35.146mb        | 35.146mb   | 0.00%       |
| benchLoad10000Events ()                | 73.283ms (±0.00%)  | 71.455ms (±0.00%)  | +2.56%    | 35.146mb        | 35.146mb   | 0.00%       |
| benchSave1Event ()                     | 1.886ms (±0.00%)   | 1.693ms (±0.00%)   | +11.41%   | 35.146mb        | 35.146mb   | 0.00%       |
| benchSave10000Events ()                | 290.741ms (±0.00%) | 291.135ms (±0.00%) | -0.14%    | 35.146mb        | 35.146mb   | 0.00%       |
| benchSave10000Aggregates ()            | 10.331s (±0.00%)   | 10.272s (±0.00%)   | +0.58%    | 35.146mb        | 35.146mb   | 0.00%       |
| benchSave10000AggregatesTransaction () | 7.204s (±0.00%)    | 7.178s (±0.00%)    | +0.36%    | 35.147mb        | 35.147mb   | 0.00%       |
+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+

SubscriptionEngineBatchBench
============================

+---------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
|                           | time (kde mode)                                     | memory                                     |
+---------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| subject                   | Tag: <current>     | Tag: base          | time-diff | Tag: <current>  | Tag: base  | memory-diff |
+---------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| benchHandle10000Events () | 112.442ms (±0.00%) | 115.794ms (±0.00%) | -2.90%    | 35.726mb        | 35.726mb   | 0.00%       |
+---------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+

PersonalDataBench
=================

+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
|                                        | time (kde mode)                                     | memory                                     |
+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| subject                                | Tag: <current>     | Tag: base          | time-diff | Tag: <current>  | Tag: base  | memory-diff |
+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+
| benchLoad1Event ()                     | 857.900μs (±0.00%) | 868.100μs (±0.00%) | -1.17%    | 37.008mb        | 37.008mb   | 0.00%       |
| benchLoad10000Events ()                | 221.029ms (±0.00%) | 221.519ms (±0.00%) | -0.22%    | 37.008mb        | 37.008mb   | -0.00%      |
| benchSave1Event ()                     | 2.321ms (±0.00%)   | 2.391ms (±0.00%)   | -2.94%    | 37.008mb        | 37.008mb   | 0.00%       |
| benchSave10000Events ()                | 474.403ms (±0.00%) | 471.363ms (±0.00%) | +0.64%    | 37.063mb        | 37.063mb   | 0.00%       |
| benchSave10000Aggregates ()            | 15.838s (±0.00%)   | 15.821s (±0.00%)   | +0.11%    | 37.008mb        | 37.008mb   | 0.00%       |
| benchSave10000AggregatesTransaction () | 12.590s (±0.00%)   | 12.628s (±0.00%)   | -0.30%    | 37.008mb        | 37.009mb   | -0.00%      |
+----------------------------------------+--------------------+--------------------+-----------+-----------------+------------+-------------+

SnapshotsBench
==============

+----------------------------------------+-------------------+-------------------+-----------+-----------------+------------+-------------+
|                                        | time (kde mode)                                   | memory                                     |
+----------------------------------------+-------------------+-------------------+-----------+-----------------+------------+-------------+
| subject                                | Tag: <current>    | Tag: base         | time-diff | Tag: <current>  | Tag: base  | memory-diff |
+----------------------------------------+-------------------+-------------------+-----------+-----------------+------------+-------------+
| benchLoad10000EventsMissingSnapshot () | 72.723ms (±0.00%) | 72.050ms (±0.00%) | +0.93%    | 35.151mb        | 35.151mb   | 0.00%       |
| benchLoad10000Events ()                | 1.111ms (±0.00%)  | 1.095ms (±0.00%)  | +1.51%    | 35.151mb        | 35.151mb   | 0.00%       |
+----------------------------------------+-------------------+-------------------+-----------+-----------------+------------+-------------+

CommandToQueryBench
===================

+----------------+------------------+------------------+-----------+-----------------+------------+-------------+
|                | time (kde mode)                                 | memory                                     |
+----------------+------------------+------------------+-----------+-----------------+------------+-------------+
| subject        | Tag: <current>   | Tag: base        | time-diff | Tag: <current>  | Tag: base  | memory-diff |
+----------------+------------------+------------------+-----------+-----------------+------------+-------------+
| benchCreate () | 3.823ms (±0.00%) | 3.908ms (±0.00%) | -2.18%    | 5.057mb         | 5.057mb    | 0.00%       |
| benchUpdate () | 5.192ms (±0.00%) | 5.238ms (±0.00%) | -0.89%    | 5.067mb         | 5.067mb    | 0.00%       |
| benchBoth ()   | 8.860ms (±0.00%) | 9.168ms (±0.00%) | -3.36%    | 5.389mb         | 5.389mb    | 0.00%       |
+----------------+------------------+------------------+-----------+-----------------+------------+-------------+

This comment gets update everytime a new commit comes in!

@DanielBadura DanielBadura left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should maybe also think about adding this to normal aggregate applies?

Comment on lines +271 to +306
```php
use Patchlevel\EventSourcing\Attribute\Apply;
use Patchlevel\EventSourcing\Identifier\Uuid;
use Patchlevel\EventSourcing\Message\Message;
use Patchlevel\EventSourcing\Projection\BasicProjection;
use Patchlevel\EventSourcing\Store\Header\RecordedOnHeader;

final class LastCheckIn extends BasicProjection
{
public function __construct(
private readonly Uuid $hotelId,
) {
}

public function initialState(): DateTimeImmutable|null
{
return null;
}

/** @return list<string> */
protected function tagFilter(): array
{
return ["hotel:{$this->hotelId->toString()}"];
}

#[Apply]
public function applyGuestIsCheckedIn(
DateTimeImmutable|null $state,
GuestIsCheckedIn $event,
Message $message,
): DateTimeImmutable {
return $message->header(RecordedOnHeader::class)->recordedOn;
}
}
```
:::

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how this will look rendered tbh :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants