diff --git a/composer.json b/composer.json index 19f1ca3..dc497c5 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "require": { "php": "^8.3", "doctrine/dbal": "^4.0", - "gember/dependency-contracts": "^0.2.1" + "gember/dependency-contracts": "^0.3" }, "require-dev": { "captainhook/captainhook": "^5.23", diff --git a/composer.lock b/composer.lock index c5d002d..6b20095 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e44de185f6349d8968fdd4ae8539ccf5", + "content-hash": "9814de873b3dfc5e942611ab268e7f99", "packages": [ { "name": "doctrine/dbal", @@ -162,16 +162,16 @@ }, { "name": "gember/dependency-contracts", - "version": "0.2.1", + "version": "0.3.0", "source": { "type": "git", "url": "https://github.com/GemberPHP/dependency-contracts.git", - "reference": "dba36626a596e8ef49c1a12ed234a4c874d335b9" + "reference": "d5dc317687f4e2f0e1c7f60159348d257ceb9f4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GemberPHP/dependency-contracts/zipball/dba36626a596e8ef49c1a12ed234a4c874d335b9", - "reference": "dba36626a596e8ef49c1a12ed234a4c874d335b9", + "url": "https://api.github.com/repos/GemberPHP/dependency-contracts/zipball/d5dc317687f4e2f0e1c7f60159348d257ceb9f4a", + "reference": "d5dc317687f4e2f0e1c7f60159348d257ceb9f4a", "shasum": "" }, "require": { @@ -212,9 +212,9 @@ ], "support": { "issues": "https://github.com/GemberPHP/dependency-contracts/issues", - "source": "https://github.com/GemberPHP/dependency-contracts/tree/0.2.1" + "source": "https://github.com/GemberPHP/dependency-contracts/tree/0.3.0" }, - "time": "2025-10-10T07:33:21+00:00" + "time": "2025-10-16T17:02:30+00:00" }, { "name": "psr/cache", diff --git a/resources/migrations/doctrine/Version20251002195234.php b/resources/migrations/doctrine/Version20251002195234.php index c8674ec..95ce560 100644 --- a/resources/migrations/doctrine/Version20251002195234.php +++ b/resources/migrations/doctrine/Version20251002195234.php @@ -12,12 +12,23 @@ public function up(Schema $schema): void $this->addSql( <<<'SQL' CREATE TABLE `saga_store` ( - `saga_id` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `id` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, `saga_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `payload` json NOT NULL, `created_at` timestamp(6) NOT NULL, `updated_at` timestamp(6) NULL DEFAULT NULL, - PRIMARY KEY (`saga_id`, `saga_name`) + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + SQL + ); + + $this->addSql( + <<<'SQL' + CREATE TABLE `saga_store_relation` ( + `id` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `saga_id` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`,`saga_id`), + CONSTRAINT `saga_store_relation_ibfk_1` FOREIGN KEY (`id`) REFERENCES `saga_store` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; SQL ); diff --git a/resources/migrations/phinx/20251002194212.php b/resources/migrations/phinx/20251002194212.php index cc79524..5b04ed5 100644 --- a/resources/migrations/phinx/20251002194212.php +++ b/resources/migrations/phinx/20251002194212.php @@ -8,8 +8,8 @@ final class V20251002194212 extends AbstractMigration { public function change(): void { - $this->table('saga_store', ['id' => false, 'primary_key' => ['saga_id', 'saga_name']]) - ->addColumn('saga_id', 'string', ['limit' => 50, 'null' => false]) + $this->table('saga_store', ['id' => false, 'primary_key' => 'id']) + ->addColumn('id', 'string', ['limit' => 50, 'null' => false]) ->addColumn('saga_name', 'string', ['null' => false]) ->addColumn('payload', 'json', ['null' => false]) ->addColumn('created_at', 'timestamp', ['limit' => 6, 'null' => false]) diff --git a/resources/migrations/phinx/20251015202332.php b/resources/migrations/phinx/20251015202332.php new file mode 100644 index 0000000..f65173b --- /dev/null +++ b/resources/migrations/phinx/20251015202332.php @@ -0,0 +1,17 @@ +table('saga_store_relation', ['id' => false, 'primary_key' => ['id', 'saga_id']]) + ->addColumn('id', 'string', ['limit' => 50, 'null' => false]) + ->addColumn('saga_id', 'string', ['limit' => 50, 'null' => false]) + ->addForeignKey('id', 'saga_store', 'id') + ->create(); + } +} diff --git a/resources/schema.sql b/resources/schema.sql index 5cd13cb..2dd90d7 100644 --- a/resources/schema.sql +++ b/resources/schema.sql @@ -16,10 +16,17 @@ CREATE TABLE `event_store_relation` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE `saga_store` ( - `saga_id` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `id` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, `saga_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, `payload` json NOT NULL, `created_at` timestamp(6) NOT NULL, `updated_at` timestamp(6) NULL DEFAULT NULL, - PRIMARY KEY (`saga_id`, `saga_name`) + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE `saga_store_relation` ( + `id` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `saga_id` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`,`saga_id`), + CONSTRAINT `saga_store_relation_ibfk_1` FOREIGN KEY (`id`) REFERENCES `saga_store` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; \ No newline at end of file diff --git a/src/Saga/DoctrineDbalRdbmsSagaFactory.php b/src/Saga/DoctrineDbalRdbmsSagaFactory.php index 42a0a1c..9cbdce9 100644 --- a/src/Saga/DoctrineDbalRdbmsSagaFactory.php +++ b/src/Saga/DoctrineDbalRdbmsSagaFactory.php @@ -21,8 +21,9 @@ public function createFromRow(array $row): RdbmsSaga { return new RdbmsSaga( + $row['id'], $row['sagaName'], - $row['sagaId'], + $row['sagaIds'], $row['payload'], new DateTimeImmutable($row['createdAt']), $row['updatedAt'] !== null ? new DateTimeImmutable($row['updatedAt']) : null, diff --git a/src/Saga/DoctrineRdbmsSagaStoreRepository.php b/src/Saga/DoctrineRdbmsSagaStoreRepository.php index 529cb31..3105a33 100644 --- a/src/Saga/DoctrineRdbmsSagaStoreRepository.php +++ b/src/Saga/DoctrineRdbmsSagaStoreRepository.php @@ -4,18 +4,23 @@ namespace Gember\RdbmsEventStoreDoctrineDbal\Saga; +use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\Connection; use Gember\DependencyContracts\EventStore\Saga\RdbmsSaga; use Gember\DependencyContracts\EventStore\Saga\RdbmsSagaStoreRepository; use Gember\DependencyContracts\EventStore\Saga\RdbmsSagaNotFoundException; +use Gember\DependencyContracts\Util\Generator\Identity\IdentityGenerator; +use Gember\RdbmsEventStoreDoctrineDbal\Saga\TableSchema\SagaStoreRelationTableSchema; use Gember\RdbmsEventStoreDoctrineDbal\Saga\TableSchema\SagaStoreTableSchema; use Override; use Stringable; use DateTimeImmutable; +use Throwable; /** * @phpstan-type SagaRow array{ - * sagaId: string, + * id: string, + * sagaIds: list, * sagaName: string, * payload: string, * createdAt: string, @@ -27,19 +32,29 @@ public function __construct( private Connection $connection, private SagaStoreTableSchema $sagaStoreTableSchema, + private SagaStoreRelationTableSchema $sagaStoreRelationTableSchema, private DoctrineDbalRdbmsSagaFactory $sagaFactory, + private IdentityGenerator $identityGenerator, ) {} #[Override] - public function get(string $sagaName, Stringable|string $sagaId): RdbmsSaga + public function get(string $sagaName, Stringable|string ...$sagaIds): RdbmsSaga { $sagaStoreSchema = $this->sagaStoreTableSchema; + $sagaStoreRelationSchema = $this->sagaStoreRelationTableSchema; - /** @var false|SagaRow $row */ + /** @var list $row */ $row = $this->connection->createQueryBuilder() ->select( <<sagaIdFieldName} as sagaId, + ss.{$sagaStoreSchema->idFieldName} as id, ss.{$sagaStoreSchema->sagaNameFieldName} as sagaName, ss.{$sagaStoreSchema->payloadFieldName} as payload, ss.{$sagaStoreSchema->createdAtFieldName} as createdAt, @@ -47,72 +62,169 @@ public function get(string $sagaName, Stringable|string $sagaId): RdbmsSaga DQL ) ->from($sagaStoreSchema->tableName, 'ss') - ->where(sprintf('ss.%s = :sagaId', $sagaStoreSchema->sagaIdFieldName)) + ->join('ss', $sagaStoreRelationSchema->tableName, 'ssr', sprintf( + 'ss.%s = ssr.%s', + $sagaStoreSchema->idFieldName, + $sagaStoreRelationSchema->idFieldName, + )) + ->where(sprintf('ssr.%s IN (:sagaIds)', $sagaStoreRelationSchema->sagaIdFieldName)) ->andWhere(sprintf('ss.%s = :sagaName', $sagaStoreSchema->sagaNameFieldName)) - ->setParameter('sagaId', (string) $sagaId) + ->setParameter( + 'sagaIds', + array_map(fn($sagaId) => (string) $sagaId, $sagaIds), + ArrayParameterType::STRING, + ) ->setParameter('sagaName', $sagaName) + ->setMaxResults(1) ->executeQuery() ->fetchAssociative(); if (!$row) { - throw RdbmsSagaNotFoundException::withSagaId($sagaName, $sagaId); + throw RdbmsSagaNotFoundException::create($sagaName, ...$sagaIds); } - return $this->sagaFactory->createFromRow($row); + $sagaIdRows = $this->connection->createQueryBuilder() + ->select( + <<sagaIdFieldName} as sagaId + DQL + ) + ->from($sagaStoreRelationSchema->tableName, 'ssr') + ->executeQuery() + ->fetchAllAssociative(); + + /** @var list $payload */ + $payload = $row; + $payload['sagaIds'] = array_map(fn($sagaIdRow) => $sagaIdRow['sagaId'], $sagaIdRows); + + return $this->sagaFactory->createFromRow($payload); } #[Override] public function save( string $sagaName, - Stringable|string $sagaId, string $payload, DateTimeImmutable $now, + Stringable|string ...$sagaIds, + ): RdbmsSaga { + try { + $previous = $this->get($sagaName, ...$sagaIds); + } catch (RdbmsSagaNotFoundException) { + return $this->create($sagaName, $payload, $now, ...$sagaIds); + } + + return $this->update($previous, $sagaName, $payload, $now, ...$sagaIds); + } + + private function create( + string $sagaName, + string $payload, + DateTimeImmutable $now, + Stringable|string ...$sagaIds, ): RdbmsSaga { + $id = $this->identityGenerator->generate(); + $sagaStoreSchema = $this->sagaStoreTableSchema; + $sagaStoreRelationSchema = $this->sagaStoreRelationTableSchema; + + $this->connection->beginTransaction(); try { - $previous = $this->get($sagaName, $sagaId); - } catch (RdbmsSagaNotFoundException) { $this->connection->createQueryBuilder() ->insert($sagaStoreSchema->tableName) - ->setValue($sagaStoreSchema->sagaIdFieldName, ':sagaId') + ->setValue($sagaStoreSchema->idFieldName, ':id') ->setValue($sagaStoreSchema->sagaNameFieldName, ':sagaName') ->setValue($sagaStoreSchema->payloadFieldName, ':payload') ->setValue($sagaStoreSchema->createdAtFieldName, ':createdAt') ->setParameters([ - 'sagaId' => $sagaId, + 'id' => $id, 'sagaName' => $sagaName, 'payload' => $payload, 'createdAt' => $now->format($sagaStoreSchema->createdAtFieldFormat), ]) ->executeStatement(); - return new RdbmsSaga( - $sagaName, - $sagaId, - $payload, - $now, - null, - ); + foreach ($sagaIds as $sagaId) { + $this->connection->createQueryBuilder() + ->insert($sagaStoreRelationSchema->tableName) + ->setValue($sagaStoreRelationSchema->idFieldName, ':id') + ->setValue($sagaStoreRelationSchema->sagaIdFieldName, ':sagaId') + ->setParameters([ + 'id' => $id, + 'sagaId' => $sagaId, + ]) + ->executeStatement(); + } + + $this->connection->commit(); + } catch (Throwable $exception) { + $this->connection->rollBack(); + + throw $exception; } - $this->connection->createQueryBuilder() - ->update($sagaStoreSchema->tableName) - ->where(sprintf('%s = :sagaId', $sagaStoreSchema->sagaIdFieldName)) - ->andWhere(sprintf('%s = :sagaName', $sagaStoreSchema->sagaNameFieldName)) - ->set($sagaStoreSchema->payloadFieldName, ':payload') - ->set($sagaStoreSchema->updatedAtFieldName, ':updatedAt') - ->setParameters([ - 'sagaId' => $sagaId, - 'sagaName' => $sagaName, - 'payload' => $payload, - 'updatedAt' => $now->format($sagaStoreSchema->updatedAtFieldFormat), - ]) - ->executeStatement(); + return new RdbmsSaga( + $id, + $sagaName, + array_values($sagaIds), + $payload, + $now, + null, + ); + } + + private function update( + RdbmsSaga $previous, + string $sagaName, + string $payload, + DateTimeImmutable $now, + Stringable|string ...$sagaIds, + ): RdbmsSaga { + $sagaStoreSchema = $this->sagaStoreTableSchema; + $sagaStoreRelationSchema = $this->sagaStoreRelationTableSchema; + + $this->connection->beginTransaction(); + + try { + $this->connection->createQueryBuilder() + ->update($sagaStoreSchema->tableName) + ->where(sprintf('%s = :id', $sagaStoreSchema->idFieldName)) + ->set($sagaStoreSchema->payloadFieldName, ':payload') + ->set($sagaStoreSchema->updatedAtFieldName, ':updatedAt') + ->setParameter('id', $previous->id) + ->setParameter('payload', $payload) + ->setParameter('updatedAt', $now->format($sagaStoreSchema->updatedAtFieldFormat)) + ->executeStatement(); + + $this->connection->createQueryBuilder() + ->delete($sagaStoreRelationSchema->tableName) + ->where(sprintf('%s = :id', $sagaStoreRelationSchema->idFieldName)) + ->setParameter('id', $previous->id) + ->executeStatement(); + + foreach ($sagaIds as $sagaId) { + $this->connection->createQueryBuilder() + ->insert($sagaStoreRelationSchema->tableName) + ->setValue($sagaStoreRelationSchema->idFieldName, ':id') + ->setValue($sagaStoreRelationSchema->sagaIdFieldName, ':sagaId') + ->setParameters([ + 'id' => $previous->id, + 'sagaId' => $sagaId, + ]) + ->executeStatement(); + } + + $this->connection->commit(); + } catch (Throwable $exception) { + $this->connection->rollBack(); + + throw $exception; + } return new RdbmsSaga( + $previous->id, $sagaName, - $sagaId, + array_values($sagaIds), $payload, $previous->createdAt, $now, diff --git a/src/Saga/TableSchema/SagaStoreRelationTableSchema.php b/src/Saga/TableSchema/SagaStoreRelationTableSchema.php new file mode 100644 index 0000000..69da234 --- /dev/null +++ b/src/Saga/TableSchema/SagaStoreRelationTableSchema.php @@ -0,0 +1,14 @@ +createFromRow([ + 'id' => '01K7Q14MMW2FQP2JS1RHQS7QXP', 'sagaName' => 'some.saga', - 'sagaId' => '01K76G1PGKPZ047KDN25PFPEEV', + 'sagaIds' => ['01K76G1PGKPZ047KDN25PFPEEV', '01K7Q13CG3A3PQCC98XYSE67K1'], 'payload' => '{"some":"data"}', 'createdAt' => '2018-12-01 12:05:08.234543', 'updatedAt' => null, ]); + self::assertSame('01K7Q14MMW2FQP2JS1RHQS7QXP', $saga->id); self::assertSame('some.saga', $saga->sagaName); - self::assertSame('01K76G1PGKPZ047KDN25PFPEEV', $saga->sagaId); + self::assertSame(['01K76G1PGKPZ047KDN25PFPEEV', '01K7Q13CG3A3PQCC98XYSE67K1'], $saga->sagaIds); self::assertSame('{"some":"data"}', $saga->payload); self::assertEquals(new DateTimeImmutable('2018-12-01 12:05:08.234543'), $saga->createdAt); self::assertNull($saga->updatedAt); diff --git a/tests/Saga/DoctrineRdbmsSagaStoreRepositoryTest.php b/tests/Saga/DoctrineRdbmsSagaStoreRepositoryTest.php index 4ff4bbf..72b75e6 100644 --- a/tests/Saga/DoctrineRdbmsSagaStoreRepositoryTest.php +++ b/tests/Saga/DoctrineRdbmsSagaStoreRepositoryTest.php @@ -10,6 +10,7 @@ use Gember\RdbmsEventStoreDoctrineDbal\Saga\DoctrineDbalRdbmsSagaFactory; use Gember\RdbmsEventStoreDoctrineDbal\Saga\DoctrineRdbmsSagaStoreRepository; use Gember\RdbmsEventStoreDoctrineDbal\Saga\TableSchema\SagaTableSchemaFactory; +use Gember\RdbmsEventStoreDoctrineDbal\Test\TestDoubles\TestIdentityGenerator; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use Override; @@ -21,6 +22,7 @@ final class DoctrineRdbmsSagaStoreRepositoryTest extends TestCase { private DoctrineRdbmsSagaStoreRepository $repository; + private TestIdentityGenerator $identityGenerator; #[Override] protected function setUp(): void @@ -33,7 +35,9 @@ protected function setUp(): void $this->repository = new DoctrineRdbmsSagaStoreRepository( $connection, SagaTableSchemaFactory::createDefaultSagaStore(), + SagaTableSchemaFactory::createDefaultSagaStoreRelation(), new DoctrineDbalRdbmsSagaFactory(), + $this->identityGenerator = new TestIdentityGenerator(), ); } @@ -48,17 +52,21 @@ public function itShouldThrowExceptionWhenSagaNotFound(): void #[Test] public function itShouldSaveAndGetSaga(): void { + $this->identityGenerator->ids[] = '01K7Q083CX4T7Z0NT5CKEX8NEJ'; + $this->repository->save( 'some.saga', - '01K76GDQ5RT71G7HQVNR264KD4', '{"some":"data"}', new DateTimeImmutable('2025-10-10 12:00:34'), + '01K76GDQ5RT71G7HQVNR264KD4', + '01K7Q033P5174AXA054FFAHW2F', ); $saga = $this->repository->get('some.saga', '01K76GDQ5RT71G7HQVNR264KD4'); + self::assertSame('01K7Q083CX4T7Z0NT5CKEX8NEJ', $saga->id); self::assertSame('some.saga', $saga->sagaName); - self::assertSame('01K76GDQ5RT71G7HQVNR264KD4', $saga->sagaId); + self::assertSame(['01K76GDQ5RT71G7HQVNR264KD4', '01K7Q033P5174AXA054FFAHW2F'], $saga->sagaIds); self::assertSame('{"some":"data"}', $saga->payload); self::assertEquals(new DateTimeImmutable('2025-10-10 12:00:34'), $saga->createdAt); self::assertNull($saga->updatedAt); @@ -67,24 +75,29 @@ public function itShouldSaveAndGetSaga(): void #[Test] public function itShouldSaveExistingSaga(): void { + $this->identityGenerator->ids[] = '01K7Q083CX4T7Z0NT5CKEX8NEJ'; + $this->repository->save( 'some.saga', - '01K76GDQ5RT71G7HQVNR264KD4', '{"some":"data"}', new DateTimeImmutable('2025-10-10 12:00:34'), + '01K76GDQ5RT71G7HQVNR264KD4', + '01K7Q0GR8ABHBZG8QCGTXJXJ7T', ); $this->repository->save( 'some.saga', - '01K76GDQ5RT71G7HQVNR264KD4', '{"some":"updated"}', new DateTimeImmutable('2025-10-10 13:30:12'), + '01K76GDQ5RT71G7HQVNR264KD4', + '01K7Q0JGY9ZMX11K75AAY5J78R', ); $saga = $this->repository->get('some.saga', '01K76GDQ5RT71G7HQVNR264KD4'); + self::assertSame('01K7Q083CX4T7Z0NT5CKEX8NEJ', $saga->id); self::assertSame('some.saga', $saga->sagaName); - self::assertSame('01K76GDQ5RT71G7HQVNR264KD4', $saga->sagaId); + self::assertSame(['01K76GDQ5RT71G7HQVNR264KD4', '01K7Q0JGY9ZMX11K75AAY5J78R'], $saga->sagaIds); self::assertSame('{"some":"updated"}', $saga->payload); self::assertEquals(new DateTimeImmutable('2025-10-10 12:00:34'), $saga->createdAt); self::assertEquals(new DateTimeImmutable('2025-10-10 13:30:12'), $saga->updatedAt); diff --git a/tests/Saga/TableSchema/SagaTableSchemaFactoryTest.php b/tests/Saga/TableSchema/SagaTableSchemaFactoryTest.php index 9c8aacf..bf7c11a 100644 --- a/tests/Saga/TableSchema/SagaTableSchemaFactoryTest.php +++ b/tests/Saga/TableSchema/SagaTableSchemaFactoryTest.php @@ -14,12 +14,12 @@ final class SagaTableSchemaFactoryTest extends TestCase { #[Test] - public function itShouldCreateDefaultEventStoreTableSchema(): void + public function itShouldCreateDefaultSagaStoreTableSchema(): void { $schema = SagaTableSchemaFactory::createDefaultSagaStore(); self::assertSame('saga_store', $schema->tableName); - self::assertSame('saga_id', $schema->sagaIdFieldName); + self::assertSame('id', $schema->idFieldName); self::assertSame('saga_name', $schema->sagaNameFieldName); self::assertSame('payload', $schema->payloadFieldName); self::assertSame('created_at', $schema->createdAtFieldName); @@ -29,11 +29,11 @@ public function itShouldCreateDefaultEventStoreTableSchema(): void } #[Test] - public function itShouldCreateCustomEventStoreTableSchema(): void + public function itShouldCreateCustomSagaStoreTableSchema(): void { $schema = SagaTableSchemaFactory::createDefaultSagaStore( 'custom_saga_store', - 'custom_saga_id', + 'custom_id', 'custom_saga_name', 'custom_payload', 'custom_created_at', @@ -43,7 +43,7 @@ public function itShouldCreateCustomEventStoreTableSchema(): void ); self::assertSame('custom_saga_store', $schema->tableName); - self::assertSame('custom_saga_id', $schema->sagaIdFieldName); + self::assertSame('custom_id', $schema->idFieldName); self::assertSame('custom_saga_name', $schema->sagaNameFieldName); self::assertSame('custom_payload', $schema->payloadFieldName); self::assertSame('custom_created_at', $schema->createdAtFieldName); @@ -51,4 +51,28 @@ public function itShouldCreateCustomEventStoreTableSchema(): void self::assertSame('custom_updated_at', $schema->updatedAtFieldName); self::assertSame('custom_updated_at_format', $schema->updatedAtFieldFormat); } + + #[Test] + public function itShouldCreateDefaultSagaStoreRelationTableSchema(): void + { + $schema = SagaTableSchemaFactory::createDefaultSagaStoreRelation(); + + self::assertSame('saga_store_relation', $schema->tableName); + self::assertSame('id', $schema->idFieldName); + self::assertSame('saga_id', $schema->sagaIdFieldName); + } + + #[Test] + public function itShouldCreateCustomSagaStoreRelationTableSchema(): void + { + $schema = SagaTableSchemaFactory::createDefaultSagaStoreRelation( + 'custom_saga_store', + 'custom_id', + 'custom_saga_id', + ); + + self::assertSame('custom_saga_store', $schema->tableName); + self::assertSame('custom_id', $schema->idFieldName); + self::assertSame('custom_saga_id', $schema->sagaIdFieldName); + } } diff --git a/tests/TestDoubles/TestIdentityGenerator.php b/tests/TestDoubles/TestIdentityGenerator.php new file mode 100644 index 0000000..3e6fc90 --- /dev/null +++ b/tests/TestDoubles/TestIdentityGenerator.php @@ -0,0 +1,22 @@ + + */ + public array $ids = []; + + #[Override] + public function generate(): string + { + return (string) array_shift($this->ids); + } +} diff --git a/tests/schema.sql b/tests/schema.sql index 1ef9736..f0d9f96 100644 --- a/tests/schema.sql +++ b/tests/schema.sql @@ -12,9 +12,14 @@ CREATE TABLE `event_store_relation` ( ); CREATE TABLE `saga_store` ( - `saga_id` varchar(50), + `id` varchar(50), `saga_name` varchar(255), `payload` json NOT NULL, `created_at` timestamp(6) NOT NULL, `updated_at` timestamp(6) NULL DEFAULT NULL +); + +CREATE TABLE `saga_store_relation` ( + `id` varchar(50) NOT NULL, + `saga_id` varchar(50) NOT NULL ); \ No newline at end of file