Skip to content

Commit

Permalink
add support for PostgreSQL
Browse files Browse the repository at this point in the history
  • Loading branch information
bendavies committed Oct 4, 2022
1 parent 3f7d1c7 commit 885a1df
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 28 deletions.
54 changes: 52 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ jobs:
- name: "Run vimeo/psalm"
run: vendor/bin/psalm --diff --show-info=false --stats --threads=4

tests:
name: "Tests"
tests-mariadb:
name: "Tests with MariaDB"

runs-on: "ubuntu-latest"

Expand Down Expand Up @@ -105,3 +105,53 @@ jobs:
run: vendor/bin/simple-phpunit
env:
TEST_DATABASE_DSN: mysql://root:[email protected]:${{ job.services.mariadb.ports[3306] }}/messenger_monitor_bundle_test

tests-postgres:
name: "Tests with PostgreSQL"

runs-on: "ubuntu-latest"

strategy:
fail-fast: false
matrix:
php:
- "8.0"
- "8.1"
postgres-version:
- "9.4"
- "13"
- "14"
dependencies:
- "lowest"
- "highest"

services:
postgres:
image: "postgres:${{ matrix.postgres-version }}"
ports:
- "5432:5432"
env:
POSTGRES_DB: messenger_monitor_bundle_test
POSTGRES_USER: user
POSTGRES_PASSWORD: password
options: --health-cmd "pg_isready -U user" --health-interval 1s --health-timeout 5s --health-retries 5

steps:
- name: "Checkout"
uses: actions/checkout@v3

- name: "Set up PHP"
uses: shivammathur/setup-php@v2
with:
coverage: none
php-version: ${{ matrix.php }}

- name: "Install dependencies with composer"
uses: ramsey/composer-install@v2
with:
dependency-versions: ${{ matrix.dependencies }}

- name: "Unit Tests"
run: vendor/bin/simple-phpunit
env:
TEST_DATABASE_DSN: postgres://user:[email protected]:${{ job.services.postgres.ports[5432] }}/messenger_monitor_bundle_test
12 changes: 6 additions & 6 deletions src/Storage/Doctrine/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ public function getStatistics(\DateTimeImmutable $fromDate, \DateTimeImmutable $
{
$statement = $this->executeQuery(
$this->driverConnection->createQueryBuilder()
->select('count(id) as countMessagesOnPeriod, class')
->addSelect(sprintf('AVG(%s) AS averageWaitingTime', $this->SQLDriver->getDateDiffInSecondsExpression('received_at', 'dispatched_at')))
->addSelect(sprintf('AVG(%s) AS averageHandlingTime', $this->SQLDriver->getDateDiffInSecondsExpression('handled_at', 'received_at')))
->select('count(id) as count_messages_on_period, class')
->addSelect(sprintf('AVG(%s) AS average_waiting_time', $this->SQLDriver->getDateDiffInSecondsExpression('received_at', 'dispatched_at')))
->addSelect(sprintf('AVG(%s) AS average_handling_time', $this->SQLDriver->getDateDiffInSecondsExpression('handled_at', 'received_at')))
->from($this->tableName)
->where('handled_at >= :from_date')
->andWhere('handled_at <= :to_date')
Expand All @@ -128,9 +128,9 @@ public function getStatistics(\DateTimeImmutable $fromDate, \DateTimeImmutable $
$fromDate,
$toDate,
$row['class'],
(int) $row['countMessagesOnPeriod'],
(float) $row['averageWaitingTime'],
(float) $row['averageHandlingTime']
(int) $row['count_messages_on_period'],
(float) $row['average_waiting_time'],
(float) $row['average_handling_time']
)
);
}
Expand Down
10 changes: 9 additions & 1 deletion src/Storage/Doctrine/ConnectionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Doctrine\Persistence\ConnectionRegistry;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use SymfonyCasts\MessengerMonitorBundle\Storage\Doctrine\Driver\MySQLDriver;
use SymfonyCasts\MessengerMonitorBundle\Storage\Doctrine\Driver\PostgreSQLDriver;

/**
* @internal
Expand All @@ -23,8 +24,15 @@ public function __invoke(): Connection
try {
/** @var DBALConnection $driverConnection */
$driverConnection = $this->registry->getConnection($this->connectionName);
$databasePlatform = $driverConnection->getDatabasePlatform()->getName();

return new Connection($driverConnection, new MySQLDriver(), $this->tableName);
$driver = match ($databasePlatform) {
'mysql' => new MySQLDriver(),
'postgresql' => new PostgreSQLDriver(),
default => throw new InvalidConfigurationException(sprintf('Doctrine platform "%s" is not supported', $databasePlatform))
};

return new Connection($driverConnection, $driver, $this->tableName);
} catch (\InvalidArgumentException) {
throw new InvalidConfigurationException(sprintf('Doctrine connection with name "%s" does not exist', $this->connectionName));
}
Expand Down
16 changes: 16 additions & 0 deletions src/Storage/Doctrine/Driver/PostgreSQLDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace SymfonyCasts\MessengerMonitorBundle\Storage\Doctrine\Driver;

