Skip to content

Commit 078c94f

Browse files
committed
feat: Rollback of Migrations
1 parent 71ed0d9 commit 078c94f

File tree

6 files changed

+377
-38
lines changed

6 files changed

+377
-38
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
namespace app\database\migrations\multiDownErr;
3+
4+
use webfiori\database\Database;
5+
use webfiori\database\migration\AbstractMigration;
6+
/**
7+
* A database migration class.
8+
*/
9+
class Migration000 extends AbstractMigration {
10+
/**
11+
* Creates new instance of the class.
12+
*/
13+
public function __construct() {
14+
parent::__construct('Third One', 2);
15+
}
16+
/**
17+
* Performs the action that will apply the migration.
18+
*
19+
* @param Database $schema The database at which the migration will be applied to.
20+
*/
21+
public function up(Database $schema) {
22+
23+
}
24+
/**
25+
* Performs the action that will revert back the migration.
26+
*
27+
* @param Database $schema The database at which the migration will be applied to.
28+
*/
29+
public function down(Database $schema) {
30+
31+
}
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
namespace app\database\migrations\multiDownErr;
3+
4+
use webfiori\database\Database;
5+
use webfiori\database\migration\AbstractMigration;
6+
/**
7+
* A database migration class.
8+
*/
9+
class Migration001 extends AbstractMigration {
10+
/**
11+
* Creates new instance of the class.
12+
*/
13+
public function __construct() {
14+
parent::__construct('Second one', 1);
15+
}
16+
/**
17+
* Performs the action that will apply the migration.
18+
*
19+
* @param Database $schema The database at which the migration will be applied to.
20+
*/
21+
public function up(Database $schema) {
22+
//TODO: Implement the action which will apply the migration to database.
23+
}
24+
/**
25+
* Performs the action that will revert back the migration.
26+
*
27+
* @param Database $schema The database at which the migration will be applied to.
28+
*/
29+
public function down(Database $schema) {
30+
$schema->do();
31+
}
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
namespace app\database\migrations\multiDownErr;
3+
4+
use webfiori\database\Database;
5+
use webfiori\database\migration\AbstractMigration;
6+
/**
7+
* A database migration class.
8+
*/
9+
class Migration002 extends AbstractMigration {
10+
/**
11+
* Creates new instance of the class.
12+
*/
13+
public function __construct() {
14+
parent::__construct('First One', 0);
15+
}
16+
/**
17+
* Performs the action that will apply the migration.
18+
*
19+
* @param Database $schema The database at which the migration will be applied to.
20+
*/
21+
public function up(Database $schema) {
22+
//TODO: Implement the action which will apply the migration to database.
23+
}
24+
/**
25+
* Performs the action that will revert back the migration.
26+
*
27+
* @param Database $schema The database at which the migration will be applied to.
28+
*/
29+
public function down(Database $schema) {
30+
//TODO: Implement the action which will revert back the migration.
31+
}
32+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
namespace app\database\migrations\multiDownErr;
3+
4+
use webfiori\database\ConnectionInfo;
5+
use webfiori\database\migration\MigrationsRunner;
6+
use const APP_PATH;
7+
use const DS;
8+
9+
10+
class MultiErrRunner extends MigrationsRunner {
11+
12+
public function __construct() {
13+
$conn = new ConnectionInfo('mssql', SQL_SERVER_USER, SQL_SERVER_PASS, SQL_SERVER_DB, SQL_SERVER_HOST, 1433, [
14+
'TrustServerCertificate' => 'true'
15+
]);
16+
parent::__construct(APP_PATH.'database'.DS.'migrations'.DS.'multiDownErr', '\\app\\database\\migrations\\multiDownErr', $conn);
17+
}
18+
}

tests/webfiori/framework/test/cli/RunMigrationsCommantTest.php

Lines changed: 222 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ public function testRunMigrations07() {
161161
$clazz = $this->createMigration('Cool', 'CoolOne');
162162
$this->assertTrue(class_exists($clazz));
163163
App::getConfig()->addOrUpdateDBConnection($conn);
164+
$output = $this->executeMultiCommand([
165+
RunMigrationsCommand::class,
166+
'--ns' => '\\app\\database\\migrations',
167+
], [
168+
'7',
169+
''
170+
]);
171+
$this->removeClass($clazz);
172+
App::getConfig()->removeAllDBConnections();
164173
$this->assertEquals([
165174
"Checking namespace '\app\database\migrations' for migrations...\n",
166175
"Info: Found 1 migration(s) in the namespace '\app\database\migrations'.\n",
@@ -170,16 +179,9 @@ public function testRunMigrations07() {
170179
"Select database connection:\n",
171180
"0: default-conn <--\n",
172181
"Error: Unable to connect to database: 4060 - [Microsoft][ODBC Driver ".ODBC_VERSION." for SQL Server][SQL Server]Cannot open database \"testing_dbx\" requested by the login. The login failed.\n",
173-
], $this->executeMultiCommand([
174-
RunMigrationsCommand::class,
175-
'--ns' => '\\app\\database\\migrations',
176-
], [
177-
'7',
178-
''
179-
]));
182+
], $output);
180183
$this->assertEquals(-1, $this->getExitCode());
181-
$this->removeClass($clazz);
182-
App::getConfig()->removeAllDBConnections();
184+
183185
}
184186
/**
185187
* @test
@@ -540,18 +542,45 @@ public function testRollback01() {
540542
'TrustServerCertificate' => 'true'
541543
]);
542544
$conn->setName('default-conn');
543-
$clazz = $this->createMigration('ABCD Cool', 'ABCCool');
544-
$this->assertTrue(class_exists($clazz));
545+
546+
$ns = '\\app\\database\\migrations';
547+
$clazz = $this->createAndRunMigration($conn, $ns, 'ABCD Cool', 'ABCCool');
545548
App::getConfig()->addOrUpdateDBConnection($conn);
546549

550+
$output = $this->executeMultiCommand([
551+
RunMigrationsCommand::class,
552+
'--ns' => '\\app\\database\\migrations',
553+
'--rollback',
554+
'--connection' => 'default-conn',
555+
]);
556+
App::getConfig()->removeAllDBConnections();
557+
$this->removeMigTable($conn);
558+
$this->removeClass($clazz);
559+
$this->assertEquals([
560+
"Checking namespace '\app\database\migrations' for migrations...\n",
561+
"Info: Found 1 migration(s) in the namespace '\app\database\migrations'.\n",
562+
"Rolling back last executed migration...\n",
563+
"Success: Migration 'ABCD Cool' was successfully rolled back.\n",
564+
], $output);
565+
$this->assertEquals(0, $this->getExitCode());
566+
}
567+
/**
568+
* @test
569+
*/
570+
public function testRollback02() {
571+
$conn = new ConnectionInfo('mssql', SQL_SERVER_USER, SQL_SERVER_PASS, SQL_SERVER_DB, SQL_SERVER_HOST, 1433, [
572+
'TrustServerCertificate' => 'true'
573+
]);
574+
$conn->setName('default-conn');
575+
576+
$ns = '\\app\\database\\migrations';
577+
$clazz = $this->createAndRunMigration($conn, $ns, 'ABCD Cool', 'ABCCool');
578+
App::getConfig()->addOrUpdateDBConnection($conn);
547579
$this->executeMultiCommand([
548580
RunMigrationsCommand::class,
549581
'--ns' => '\\app\\database\\migrations',
582+
'--rollback',
550583
'--connection' => 'default-conn',
551-
'--ini'
552-
], [
553-
'7',
554-
''
555584
]);
556585
$output = $this->executeMultiCommand([
557586
RunMigrationsCommand::class,
@@ -566,10 +595,187 @@ public function testRollback01() {
566595
"Checking namespace '\app\database\migrations' for migrations...\n",
567596
"Info: Found 1 migration(s) in the namespace '\app\database\migrations'.\n",
568597
"Rolling back last executed migration...\n",
569-
"Success: Migration 'ABCD Cool' was successfully rolled back.\n",
598+
"Info: No migration rolled back.\n",
599+
], $output);
600+
$this->assertEquals(0, $this->getExitCode());
601+
}
602+
/**
603+
* @test
604+
*/
605+
public function testRollback03() {
606+
$conn = new ConnectionInfo('mssql', SQL_SERVER_USER, SQL_SERVER_PASS, SQL_SERVER_DB, SQL_SERVER_HOST, 1433, [
607+
'TrustServerCertificate' => 'true'
608+
]);
609+
$conn->setName('default-conn');
610+
611+
App::getConfig()->addOrUpdateDBConnection($conn);
612+
$this->executeMultiCommand([
613+
RunMigrationsCommand::class,
614+
'--runner' => '\\app\\database\\migrations\\multi\MultiRunner',
615+
'--ini'
616+
]);
617+
$output = $this->executeMultiCommand([
618+
RunMigrationsCommand::class,
619+
'--runner' => '\\app\\database\\migrations\\multi\\MultiRunner',
620+
'--rollback',
621+
]);
622+
623+
App::getConfig()->removeAllDBConnections();
624+
625+
626+
$this->assertEquals([
627+
"Checking namespace '\app\database\migrations\multi' for migrations...\n",
628+
"Info: Found 3 migration(s) in the namespace '\app\database\migrations\multi'.\n",
629+
"Rolling back last executed migration...\n",
630+
"Success: Migration 'Third One' was successfully rolled back.\n",
631+
], $output);
632+
633+
$this->assertEquals(0, $this->getExitCode());
634+
$output = $this->executeMultiCommand([
635+
RunMigrationsCommand::class,
636+
'--runner' => '\\app\\database\\migrations\\multi\\MultiRunner',
637+
'--rollback',
638+
]);
639+
$this->assertEquals([
640+
"Checking namespace '\app\database\migrations\multi' for migrations...\n",
641+
"Info: Found 3 migration(s) in the namespace '\app\database\migrations\multi'.\n",
642+
"Rolling back last executed migration...\n",
643+
"Success: Migration 'Second one' was successfully rolled back.\n",
644+
], $output);
645+
$this->assertEquals(0, $this->getExitCode());
646+
$output = $this->executeMultiCommand([
647+
RunMigrationsCommand::class,
648+
'--runner' => '\\app\\database\\migrations\\multi\\MultiRunner',
649+
'--rollback',
650+
]);
651+
$this->assertEquals([
652+
"Checking namespace '\app\database\migrations\multi' for migrations...\n",
653+
"Info: Found 3 migration(s) in the namespace '\app\database\migrations\multi'.\n",
654+
"Rolling back last executed migration...\n",
655+
"Success: Migration 'First One' was successfully rolled back.\n",
656+
], $output);
657+
$this->assertEquals(0, $this->getExitCode());
658+
$output = $this->executeMultiCommand([
659+
RunMigrationsCommand::class,
660+
'--runner' => '\\app\\database\\migrations\\multi\\MultiRunner',
661+
'--rollback',
662+
]);
663+
$this->assertEquals([
664+
"Checking namespace '\app\database\migrations\multi' for migrations...\n",
665+
"Info: Found 3 migration(s) in the namespace '\app\database\migrations\multi'.\n",
666+
"Rolling back last executed migration...\n",
667+
"Info: No migration rolled back.\n",
668+
], $output);
669+
$this->removeMigTable($conn);
670+
}
671+
/**
672+
* @test
673+
*/
674+
public function testRollback04() {
675+
$conn = new ConnectionInfo('mssql', SQL_SERVER_USER, SQL_SERVER_PASS, SQL_SERVER_DB, SQL_SERVER_HOST, 1433, [
676+
'TrustServerCertificate' => 'true'
677+
]);
678+
$conn->setName('default-conn');
679+
680+
App::getConfig()->addOrUpdateDBConnection($conn);
681+
$this->executeMultiCommand([
682+
RunMigrationsCommand::class,
683+
'--runner' => '\\app\\database\\migrations\\multi\MultiRunner',
684+
'--ini'
685+
]);
686+
$output = $this->executeMultiCommand([
687+
RunMigrationsCommand::class,
688+
'--runner' => '\\app\\database\\migrations\\multi\\MultiRunner',
689+
'--rollback',
690+
'--all'
691+
]);
692+
693+
$this->assertEquals([
694+
"Checking namespace '\app\database\migrations\multi' for migrations...\n",
695+
"Info: Found 3 migration(s) in the namespace '\app\database\migrations\multi'.\n",
696+
"Rolling back migrations...\n",
697+
"Success: Migration 'Third One' was successfully rolled back.\n",
698+
"Success: Migration 'Second one' was successfully rolled back.\n",
699+
"Success: Migration 'First One' was successfully rolled back.\n",
570700
], $output);
701+
571702
$this->assertEquals(0, $this->getExitCode());
703+
$output = $this->executeMultiCommand([
704+
RunMigrationsCommand::class,
705+
'--runner' => '\\app\\database\\migrations\\multi\\MultiRunner',
706+
'--rollback',
707+
'--all'
708+
]);
709+
$this->assertEquals([
710+
"Checking namespace '\app\database\migrations\multi' for migrations...\n",
711+
"Info: Found 3 migration(s) in the namespace '\app\database\migrations\multi'.\n",
712+
"Rolling back migrations...\n",
713+
"Info: No migration rolled back.\n",
714+
], $output);
715+
$this->removeMigTable($conn);
716+
}
717+
/**
718+
* @test
719+
*/
720+
public function testRollback05() {
721+
$conn = new ConnectionInfo('mssql', SQL_SERVER_USER, SQL_SERVER_PASS, SQL_SERVER_DB, SQL_SERVER_HOST, 1433, [
722+
'TrustServerCertificate' => 'true'
723+
]);
724+
$conn->setName('default-conn');
725+
726+
App::getConfig()->addOrUpdateDBConnection($conn);
727+
$this->executeMultiCommand([
728+
RunMigrationsCommand::class,
729+
'--runner' => '\\app\\database\\migrations\\multiDownErr\MultiErrRunner',
730+
'--ini'
731+
]);
732+
$output = $this->executeMultiCommand([
733+
RunMigrationsCommand::class,
734+
'--runner' => '\\app\\database\\migrations\\multiDownErr\MultiErrRunner',
735+
'--rollback',
736+
'--all'
737+
]);
738+
739+
$this->assertEquals([
740+
"Checking namespace '\app\database\migrations\multiDownErr' for migrations...\n",
741+
"Info: Found 3 migration(s) in the namespace '\app\database\migrations\multiDownErr'.\n",
742+
"Rolling back migrations...\n",
743+
"Success: Migration 'Third One' was successfully rolled back.\n",
744+
"Error: Failed to execute migration due to following:\n",
745+
"Call to undefined method webfiori\database\migration\MigrationsRunner::do() (Line 30)\n",
746+
"Warning: Execution stopped.\n",
747+
], $output);
748+
749+
$this->assertEquals(-1, $this->getExitCode());
750+
$output = $this->executeMultiCommand([
751+
RunMigrationsCommand::class,
752+
'--runner' => '\\app\\database\\migrations\\multiDownErr\MultiErrRunner',
753+
'--rollback',
754+
'--all'
755+
]);
572756

757+
$this->assertEquals([
758+
"Checking namespace '\app\database\migrations\multiDownErr' for migrations...\n",
759+
"Info: Found 3 migration(s) in the namespace '\app\database\migrations\multiDownErr'.\n",
760+
"Rolling back migrations...\n",
761+
"Error: Failed to execute migration due to following:\n",
762+
"Call to undefined method webfiori\database\migration\MigrationsRunner::do() (Line 30)\n",
763+
"Warning: Execution stopped.\n",
764+
], $output);
765+
$this->removeMigTable($conn);
766+
}
767+
private function createAndRunMigration(ConnectionInfo $connection, string $ns, ?string $name = null, ?string $className = null) : string {
768+
$clazz = $this->createMigration($name, $className);
769+
App::getConfig()->addOrUpdateDBConnection($connection);
770+
$this->executeMultiCommand([
771+
RunMigrationsCommand::class,
772+
'--ns' => $ns,
773+
'--connection' => $connection->getName(),
774+
'--ini'
775+
]);
776+
$this->assertTrue(class_exists($clazz));
777+
App::getConfig()->removeDBConnection($connection->getName());
778+
return $clazz;
573779
}
574780
private function createMigration(?string $name = null, ?string $className = null) : string {
575781
$runner = new MigrationsRunner(APP_PATH.DS.'database'.DS.'migrations'.DS.'commands', '\\app\\database\\migrations\\commands', null);

0 commit comments

Comments
 (0)