diff --git a/src/DoctrineMessageRepository/DefaultDoctrineMessageRepositoryTest.php b/src/DoctrineMessageRepository/DefaultDoctrineMessageRepositoryTest.php index fff2e16..bfc3ef7 100644 --- a/src/DoctrineMessageRepository/DefaultDoctrineMessageRepositoryTest.php +++ b/src/DoctrineMessageRepository/DefaultDoctrineMessageRepositoryTest.php @@ -5,9 +5,12 @@ use EventSauce\IdEncoding\BinaryUuidIdEncoder; use EventSauce\EventSourcing\Serialization\ConstructingMessageSerializer; use EventSauce\MessageRepository\TableSchema\DefaultTableSchema; +use EventSauce\MessageRepository\TestTooling\BinaryUuidTestTrait; class DefaultDoctrineMessageRepositoryTest extends DoctrineMessageRepositoryTestCase { + use BinaryUuidTestTrait; + protected string $tableName = 'domain_messages_uuid'; protected function messageRepository(): DoctrineMessageRepository diff --git a/src/DoctrineMessageRepository/DefaultDoctrineUuidV4MessageRepositoryTest.php b/src/DoctrineMessageRepository/DefaultDoctrineUuidV4MessageRepositoryTest.php index 09ad35b..831abb1 100644 --- a/src/DoctrineMessageRepository/DefaultDoctrineUuidV4MessageRepositoryTest.php +++ b/src/DoctrineMessageRepository/DefaultDoctrineUuidV4MessageRepositoryTest.php @@ -4,10 +4,13 @@ use EventSauce\EventSourcing\Serialization\ConstructingMessageSerializer; use EventSauce\MessageRepository\TableSchema\DefaultTableSchema; +use EventSauce\MessageRepository\TestTooling\BinaryUuidTestTrait; use EventSauce\UuidEncoding\BinaryUuidEncoder; class DefaultDoctrineUuidV4MessageRepositoryTest extends DoctrineMessageRepositoryTestCase { + use BinaryUuidTestTrait; + protected string $tableName = 'domain_messages_uuid'; protected function messageRepository(): DoctrineUuidV4MessageRepository diff --git a/src/DoctrineMessageRepository/DoctrineMessageRepository.php b/src/DoctrineMessageRepository/DoctrineMessageRepository.php index 8b8fcca..c2b6a00 100644 --- a/src/DoctrineMessageRepository/DoctrineMessageRepository.php +++ b/src/DoctrineMessageRepository/DoctrineMessageRepository.php @@ -3,6 +3,7 @@ namespace EventSauce\MessageRepository\DoctrineMessageRepository; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Query\QueryBuilder; use EventSauce\IdEncoding\BinaryUuidIdEncoder; use EventSauce\IdEncoding\IdEncoder; @@ -36,6 +37,8 @@ class DoctrineMessageRepository implements MessageRepository private TableSchema $tableSchema; private IdEncoder $aggregateRootIdEncoder; private IdEncoder $eventIdEncoder; + private bool $binaryAggregateRootId; + private bool $binaryEventId; public function __construct( private Connection $connection, @@ -50,6 +53,9 @@ public function __construct( $this->tableSchema = $tableSchema ?? new DefaultTableSchema(); $this->aggregateRootIdEncoder = $aggregateRootIdEncoder ?? new BinaryUuidIdEncoder(); $this->eventIdEncoder = $eventIdEncoder ?? $this->aggregateRootIdEncoder; + + $this->binaryAggregateRootId = $this->aggregateRootIdEncoder instanceof BinaryUuidIdEncoder; + $this->binaryEventId = $this->eventIdEncoder instanceof BinaryUuidIdEncoder; } public function persist(Message ...$messages): void @@ -73,9 +79,11 @@ public function persist(Message ...$messages): void $payload = $this->serializer->serializeMessage($message); $payload['headers'][Header::EVENT_ID] ??= Uuid::uuid4()->toString(); + $eventIdIndex = $this->indexParameter('event_id', $index); + $aggregateRootIdIndex = $this->indexParameter('aggregate_root_id', $index); $messageParameters = [ - $this->indexParameter('event_id', $index) => $this->eventIdEncoder->encodeId($payload['headers'][Header::EVENT_ID]), - $this->indexParameter('aggregate_root_id', $index) => $this->aggregateRootIdEncoder->encodeId($message->aggregateRootId()), + $eventIdIndex => $this->eventIdEncoder->encodeId($payload['headers'][Header::EVENT_ID]), + $aggregateRootIdIndex => $this->aggregateRootIdEncoder->encodeId($message->aggregateRootId()), $this->indexParameter('version', $index) => $payload['headers'][Header::AGGREGATE_ROOT_VERSION] ?? 0, $this->indexParameter('payload', $index) => json_encode($payload, $this->jsonEncodeOptions), ]; @@ -98,8 +106,16 @@ public function persist(Message ...$messages): void implode("),\n(", $insertValues), ); + $types = []; + if ($this->binaryEventId) { + $types[$eventIdIndex] = ParameterType::BINARY; + } + if ($this->binaryAggregateRootId) { + $types[$aggregateRootIdIndex] = ParameterType::BINARY; + } + try { - $this->connection->executeStatement($insertQuery, $insertParameters); + $this->connection->executeStatement($insertQuery, $insertParameters, $types); } catch (Throwable $exception) { throw UnableToPersistMessages::dueTo('', $exception); } @@ -119,7 +135,7 @@ public function retrieveAll(AggregateRootId $id): Generator { $builder = $this->createQueryBuilder(); $builder->where(sprintf('%s = :aggregate_root_id', $this->tableSchema->aggregateRootIdColumn())); - $builder->setParameter('aggregate_root_id', $this->aggregateRootIdEncoder->encodeId($id)); + $builder->setParameter('aggregate_root_id', $this->aggregateRootIdEncoder->encodeId($id), $this->binaryAggregateRootId ? ParameterType::BINARY : ParameterType::STRING); try { return $this->yieldMessagesFromPayloads($builder->executeQuery()->iterateColumn()); @@ -136,7 +152,7 @@ public function retrieveAllAfterVersion(AggregateRootId $id, int $aggregateRootV $builder = $this->createQueryBuilder(); $builder->where(sprintf('%s = :aggregate_root_id', $this->tableSchema->aggregateRootIdColumn())); $builder->andWhere(sprintf('%s > :version', $this->tableSchema->versionColumn())); - $builder->setParameter('aggregate_root_id', $this->aggregateRootIdEncoder->encodeId($id)); + $builder->setParameter('aggregate_root_id', $this->aggregateRootIdEncoder->encodeId($id), $this->binaryAggregateRootId ? ParameterType::BINARY : ParameterType::STRING); $builder->setParameter('version', $aggregateRootVersion); try { diff --git a/src/DoctrineMessageRepository/DoctrineUuidV4MessageRepository.php b/src/DoctrineMessageRepository/DoctrineUuidV4MessageRepository.php index e9311b7..0d4006d 100644 --- a/src/DoctrineMessageRepository/DoctrineUuidV4MessageRepository.php +++ b/src/DoctrineMessageRepository/DoctrineUuidV4MessageRepository.php @@ -3,6 +3,7 @@ namespace EventSauce\MessageRepository\DoctrineMessageRepository; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Query\QueryBuilder; use EventSauce\EventSourcing\AggregateRootId; use EventSauce\EventSourcing\Header; @@ -74,9 +75,11 @@ public function persist(Message ...$messages): void $payload = $this->serializer->serializeMessage($message); $payload['headers'][Header::EVENT_ID] ??= Uuid::uuid4()->toString(); + $eventIdIndex = $this->indexParameter('event_id', $index); + $aggregateRootIdIndex = $this->indexParameter('aggregate_root_id', $index); $messageParameters = [ - $this->indexParameter('event_id', $index) => $this->uuidEncoder->encodeString($payload['headers'][Header::EVENT_ID]), - $this->indexParameter('aggregate_root_id', $index) => $this->uuidEncoder->encodeString($payload['headers'][Header::AGGREGATE_ROOT_ID]), + $eventIdIndex => $this->uuidEncoder->encodeString($payload['headers'][Header::EVENT_ID]), + $aggregateRootIdIndex => $this->uuidEncoder->encodeString($payload['headers'][Header::AGGREGATE_ROOT_ID]), $this->indexParameter('version', $index) => $payload['headers'][Header::AGGREGATE_ROOT_VERSION] ?? 0, $this->indexParameter('payload', $index) => json_encode($payload, $this->jsonEncodeOptions), ]; @@ -99,8 +102,16 @@ public function persist(Message ...$messages): void implode("),\n(", $insertValues), ); + $types = []; + if ($this->uuidEncoder instanceof BinaryUuidEncoder) { + $types = [ + $eventIdIndex => ParameterType::BINARY, + $aggregateRootIdIndex => ParameterType::BINARY, + ]; + } + try { - $this->connection->executeStatement($insertQuery, $insertParameters); + $this->connection->executeStatement($insertQuery, $insertParameters, $types); } catch (Throwable $exception) { throw UnableToPersistMessages::dueTo('', $exception); } @@ -120,7 +131,7 @@ public function retrieveAll(AggregateRootId $id): Generator { $builder = $this->createQueryBuilder(); $builder->where(sprintf('%s = :aggregate_root_id', $this->tableSchema->aggregateRootIdColumn())); - $builder->setParameter('aggregate_root_id', $this->uuidEncoder->encodeString($id->toString())); + $builder->setParameter('aggregate_root_id', $this->uuidEncoder->encodeString($id->toString()), $this->uuidEncoder instanceof BinaryUuidEncoder ? ParameterType::BINARY : ParameterType::STRING); try { return $this->yieldMessagesFromPayloads($builder->executeQuery()->iterateColumn()); @@ -137,7 +148,7 @@ public function retrieveAllAfterVersion(AggregateRootId $id, int $aggregateRootV $builder = $this->createQueryBuilder(); $builder->where(sprintf('%s = :aggregate_root_id', $this->tableSchema->aggregateRootIdColumn())); $builder->andWhere(sprintf('%s > :version', $this->tableSchema->versionColumn())); - $builder->setParameter('aggregate_root_id', $this->uuidEncoder->encodeString($id->toString())); + $builder->setParameter('aggregate_root_id', $this->uuidEncoder->encodeString($id->toString()), $this->uuidEncoder instanceof BinaryUuidEncoder ? ParameterType::BINARY : ParameterType::STRING); $builder->setParameter('version', $aggregateRootVersion); try { diff --git a/src/MessageRepositoryTestTooling/BinaryUuidTestTrait.php b/src/MessageRepositoryTestTooling/BinaryUuidTestTrait.php new file mode 100644 index 0000000..f45df59 --- /dev/null +++ b/src/MessageRepositoryTestTooling/BinaryUuidTestTrait.php @@ -0,0 +1,36 @@ +=8.4 to have PDO use binary hints'); + } + + $repository = $this->messageRepository(); + $message = $this->createMessage('payload'); + + $repository->persist($message); + $this->assertWarnings('persist()'); + + $repository->retrieveAll($message->aggregateRootId()); + $this->assertWarnings('retrieveAll()'); + + $repository->retrieveAllAfterVersion($message->aggregateRootId(), 1); + $this->assertWarnings('retrieveAllAfterVersion()'); + } + + private function assertWarnings(string $scenario): void + { + $warnings = $this->connection->executeQuery('SHOW WARNINGS')->fetchAllAssociative(); + self::assertSame([], $warnings, 'Binary uuids were not properly passed during ' . $scenario); + } +}