/**
* @internal
*/
final class PostgreSQLDriver implements SQLDriverInterface
{
public function getDateDiffInSecondsExpression(string $fieldFrom, string $fieldTo): string
{
return sprintf('extract(epoch from (%s - %s))', $fieldFrom, $fieldTo);
}
}
13 changes: 11 additions & 2 deletions tests/FunctionalTests/AbstractFunctionalTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Doctrine\DBAL\Schema\Schema;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Messenger\Envelope;
Expand Down Expand Up @@ -48,8 +49,16 @@ protected function setUp(): void

$connection->executeQuery('DROP TABLE IF EXISTS messenger_messages');

$databasePlatform = $connection->getDatabasePlatform()->getName();

$truncateTable = match ($databasePlatform) {
'mysql' => 'TRUNCATE TABLE messenger_monitor',
'postgresql' => 'TRUNCATE TABLE messenger_monitor RESTART IDENTITY',
default => throw new InvalidConfigurationException(sprintf('Doctrine platform "%s" is not supported', $databasePlatform))
};

try {
$connection->executeQuery('TRUNCATE TABLE messenger_monitor');
$connection->executeQuery($truncateTable);
} catch (\Throwable) {
self::getContainer()->get('test.symfonycasts.messenger_monitor.storage.doctrine_connection')->executeSchema(new Schema(), $connection);
}
Expand Down Expand Up @@ -102,7 +111,7 @@ protected function assertStoredMessageIsInDB(Envelope $envelope): void
/** @var MonitorIdStamp $monitorIdStamp */
$monitorIdStamp = $envelope->last(MonitorIdStamp::class);
$this->assertNotFalse(
$connection->executeQuery('SELECT id FROM messenger_monitor WHERE id = :id', ['id' => $monitorIdStamp->getId()])
$connection->executeQuery('SELECT id FROM messenger_monitor WHERE message_uid = :id', ['id' => $monitorIdStamp->getId()])
);
}

Expand Down
11 changes: 10 additions & 1 deletion tests/IntegrationTests/AbstractDoctrineIntegrationTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Schema\Schema;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\HttpKernel\KernelInterface;
use SymfonyCasts\MessengerMonitorBundle\Storage\Doctrine\Connection as DoctrineConnection;
use SymfonyCasts\MessengerMonitorBundle\Tests\TestKernel;
Expand Down Expand Up @@ -37,8 +38,16 @@ protected function setUp(): void

$this->doctrineConnection = self::getContainer()->get('test.symfonycasts.messenger_monitor.storage.doctrine_connection');

$databasePlatform = $connection->getDatabasePlatform()->getName();

$truncateTable = match ($databasePlatform) {
'mysql' => 'TRUNCATE TABLE messenger_monitor',
'postgresql' => 'TRUNCATE TABLE messenger_monitor RESTART IDENTITY',
default => throw new InvalidConfigurationException(sprintf('Doctrine platform "%s" is not supported', $databasePlatform))
};

