diff --git a/README.md b/README.md index 9947e5e..8bfdcca 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,20 @@ $writtenEvents = $client->writeEvents([ ]); ``` +#### Using the `isSubjectPopulated` precondition + +If you only want to write events in case a subject (such as `/books/42`) already has at least one event, import the `IsSubjectPopulated` class, use it to create a precondition, and pass it in an array as the second argument: + +```php +use Thenativeweb\Eventsourcingdb\IsSubjectPopulated; + +$writtenEvents = $client->writeEvents([ + // events +], [ + new IsSubjectPopulated('/books/42'), +]); +``` + #### Using the `isSubjectOnEventId` precondition If you only want to write events in case the last event of a subject (such as `/books/42`) has a specific ID (e.g., `0`), import the `IsSubjectOnEventId` class, use it to create a precondition, and pass it in an array as the second argument: diff --git a/src/IsSubjectPopulated.php b/src/IsSubjectPopulated.php new file mode 100644 index 0000000..a013ac4 --- /dev/null +++ b/src/IsSubjectPopulated.php @@ -0,0 +1,25 @@ + 'isSubjectPopulated', + 'payload' => [ + 'subject' => $this->subject, + ], + ]; + } +} diff --git a/tests/WriteEventsTest.php b/tests/WriteEventsTest.php index 3ebe392..5a24fe4 100644 --- a/tests/WriteEventsTest.php +++ b/tests/WriteEventsTest.php @@ -7,6 +7,7 @@ use Thenativeweb\Eventsourcingdb\EventCandidate; use Thenativeweb\Eventsourcingdb\IsEventQlQueryTrue; use Thenativeweb\Eventsourcingdb\IsSubjectOnEventId; +use Thenativeweb\Eventsourcingdb\IsSubjectPopulated; use Thenativeweb\Eventsourcingdb\IsSubjectPristine; use Thenativeweb\Eventsourcingdb\Tests\Trait\ClientTestTrait; @@ -104,6 +105,68 @@ public function testSupportsTheIsSubjectPristinePrecondition(): void ); } + public function testRejectsWritingToEmptySubjectWhenUsingTheIsSubjectPopulatedPrecondition(): void + { + $eventCandidate = new EventCandidate( + source: 'https://www.eventsourcingdb.io', + subject: '/test', + type: 'io.eventsourcingdb.test', + data: [ + 'value' => 42, + ], + ); + + $this->expectExceptionMessage("Failed to write events, got HTTP status code '409', expected '200'"); + + $this->client->writeEvents( + [ + $eventCandidate, + ], + [ + new IsSubjectPopulated('/test'), + ], + ); + } + + public function testSupportsTheIsSubjectPopulatedPrecondition(): void + { + $firstEvent = new EventCandidate( + source: 'https://www.eventsourcingdb.io', + subject: '/test', + type: 'io.eventsourcingdb.test', + data: [ + 'value' => 23, + ], + ); + + $secondEvent = new EventCandidate( + source: 'https://www.eventsourcingdb.io', + subject: '/test', + type: 'io.eventsourcingdb.test', + data: [ + 'value' => 42, + ], + ); + + $this->client->writeEvents([ + $firstEvent, + ]); + + $writtenEvents = $this->client->writeEvents( + [ + $secondEvent, + ], + [ + new IsSubjectPopulated('/test'), + ], + ); + + $this->assertCount(1, $writtenEvents); + $this->assertInstanceOf(CloudEvent::class, $writtenEvents[0]); + $this->assertSame('1', $writtenEvents[0]->id); + $this->assertSame(42, $writtenEvents[0]->data['value']); + } + public function testSupportsTheIsSubjectOnEventIdPrecondition(): void { $firstEvent = new EventCandidate(