diff --git a/config/constants.php b/config/constants.php index a7bd0bb7..d3d869c3 100644 --- a/config/constants.php +++ b/config/constants.php @@ -19,3 +19,4 @@ const DEFAULT_QR_CODE_FORMAT = 'png'; const DEFAULT_QR_CODE_ERROR_CORRECTION = 'l'; const DEFAULT_QR_CODE_ROUND_BLOCK_SIZE = true; const MIN_TASK_WORKERS = 4; +const MIGRATIONS_TABLE = 'migrations'; diff --git a/migrations.php b/migrations.php index 306c1c08..78369f6a 100644 --- a/migrations.php +++ b/migrations.php @@ -2,13 +2,15 @@ declare(strict_types=1); +use const Shlinkio\Shlink\MIGRATIONS_TABLE; + return [ 'migrations_paths' => [ 'ShlinkMigrations' => 'data/migrations', ], 'table_storage' => [ - 'table_name' => 'migrations', + 'table_name' => MIGRATIONS_TABLE, ], 'custom_template' => 'data/migrations_template.txt', diff --git a/module/CLI/src/Command/Db/CreateDatabaseCommand.php b/module/CLI/src/Command/Db/CreateDatabaseCommand.php index 4056477e..afc57d1e 100644 --- a/module/CLI/src/Command/Db/CreateDatabaseCommand.php +++ b/module/CLI/src/Command/Db/CreateDatabaseCommand.php @@ -15,6 +15,9 @@ use Symfony\Component\Lock\LockFactory; use Symfony\Component\Process\PhpExecutableFinder; use function Functional\contains; +use function Functional\filter; + +use const Shlinkio\Shlink\MIGRATIONS_TABLE; class CreateDatabaseCommand extends AbstractDatabaseCommand { @@ -81,8 +84,9 @@ class CreateDatabaseCommand extends AbstractDatabaseCommand private function schemaExists(): bool { // If at least one of the shlink tables exist, we will consider the database exists somehow. - // Any inconsistency should be taken care by the migrations + // We exclude the migrations table, in case db:migrate was run first by mistake. + // Any other inconsistency will be taken care by the migrations. $schemaManager = $this->regularConn->createSchemaManager(); - return ! empty($schemaManager->listTableNames()); + return ! empty(filter($schemaManager->listTableNames(), fn (string $table) => $table !== MIGRATIONS_TABLE)); } } diff --git a/module/CLI/test/Command/Db/CreateDatabaseCommandTest.php b/module/CLI/test/Command/Db/CreateDatabaseCommandTest.php index 65271710..9a5b23d9 100644 --- a/module/CLI/test/Command/Db/CreateDatabaseCommandTest.php +++ b/module/CLI/test/Command/Db/CreateDatabaseCommandTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\LockInterface; use Symfony\Component\Process\PhpExecutableFinder; +use const Shlinkio\Shlink\MIGRATIONS_TABLE; class CreateDatabaseCommandTest extends TestCase { @@ -89,7 +90,7 @@ class CreateDatabaseCommandTest extends TestCase $listDatabases = $this->schemaManager->listDatabases()->willReturn(['foo', 'bar']); $createDatabase = $this->schemaManager->createDatabase($shlinkDatabase)->will(function (): void { }); - $listTables = $this->schemaManager->listTableNames()->willReturn(['foo_table', 'bar_table']); + $listTables = $this->schemaManager->listTableNames()->willReturn(['foo_table', 'bar_table', MIGRATIONS_TABLE]); $this->commandTester->execute([]); @@ -99,15 +100,18 @@ class CreateDatabaseCommandTest extends TestCase $listTables->shouldHaveBeenCalledOnce(); } - /** @test */ - public function tablesAreCreatedIfDatabaseIsEmpty(): void + /** + * @test + * @dataProvider provideEmptyDatabase + */ + public function tablesAreCreatedIfDatabaseIsEmpty(array $tables): void { $shlinkDatabase = 'shlink_database'; $getDatabase = $this->regularConn->getDatabase()->willReturn($shlinkDatabase); $listDatabases = $this->schemaManager->listDatabases()->willReturn(['foo', $shlinkDatabase, 'bar']); $createDatabase = $this->schemaManager->createDatabase($shlinkDatabase)->will(function (): void { }); - $listTables = $this->schemaManager->listTableNames()->willReturn([]); + $listTables = $this->schemaManager->listTableNames()->willReturn($tables); $runCommand = $this->processHelper->run(Argument::type(OutputInterface::class), [ '/usr/local/bin/php', CreateDatabaseCommand::DOCTRINE_SCRIPT, @@ -127,6 +131,12 @@ class CreateDatabaseCommandTest extends TestCase $runCommand->shouldHaveBeenCalledOnce(); } + public function provideEmptyDatabase(): iterable + { + yield 'no tables' => [[]]; + yield 'migrations table' => [[MIGRATIONS_TABLE]]; + } + /** @test */ public function databaseCheckIsSkippedForSqlite(): void {