Skip to content

Commit 6f641db

Browse files
authored
Merge pull request #773 from patchlevel/same-database
add same database check
2 parents 6b1174a + d2ab18e commit 6f641db

12 files changed

Lines changed: 160 additions & 9 deletions

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ phpunit-integration: vendor
4141

4242
.PHONY: phpunit-integration-postgres
4343
phpunit-integration-postgres: vendor ## run phpunit integration tests on postgres
44-
DB_URL="pdo-pgsql://postgres:postgres@localhost:5432/eventstore?charset=utf8" vendor/bin/phpunit --testsuite=integration
44+
DB_URL="pdo-pgsql://postgres:postgres@127.0.0.1:5432/eventstore?charset=utf8" vendor/bin/phpunit --testsuite=integration
4545

4646
.PHONY: phpunit-integration-mysql
4747
phpunit-integration-mysql: vendor ## run phpunit integration tests on mysql
48-
DB_URL="pdo-mysql://root@localhost:3306/eventstore?charset=utf8" vendor/bin/phpunit --testsuite=integration
48+
DB_URL="pdo-mysql://root@127.0.0.1:3306/eventstore?charset=utf8" vendor/bin/phpunit --testsuite=integration
4949

5050
.PHONY: phpunit-unit
5151
phpunit-unit: vendor ## run phpunit unit tests

baseline.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@
9595
<code><![CDATA[archive]]></code>
9696
</UndefinedInterfaceMethod>
9797
</file>
98+
<file src="src/Schema/DoctrineHelper.php">
99+
<InternalMethod>
100+
<code><![CDATA[getParams]]></code>
101+
<code><![CDATA[getParams]]></code>
102+
</InternalMethod>
103+
</file>
98104
<file src="src/Schema/DoctrineSchemaDirector.php">
99105
<InternalMethod>
100106
<code><![CDATA[getName]]></code>

src/Cryptography/DoctrineCipherKeyStore.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Doctrine\DBAL\Connection;
88
use Doctrine\DBAL\Schema\Schema;
9+
use Patchlevel\EventSourcing\Schema\DoctrineHelper;
910
use Patchlevel\EventSourcing\Schema\DoctrineSchemaConfigurator;
1011
use Patchlevel\Hydrator\Cryptography\Cipher\CipherKey;
1112
use Patchlevel\Hydrator\Cryptography\Store\CipherKeyNotExists;
@@ -80,7 +81,7 @@ public function remove(string $id): void
8081