try {
$connection->executeQuery('TRUNCATE TABLE messenger_monitor');
$connection->executeQuery($truncateTable);
} catch (\Throwable) {
$this->doctrineConnection->executeSchema(new Schema(), $connection);
}
Expand Down
37 changes: 24 additions & 13 deletions tests/IntegrationTests/Storage/DoctrineConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,41 @@ final class DoctrineConnectionTest extends AbstractDoctrineIntegrationTests
{
public function testSaveAndLoadMessage(): void
{
$uuid = uuid_create(UUID_TYPE_RANDOM);

$this->doctrineConnection->saveMessage(
new StoredMessage('message_uid', TestableMessage::class, $dispatchedAt = (new \DateTimeImmutable())->setTime(0, 0, 0))
new StoredMessage($uuid, TestableMessage::class, $dispatchedAt = (new \DateTimeImmutable())->setTime(0, 0, 0))
);

$storedMessage = $this->doctrineConnection->findMessage('message_uid');
$storedMessage = $this->doctrineConnection->findMessage($uuid);

$this->assertEquals(new StoredMessage('message_uid', TestableMessage::class, $dispatchedAt, 1), $storedMessage);
$this->assertEquals(new StoredMessage($uuid, TestableMessage::class, $dispatchedAt, 1), $storedMessage);
}

public function testSaveSeveralMessages(): void
{
$this->doctrineConnection->saveMessage(new StoredMessage('message_uid', TestableMessage::class, new \DateTimeImmutable()));
$this->doctrineConnection->saveMessage(new StoredMessage('message_uid', TestableMessage::class, new \DateTimeImmutable()));
$uuid = uuid_create(UUID_TYPE_RANDOM);
$uuid2 = uuid_create(UUID_TYPE_RANDOM);

$this->doctrineConnection->saveMessage(new StoredMessage($uuid, TestableMessage::class, new \DateTimeImmutable()));
$this->doctrineConnection->saveMessage(new StoredMessage($uuid2, TestableMessage::class, new \DateTimeImmutable()));

$this->assertInstanceOf(StoredMessage::class, $this->doctrineConnection->findMessage('message_uid'));
$this->assertInstanceOf(StoredMessage::class, $this->doctrineConnection->findMessage('message_uid'));
$this->assertInstanceOf(StoredMessage::class, $this->doctrineConnection->findMessage($uuid));
$this->assertInstanceOf(StoredMessage::class, $this->doctrineConnection->findMessage($uuid2));
}

public function testUpdateMessage(): void
{
$this->doctrineConnection->saveMessage($storedMessage = new StoredMessage('message_uid', TestableMessage::class, new \DateTimeImmutable()));
$uuid = uuid_create(UUID_TYPE_RANDOM);

$this->doctrineConnection->saveMessage($storedMessage = new StoredMessage($uuid, TestableMessage::class, new \DateTimeImmutable()));
$storedMessage->setReceivedAt(\DateTimeImmutable::createFromFormat('U', (string) time()));
$storedMessage->setHandledAt(\DateTimeImmutable::createFromFormat('U', (string) time()));
$storedMessage->setFailedAt(\DateTimeImmutable::createFromFormat('U', (string) time()));
$storedMessage->setReceiverName('receiver_name');
$this->doctrineConnection->updateMessage($storedMessage);

$storedMessageLoadedFromDatabase = $this->doctrineConnection->findMessage('message_uid');
$storedMessageLoadedFromDatabase = $this->doctrineConnection->findMessage($uuid);

$this->assertSame(
$storedMessage->getReceivedAt()->format('Y-m-d H:i:s'),
Expand Down Expand Up @@ -83,10 +90,14 @@ private function storeMessages(): void
/** @var Connection $connection */
$connection = self::getContainer()->get('doctrine.dbal.default_connection');

$uuid = uuid_create(UUID_TYPE_RANDOM);
$uuid2 = uuid_create(UUID_TYPE_RANDOM);
$uuid3 = uuid_create(UUID_TYPE_RANDOM);

$connection->insert(
'messenger_monitor',
[
'message_uid' => 'message_uid_1',
'message_uid' => $uuid,
'class' => TestableMessage::class,
'dispatched_at' => (new \DateTimeImmutable('3 minutes ago'))->format('Y-m-d H:i:s'),
'received_at' => (new \DateTimeImmutable('2 minutes ago'))->format('Y-m-d H:i:s'),
Expand All @@ -97,7 +108,7 @@ private function storeMessages(): void
$connection->insert(
'messenger_monitor',
[
'message_uid' => 'message_uid_2',
'message_uid' => $uuid2,
'class' => TestableMessage::class,
'dispatched_at' => (new \DateTimeImmutable('10 minutes ago'))->format('Y-m-d H:i:s'),
'received_at' => (new \DateTimeImmutable('7 minutes ago'))->format('Y-m-d H:i:s'),
Expand All @@ -108,7 +119,7 @@ private function storeMessages(): void
$connection->insert(
'messenger_monitor',
[
'message_uid' => 'message_uid_3',
'message_uid' => $uuid3,
'class' => 'Another'.TestableMessage::class,
'dispatched_at' => (new \DateTimeImmutable('3 minutes ago'))->format('Y-m-d H:i:s'),
'received_at' => (new \DateTimeImmutable('2 minutes ago'))->format('Y-m-d H:i:s'),
Expand All @@ -120,7 +131,7 @@ private function storeMessages(): void
$connection->insert(
'messenger_monitor',
[
'message_uid' => 'message_uid_2',
'message_uid' => $uuid2,
'class' => TestableMessage::class,
'dispatched_at' => (new \DateTimeImmutable('6 hours ago'))->format('Y-m-d H:i:s'),
'received_at' => (new \DateTimeImmutable('6 hours ago'))->format('Y-m-d H:i:s'),
Expand Down
20 changes: 20 additions & 0 deletions tests/Storage/Doctrine/Driver/PostgreSQLDriverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace SymfonyCasts\MessengerMonitorBundle\Tests\Storage\Doctrine\Driver;

use PHPUnit\Framework\TestCase;
use SymfonyCasts\MessengerMonitorBundle\Storage\Doctrine\Driver\PostgreSQLDriver;

final class PostgreSQLDriverTest extends TestCase
{
public function testGetDateDiffInSecondsExpression(): void
{
$mysqlDriver = new PostgreSQLDriver();
$this->assertSame(
'extract(epoch from (field_from - field_to))',
$mysqlDriver->getDateDiffInSecondsExpression('field_from', 'field_to')
);
}
}
6 changes: 4 additions & 2 deletions tests/Storage/Doctrine/StoredMessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ final class StoredMessageTest extends TestCase
{
public function testStoredMessage(): void
{
$uuid = uuid_create(UUID_TYPE_RANDOM);

$storedMessage = new StoredMessage(
'message_uid', TestableMessage::class, $dispatchedAt = new \DateTimeImmutable(), 1, $receivedAt = new \DateTimeImmutable(), $handledAt = new \DateTimeImmutable(), $failedAt = new \DateTimeImmutable(), $receiverName = 'receiver_name'
$uuid, TestableMessage::class, $dispatchedAt = new \DateTimeImmutable(), 1, $receivedAt = new \DateTimeImmutable(), $handledAt = new \DateTimeImmutable(), $failedAt = new \DateTimeImmutable(), $receiverName = 'receiver_name'
);

$this->assertSame(1, $storedMessage->getId());
$this->assertSame('message_uid', $storedMessage->getMessageUid());
$this->assertSame($uuid, $storedMessage->getMessageUid());
$this->assertSame(TestableMessage::class, $storedMessage->getMessageClass());
$this->assertSame($dispatchedAt, $storedMessage->getDispatchedAt());
$this->assertSame($receivedAt, $storedMessage->getReceivedAt());
Expand Down
2 changes: 1 addition & 1 deletion tests/TestKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ protected function configureContainer(ContainerBuilder $container)
'dbal' => [
'connections' => [
'default' => [
'url' => getenv('TEST_DATABASE_DSN'),
'url' => '%env(resolve:TEST_DATABASE_DSN)%',
'logging' => false,
],
],
Expand Down

0 comments on commit 885a1df

Please sign in to comment.