8182
public function configureSchema(Schema $schema, Connection $connection): void
8283
{
83-
if ($connection !== $this->connection) {
84+
if (!DoctrineHelper::sameDatabase($this->connection, $connection)) {
8485
return;
8586
}
8687

src/Schema/DoctrineHelper.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Patchlevel\EventSourcing\Schema;
6+
7+
use Doctrine\DBAL\Connection;
8+
use Doctrine\DBAL\Exception\TableNotFoundException;
9+
use Throwable;
10+
11+
use function bin2hex;
12+
use function random_bytes;
13+
use function sprintf;
14+
15+
final class DoctrineHelper
16+
{
17+
public static function sameDatabase(Connection $connectionA, Connection $connectionB): bool
18+
{
19+
if ($connectionA === $connectionB) {
20+
return true;
21+
}
22+
23+
if ($connectionA->getParams() === $connectionB->getParams()) {
24+
return true;
25+
}
26+
27+
$checkTable = 'same_db_check_' . bin2hex(random_bytes(7));
28+
$connectionA->executeStatement(sprintf('CREATE TABLE %s (id INTEGER NOT NULL)', $checkTable));
29+
30+
try {
31+
$connectionB->executeStatement(sprintf('DROP TABLE %s', $checkTable));
32+
} catch (Throwable) {
33+
// ignore
34+
}
35+
36+
try {
37+
$connectionA->executeStatement(sprintf('DROP TABLE %s', $checkTable));
38+
39+
return false;
40+
} catch (TableNotFoundException) {
41+
return true;
42+
}
43+
}
44+
}

src/Store/DoctrineDbalStore.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Patchlevel\EventSourcing\Message\Message;
2222
use Patchlevel\EventSourcing\Message\Serializer\DefaultHeadersSerializer;
2323
use Patchlevel\EventSourcing\Message\Serializer\HeadersSerializer;
24+
use Patchlevel\EventSourcing\Schema\DoctrineHelper;
2425
use Patchlevel\EventSourcing\Schema\DoctrineSchemaConfigurator;
2526
use Patchlevel\EventSourcing\Serializer\EventSerializer;
2627
use Patchlevel\EventSourcing\Store\Criteria\AggregateIdCriterion;
@@ -314,7 +315,7 @@ public function transactional(Closure $function): void
314315

315316
public function configureSchema(Schema $schema, Connection $connection): void
316317
{
317-
if ($this->connection !== $connection) {
318+
if (!DoctrineHelper::sameDatabase($this->connection, $connection)) {
318319
return;
319320
}
320321

src/Store/StreamDoctrineDbalStore.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Patchlevel\EventSourcing\Message\Message;
2222
use Patchlevel\EventSourcing\Message\Serializer\DefaultHeadersSerializer;
2323
use Patchlevel\EventSourcing\Message\Serializer\HeadersSerializer;
24+
use Patchlevel\EventSourcing\Schema\DoctrineHelper;
2425
use Patchlevel\EventSourcing\Schema\DoctrineSchemaConfigurator;
2526
use Patchlevel\EventSourcing\Serializer\EventSerializer;
2627
use Patchlevel\EventSourcing\Store\Criteria\ArchivedCriterion;
@@ -396,7 +397,7 @@ public function archive(Criteria|null $criteria = null): void
396397

397398
public function configureSchema(Schema $schema, Connection $connection): void
398399
{
399-
if ($this->connection !== $connection) {
400+
if (!DoctrineHelper::sameDatabase($this->connection, $connection)) {
400401
return;
401402
}
402403

src/Subscription/Store/DoctrineSubscriptionStore.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Doctrine\DBAL\Types\Type;
1616
use Doctrine\DBAL\Types\Types;
1717
use Patchlevel\EventSourcing\Clock\SystemClock;
18+
use Patchlevel\EventSourcing\Schema\DoctrineHelper;
1819
use Patchlevel\EventSourcing\Schema\DoctrineSchemaConfigurator;
1920
use Patchlevel\EventSourcing\Subscription\RunMode;
2021
use Patchlevel\EventSourcing\Subscription\Status;
@@ -208,6 +209,10 @@ public function inLock(Closure $closure): mixed
208209

209210
public function configureSchema(Schema $schema, Connection $connection): void
210211
{
212+
if (!DoctrineHelper::sameDatabase($this->connection, $connection)) {
213+
return;
214+
}
215+
211216
$table = $schema->createTable($this->tableName);
212217

213218
$table->addColumn('id', Types::STRING)

tests/DbalManager.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Doctrine\DBAL\Connection;
88
use Doctrine\DBAL\Driver\AbstractSQLiteDriver;
99
use Doctrine\DBAL\DriverManager;
10+
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
1011
use Doctrine\DBAL\Tools\DsnParser;
1112
use Patchlevel\EventSourcing\Console\DoctrineHelper;
1213
use RuntimeException;
@@ -45,6 +46,14 @@ public static function createConnection(string $dbName = self::DEFAULT_DB_NAME):
4546
$databases = $schemaManager->listDatabases();
4647

4748
if (in_array($dbName, $databases, true)) {
49+
if ($tempConnection->getDatabasePlatform() instanceof PostgreSQLPlatform) {
50+
$tempConnection->executeStatement("
51+
SELECT pg_terminate_backend(pid)
52+
FROM pg_stat_activity
53+
WHERE datname = '{$dbName}';
54+
");
55+
}
56+
4857
$schemaManager->dropDatabase($dbName);
4958
}
5059

tests/Integration/Store/DoctrineDbalStoreTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use DateTimeImmutable;
88
use Doctrine\DBAL\Connection;
9+
use Doctrine\DBAL\Schema\Schema;
910
use Patchlevel\EventSourcing\Aggregate\AggregateHeader;
1011
use Patchlevel\EventSourcing\Message\Message;
1112
use Patchlevel\EventSourcing\Schema\DoctrineSchemaDirector;
@@ -224,4 +225,38 @@ public function testLoad(): void
224225
$stream?->close();
225226
}
226227
}
228+
229+
public function testConfigureSchemaSameDatabase(): void
230+
{
231+
$connection = DbalManager::createConnection();
232+
$otherConnection = DbalManager::createConnection();
233+
234+
$store = new DoctrineDbalStore(
235+
$connection,
236+
DefaultEventSerializer::createFromPaths([__DIR__ . '/Events']),
237+
);
238+
239+
$schema = new Schema();
240+
241+
$store->configureSchema($schema, $otherConnection);
242+
243+
self::assertTrue($schema->hasTable('eventstore'));
244+
}
245+
246+
public function testConfigureSchemaNotSameDatabase(): void
247+
{
248+
$connection = DbalManager::createConnection();
249+
$otherConnection = DbalManager::createConnection('other');
250+
251+
$store = new DoctrineDbalStore(
252+
$connection,
253+
DefaultEventSerializer::createFromPaths([__DIR__ . '/Events']),
254+
);
255+
256+
$schema = new Schema();
257+
258+
$store->configureSchema($schema, $otherConnection);
259+
260+
self::assertFalse($schema->hasTable('eventstore'));
261+
}
227262
}

tests/Integration/Store/StreamDoctrineDbalStoreTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use DateTimeImmutable;
88
use Doctrine\DBAL\Connection;
9+
use Doctrine\DBAL\Schema\Schema;
910
use Patchlevel\EventSourcing\Clock\FrozenClock;
1011
use Patchlevel\EventSourcing\Message\Message;
1112
use Patchlevel\EventSourcing\Schema\DoctrineSchemaDirector;
@@ -538,4 +539,40 @@ public function testRemove(): void
538539

539540
self::assertEquals(['foo'], $streams);
540541
}
542+
543+
public function testConfigureSchemaSameDatabase(): void
544+
{
545+
$connection = DbalManager::createConnection();
546+
$otherConnection = DbalManager::createConnection();
547+
548+
$store = new StreamDoctrineDbalStore(
549+
$connection,
550+
DefaultEventSerializer::createFromPaths([__DIR__ . '/Events']),
551+
clock: $this->clock,
552+
);
553+
554+
$schema = new Schema();
555+
556+
$store->configureSchema($schema, $otherConnection);
557+
558+
self::assertTrue($schema->hasTable('event_store'));
559+
}
560+
561+
public function testConfigureSchemaNotSameDatabase(): void
562+
{
563+
$connection = DbalManager::createConnection();
564+
$otherConnection = DbalManager::createConnection('other');
565+
566+
$store = new StreamDoctrineDbalStore(
567+
$connection,
568+
DefaultEventSerializer::createFromPaths([__DIR__ . '/Events']),
569+
clock: $this->clock,
570+
);
571+
572+
$schema = new Schema();
573+
574+
$store->configureSchema($schema, $otherConnection);
575+
576+
self::assertFalse($schema->hasTable('event_store'));
577+
}
541578
}

0 commit comments

Comments
 (0)