diff --git a/CHANGELOG-6.0.md b/CHANGELOG-6.0.md new file mode 100644 index 0000000..1b9fba4 --- /dev/null +++ b/CHANGELOG-6.0.md @@ -0,0 +1,188 @@ +# Changelog - Version 6.0 + +## Overview + +Version 6.0 represents a major upgrade focused on modernizing the codebase, improving developer experience, and maintaining compatibility with the latest PHP versions and dependencies. + +## New Features + +### Built-in CLI Tool +- **Standalone CLI without external dependencies**: Pure PHP implementation without requiring Symfony Console +- **Environment variable support**: Configure migrations using `MIGRATION_CONNECTION`, `MIGRATION_PATH`, and `MIGRATION_TABLE` +- **Comprehensive help system**: Multiple verbosity levels (`-v`, `-vv`, `-vvv`) for detailed output +- **Available commands**: + - `version/status` - Show current database version + - `create/install` - Create migration tracking table + - `reset` - Reset database to base schema + - `up` - Migrate to a specific or latest version + - `down` - Migrate down to a specific version or version 0 + - `update` - Automatically update to latest version +- **Composer bin integration**: Automatically available as `vendor/bin/migrate` +- **Comprehensive CLI tests**: Full test coverage for CLI functionality + +### Enhanced Documentation +- Complete documentation restructure with separate guides: + - Getting Started guide + - Database Setup guide + - Migration Scripts guide + - CLI Usage guide + - API Reference guide +- Docusaurus-ready documentation format +- Improved accuracy and examples throughout + +### Database Handling Improvements +- Better database name extraction for SQL Server (support for `dbname` and `Database` query parameters) +- Improved database preparation methods across all database drivers +- Enhanced SQL statement parsing for SQL Server +- Type safety improvements with PHP 8.3+ attributes + +### Development Environment Enhancements +- Gitpod configuration for cloud-based development +- VS Code launch configurations +- Enhanced GitHub Actions CI workflow with SQL Server support +- Improved Docker Compose setup + +## Bug Fixes + +- Fixed Psalm static analysis issues +- Improved SQL statement splitting for SQL Server to handle edge cases +- Fixed database name extraction for SQL Server connections +- Enhanced type checking and error handling throughout the codebase +- Better handling of file operations with proper false checks + +## Breaking Changes + +| Component | Before (5.x) | After (6.x) | Description | +|-----------|-------------|------------|-------------| +| **PHP Version** | `>=8.1 <8.4` | `>=8.3 <8.6` | Minimum PHP version raised to 8.3, added support for PHP 8.4 and 8.5 | +| **PHPUnit** | `^9.6` | `^10.5\|^11.5` | Upgraded to PHPUnit 10/11 for PHP 8.3+ compatibility | +| **Psalm** | `^5.9` | `^6.13` | Upgraded to Psalm 6 for better PHP 8.3+ analysis | +| **byjg/anydataset-db** | `^5.0` | `^6.0` | Updated dependency to match version | +| **Import paths** | `use ByJG\AnyDataset\Db\DbDriverInterface` | `use ByJG\AnyDataset\Db\Interfaces\DbDriverInterface` | Interface namespace changed in anydataset-db 6.0 | +| **Type declarations** | PHP version requirement was in `require-dev` | Now in `require` | PHP version is now a production requirement | + +## Upgrade Path from 5.x to 6.x + +### Step 1: Check PHP Version +Ensure you're running PHP 8.3 or higher: +```bash +php -v +``` + +If you're on PHP 8.1 or 8.2, you need to upgrade PHP before proceeding. + +### Step 2: Update composer.json +Update your `composer.json` to require the new version: +```json +{ + "require": { + "byjg/migration": "^6.0" + } +} +``` + +### Step 3: Update Dependencies +Run composer update: +```bash +composer update byjg/migration +``` + +This will automatically update `byjg/anydataset-db` to version 6.0 as well. + +### Step 4: Update Import Statements (If Using Library Directly) +If you're using the library programmatically and importing `DbDriverInterface`, update the import: + +**Before:** +```php +use ByJG\AnyDataset\Db\DbDriverInterface; +``` + +**After:** +```php +use ByJG\AnyDataset\Db\Interfaces\DbDriverInterface; +``` + +Note: This change is in the `byjg/anydataset-db` package, not in the migration package itself. + +### Step 5: Update Dev Dependencies (If Applicable) +If you have PHPUnit or Psalm in your project, you may need to update them as well: +```bash +composer update --with-dependencies phpunit/phpunit vimeo/psalm +``` + +### Step 6: Test Your Migrations +Run your test suite to ensure everything works: +```bash +vendor/bin/phpunit +``` + +Test your migrations in a development environment: +```bash +# Using the new CLI tool +vendor/bin/migrate version -c +vendor/bin/migrate update -c -p ./migrations +``` + +### Step 7: Optional - Migrate to Built-in CLI +If you were using a custom CLI solution, you can now use the built-in CLI tool: + +**Old approach (custom script):** +```php +#!/usr/bin/env php +update(); +``` + +**New approach (built-in CLI):** +```bash +vendor/bin/migrate update -c -p ./migrations +``` + +Or use environment variables: +```bash +export MIGRATION_CONNECTION="mysql://user:pass@localhost/mydb" +export MIGRATION_PATH="./migrations" +vendor/bin/migrate update +``` + +### Known Issues & Compatibility Notes + +1. **SQL Server Connections**: If you're using SQL Server, ensure your connection string includes the database name in the query parameters (`?dbname=mydb` or `?Database=mydb`) in addition to or instead of the path component. + +2. **Database Interface Changes**: If you've implemented custom database adapters, you may need to update them to match the new interface signatures and add `#[\Override]` attributes for PHP 8.3+ compatibility. + +3. **Namespace Changes**: The primary breaking change comes from the `byjg/anydataset-db` v6.0 dependency, which moved interfaces to an `Interfaces` namespace. This is handled internally by the migration library, but may affect you if you're using these interfaces directly. + +## Performance & Quality Improvements + +- Enhanced static analysis with Psalm 6 +- Improved test infrastructure with PHPUnit 10/11 +- Better type safety with PHP 8.3+ features +- More robust error handling +- Enhanced CI/CD pipeline with SQL Server testing + +## Migration Statistics + +- 42 files changed +- 2,218 insertions(+) +- 597 deletions(-) +- Major commits: 17 + +## Contributors + +This release includes contributions and improvements from: +- Joao Gilberto Magalhaes (@byjg) +- Community contributors + +## Support + +For issues or questions about this release: +- GitHub Issues: https://github.com/byjg/php-migration/issues +- Documentation: See the `docs/` directory + +## License + +This project continues to be licensed under the MIT License. diff --git a/CHANGELOG-7.0.md b/CHANGELOG-7.0.md new file mode 100644 index 0000000..17c3c6e --- /dev/null +++ b/CHANGELOG-7.0.md @@ -0,0 +1,103 @@ +# Changelog - Version 7.0 + +## Overview + +Version 7.0 upgrades the library to `byjg/anydataset-db` 7.0, which introduced a major API redesign: query execution moved from the database driver to the new `DatabaseExecutor` class. Starting with this release, the migration library version is aligned with the `byjg/anydataset-db` major version. + +## New Features + +### DatabaseExecutor Support +- **New `getExecutor()` method**: Available on `Migration`, `DatabaseInterface`, and `AbstractDatabase`, returning a `ByJG\AnyDataset\Db\DatabaseExecutor` instance +- **Single entry point for queries**: Use the executor to run queries against the connection managed by the migration library: + +```php +$migration = new Migration($uri, $path); + +// Before (6.x) +$migration->getDbDriver()->execute("insert into ..."); +$value = $migration->getDbDriver()->getScalar("select ..."); + +// After (7.x) +$migration->getExecutor()->execute("insert into ..."); +$value = $migration->getExecutor()->getScalar("select ..."); +``` + +### Development Environment +- SQL Server image pinned to `mcr.microsoft.com/mssql/server:2022-latest` with `MSSQL_SA_PASSWORD` environment variable +- Removed obsolete `version` key from `docker-compose.yml` + +## Breaking Changes + +| Component | Before (6.x) | After (7.x) | Description | +|-----------|-------------|------------|-------------| +| **byjg/anydataset-db** | `^6.0` | `^7.0` | Query methods (`execute`, `getScalar`, `getIterator`) were removed from `DbDriverInterface` and moved to `DatabaseExecutor` | +| **Query execution** | `$migration->getDbDriver()->execute($sql)` | `$migration->getExecutor()->execute($sql)` | The driver returned by `getDbDriver()` no longer executes queries; it still handles connection and transactions | +| **DatabaseInterface** | — | `getExecutor(): DatabaseExecutor` | New required method. Custom database handlers must implement it (or extend `AbstractDatabase`, which provides it) | +| **AbstractDatabase (protected)** | `getDbDriverWithoutDatabase(): DbDriverInterface` | `getExecutorWithoutDatabase(): DatabaseExecutor` | Renamed static helper used by `prepareEnvironment()` implementations | +| **PgsqlDatabase (protected)** | `createDatabaseIfNotExists(DbDriverInterface $dbDriver, ...)` | `createDatabaseIfNotExists(DatabaseExecutor $executor, ...)` | Signature changed for subclasses overriding this method | +| **PHPUnit** | `^10.5\|^11.5` | `^12.5` | Dev dependency upgrade | + +### Unchanged + +- PHP requirement remains `>=8.3 <8.6` +- `getDbDriver()` is still available on `Migration` and `DatabaseInterface` for connection and transaction control (`beginTransaction`, `commitTransaction`, `rollbackTransaction`) +- Migration scripts, folder structure, CLI usage, and connection strings are unaffected + +## Upgrade Path from 6.x to 7.x + +### Step 1: Update composer.json + +```json +{ + "require": { + "byjg/migration": "^7.0" + } +} +``` + +```bash +composer update byjg/migration +``` + +This will automatically update `byjg/anydataset-db` to version 7.0 as well. + +### Step 2: Replace Direct Driver Query Calls (If Applicable) + +If you call query methods on the driver returned by `getDbDriver()`, switch to the executor: + +```php +// Before +$migration->getDbDriver()->getIterator("select * from users"); + +// After +$migration->getExecutor()->getIterator("select * from users"); +``` + +Transaction calls on the driver do not need to change. + +### Step 3: Update Custom Database Handlers (If Applicable) + +If you implemented `DatabaseInterface` directly, add the new method: + +```php +public function getExecutor(): DatabaseExecutor; +``` + +If you extend `AbstractDatabase`, the method is inherited. Subclasses using the static helper must rename `getDbDriverWithoutDatabase()` calls to `getExecutorWithoutDatabase()` (note it now returns a `DatabaseExecutor`). + +### Step 4: Test Your Migrations + +```bash +vendor/bin/phpunit +vendor/bin/migrate version -c +``` + +## Support + +For issues or questions about this release: +- GitHub Issues: https://github.com/byjg/php-migration/issues +- Documentation: See the `docs/` directory + +## License + +This project continues to be licensed under the MIT License. diff --git a/composer.json b/composer.json index 4215577..4e41b02 100644 --- a/composer.json +++ b/composer.json @@ -5,11 +5,11 @@ "prefer-stable": true, "require": { "ext-pdo": "*", - "byjg/anydataset-db": "^6.0", + "byjg/anydataset-db": "^7.0", "php": ">=8.3 <8.6" }, "require-dev": { - "phpunit/phpunit": "^10.5|^11.5", + "phpunit/phpunit": "^12.5", "vimeo/psalm": "^6.13" }, "autoload": { diff --git a/docker-compose.yml b/docker-compose.yml index 80ab50d..437204b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,9 @@ -version: '3.4' services: mssql: - image: mcr.microsoft.com/mssql/server + image: mcr.microsoft.com/mssql/server:2022-latest environment: - ACCEPT_EULA=Y - - SA_PASSWORD=Pa55word + - MSSQL_SA_PASSWORD=Pa55word ports: - "1433:1433" healthcheck: diff --git a/docs/api-reference.md b/docs/api-reference.md index b41b5f3..0490ab3 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -81,6 +81,9 @@ public static function registerDatabase(string $class): void // Get database driver instance public function getDbDriver(): DbDriverInterface +// Get database executor instance (run queries: execute, getScalar, getIterator) +public function getExecutor(): DatabaseExecutor + // Get database command instance public function getDbCommand(): DatabaseInterface ``` @@ -120,6 +123,7 @@ interface DatabaseInterface public function getCurrentVersion(): int; public function executeSql(string $sql): void; public function getDbDriver(): DbDriverInterface; + public function getExecutor(): DatabaseExecutor; // ... other methods } ``` diff --git a/src/Database/AbstractDatabase.php b/src/Database/AbstractDatabase.php index d788e13..ef92d52 100644 --- a/src/Database/AbstractDatabase.php +++ b/src/Database/AbstractDatabase.php @@ -2,6 +2,7 @@ namespace ByJG\DbMigration\Database; +use ByJG\AnyDataset\Db\DatabaseExecutor; use ByJG\AnyDataset\Db\Interfaces\DbDriverInterface; use ByJG\AnyDataset\Db\Factory; use ByJG\DbMigration\Exception\DatabaseNotVersionedException; @@ -18,6 +19,11 @@ abstract class AbstractDatabase implements DatabaseInterface */ private ?DbDriverInterface $dbDriver = null; + /** + * @var DatabaseExecutor|null + */ + private ?DatabaseExecutor $executor = null; + /** * @var UriInterface */ @@ -44,9 +50,9 @@ protected static function getDatabaseName(Uri $uri): string return ltrim($uri->getPath(), '/'); } - protected static function getDbDriverWithoutDatabase(UriInterface $uri, string $database = ''): DbDriverInterface + protected static function getExecutorWithoutDatabase(UriInterface $uri, string $database = ''): DatabaseExecutor { - return Factory::getDbInstance($uri->withPath("/$database")->__toString()); + return DatabaseExecutor::using(Factory::getDbInstance($uri->withPath("/$database")->__toString())); } /** @@ -70,6 +76,18 @@ public function getDbDriver(): DbDriverInterface return $this->dbDriver; } + /** + * @return DatabaseExecutor + */ + #[\Override] + public function getExecutor(): DatabaseExecutor + { + if (is_null($this->executor)) { + $this->executor = DatabaseExecutor::using($this->getDbDriver()); + } + return $this->executor; + } + /** * @return array * @throws DatabaseNotVersionedException @@ -80,13 +98,13 @@ public function getVersion(): array { $result = []; try { - $result['version'] = $this->getDbDriver()->getScalar('SELECT version FROM ' . $this->getMigrationTable()); + $result['version'] = $this->getExecutor()->getScalar('SELECT version FROM ' . $this->getMigrationTable()); } catch (Exception $ex) { throw new DatabaseNotVersionedException('This database does not have a migration version. Please use "migrate reset" or "migrate install" to create one.'); } try { - $result['status'] = $this->getDbDriver()->getScalar('SELECT status FROM ' . $this->getMigrationTable()); + $result['status'] = $this->getExecutor()->getScalar('SELECT status FROM ' . $this->getMigrationTable()); } catch (Exception $ex) { throw new OldVersionSchemaException('This database does not have a migration version. Please use "migrate install" for update it.'); } @@ -101,7 +119,7 @@ public function getVersion(): array #[\Override] public function setVersion(int $version, MigrationStatus $status): void { - $this->getDbDriver()->execute( + $this->getExecutor()->execute( 'UPDATE ' . $this->getMigrationTable() . ' SET version = :version, status = :status', [ 'version' => $version, @@ -119,7 +137,7 @@ protected function checkExistsVersion(): void // Get the version to check if exists $versionInfo = $this->getVersion(); if ($versionInfo['version'] === false) { - $this->getDbDriver()->execute(sprintf( + $this->getExecutor()->execute(sprintf( "insert into %s values(0, '%s')", $this->getMigrationTable(), MigrationStatus::unknown->value) @@ -133,15 +151,15 @@ protected function checkExistsVersion(): void #[\Override] public function updateVersionTable(): void { - $currentVersion = $this->getDbDriver()->getScalar(sprintf('select version from %s', $this->getMigrationTable())); - $this->getDbDriver()->execute(sprintf('drop table %s', $this->getMigrationTable())); + $currentVersion = $this->getExecutor()->getScalar(sprintf('select version from %s', $this->getMigrationTable())); + $this->getExecutor()->execute(sprintf('drop table %s', $this->getMigrationTable())); $this->createVersion(); $this->setVersion($currentVersion, MigrationStatus::unknown); } protected function isTableExists(?string $schema, string $table): bool { - $count = $this->getDbDriver()->getScalar( + $count = $this->getExecutor()->getScalar( 'SELECT count(*) FROM information_schema.tables ' . ' WHERE table_schema = :schema ' . ' AND table_name = :table ', diff --git a/src/Database/DatabaseInterface.php b/src/Database/DatabaseInterface.php index 4e124db..f5c1fff 100644 --- a/src/Database/DatabaseInterface.php +++ b/src/Database/DatabaseInterface.php @@ -2,6 +2,7 @@ namespace ByJG\DbMigration\Database; +use ByJG\AnyDataset\Db\DatabaseExecutor; use ByJG\AnyDataset\Db\Interfaces\DbDriverInterface; use ByJG\DbMigration\Exception\DatabaseNotVersionedException; use ByJG\DbMigration\Exception\OldVersionSchemaException; @@ -37,6 +38,8 @@ public function isDatabaseVersioned(): bool; public function getDbDriver(): DbDriverInterface; + public function getExecutor(): DatabaseExecutor; + public function getMigrationTable(): string; public function supportsTransaction(): bool; diff --git a/src/Database/DblibDatabase.php b/src/Database/DblibDatabase.php index f9381bf..06076d0 100644 --- a/src/Database/DblibDatabase.php +++ b/src/Database/DblibDatabase.php @@ -27,8 +27,8 @@ public static function prepareEnvironment(UriInterface|Uri $uri): void { $uriInstance = $uri instanceof Uri ? $uri : new Uri($uri->__toString()); $database = static::getDatabaseName($uriInstance); - $dbDriver = static::getDbDriverWithoutDatabase($uri); - $dbDriver->execute("IF NOT EXISTS(select * from sys.databases where name='$database') CREATE DATABASE $database"); + $executor = static::getExecutorWithoutDatabase($uri); + $executor->execute("IF NOT EXISTS(select * from sys.databases where name='$database') CREATE DATABASE $database"); } #[\Override] @@ -36,8 +36,8 @@ public function createDatabase(): void { $database = static::getDatabaseName($this->getDbDriver()->getUri()); - $this->getDbDriver()->execute("IF NOT EXISTS(select * from sys.databases where name='$database') CREATE DATABASE $database"); - $this->getDbDriver()->execute("USE $database"); + $this->getExecutor()->execute("IF NOT EXISTS(select * from sys.databases where name='$database') CREATE DATABASE $database"); + $this->getExecutor()->execute("USE $database"); } #[\Override] @@ -45,13 +45,13 @@ public function dropDatabase(): void { $database = static::getDatabaseName($this->getDbDriver()->getUri()); - $this->getDbDriver()->execute("use master"); - $this->getDbDriver()->execute("drop database $database"); + $this->getExecutor()->execute("use master"); + $this->getExecutor()->execute("drop database $database"); } protected function createTableIfNotExists(string $database, string $createTable): void { - $this->getDbDriver()->execute("use $database"); + $this->getExecutor()->execute("use $database"); $sql = "IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES @@ -61,7 +61,7 @@ protected function createTableIfNotExists(string $database, string $createTable) $createTable END"; - $this->getDbDriver()->execute($sql); + $this->getExecutor()->execute($sql); } /** @@ -97,7 +97,7 @@ protected function executeSqlInternal(string $sql): void if (empty(trim($sql))) { return; } - $this->getDbDriver()->execute($sql); + $this->getExecutor()->execute($sql); } /** @@ -108,7 +108,7 @@ protected function executeSqlInternal(string $sql): void #[\Override] protected function isTableExists(?string $schema, string $table): bool { - $count = $this->getDbDriver()->getScalar( + $count = $this->getExecutor()->getScalar( 'SELECT count(*) FROM information_schema.tables ' . ' WHERE table_catalog = :schema ' . ' AND table_name = :table ', diff --git a/src/Database/MySqlDatabase.php b/src/Database/MySqlDatabase.php index b4647dd..57a5f26 100644 --- a/src/Database/MySqlDatabase.php +++ b/src/Database/MySqlDatabase.php @@ -21,8 +21,8 @@ public static function prepareEnvironment(UriInterface|Uri $uri): void { $uriInstance = $uri instanceof Uri ? $uri : new Uri($uri->__toString()); $database = static::getDatabaseName($uriInstance); - $dbDriver = static::getDbDriverWithoutDatabase($uri); - $dbDriver->execute("CREATE SCHEMA IF NOT EXISTS `$database` DEFAULT CHARACTER SET utf8 ;"); + $executor = static::getExecutorWithoutDatabase($uri); + $executor->execute("CREATE SCHEMA IF NOT EXISTS `$database` DEFAULT CHARACTER SET utf8 ;"); } #[\Override] @@ -30,8 +30,8 @@ public function createDatabase(): void { $database = static::getDatabaseName($this->getDbDriver()->getUri()); - $this->getDbDriver()->execute("CREATE SCHEMA IF NOT EXISTS `$database` DEFAULT CHARACTER SET utf8 ;"); - $this->getDbDriver()->execute("USE `$database`"); + $this->getExecutor()->execute("CREATE SCHEMA IF NOT EXISTS `$database` DEFAULT CHARACTER SET utf8 ;"); + $this->getExecutor()->execute("USE `$database`"); } #[\Override] @@ -39,7 +39,7 @@ public function dropDatabase(): void { $database = static::getDatabaseName($this->getDbDriver()->getUri()); - $this->getDbDriver()->execute("drop database `$database`"); + $this->getExecutor()->execute("drop database `$database`"); } /** @@ -49,14 +49,14 @@ public function dropDatabase(): void #[\Override] public function createVersion(): void { - $this->getDbDriver()->execute('CREATE TABLE IF NOT EXISTS ' . $this->getMigrationTable() . ' (version int, status varchar(20), PRIMARY KEY (version))'); + $this->getExecutor()->execute('CREATE TABLE IF NOT EXISTS ' . $this->getMigrationTable() . ' (version int, status varchar(20), PRIMARY KEY (version))'); $this->checkExistsVersion(); } #[\Override] public function executeSql(string $sql): void { - $this->getDbDriver()->execute($sql); + $this->getExecutor()->execute($sql); } #[\Override] diff --git a/src/Database/PgsqlDatabase.php b/src/Database/PgsqlDatabase.php index 48e84dd..94441fe 100644 --- a/src/Database/PgsqlDatabase.php +++ b/src/Database/PgsqlDatabase.php @@ -2,7 +2,7 @@ namespace ByJG\DbMigration\Database; -use ByJG\AnyDataset\Db\Interfaces\DbDriverInterface; +use ByJG\AnyDataset\Db\DatabaseExecutor; use ByJG\AnyDataset\Db\Factory; use ByJG\DbMigration\Exception\DatabaseNotVersionedException; use ByJG\DbMigration\Exception\OldVersionSchemaException; @@ -22,23 +22,23 @@ public static function prepareEnvironment(UriInterface|Uri $uri): void { $uriInstance = $uri instanceof Uri ? $uri : new Uri($uri->__toString()); $database = static::getDatabaseName($uriInstance); - $dbDriver = static::getDbDriverWithoutDatabase($uri, 'postgres'); - static::createDatabaseIfNotExists($dbDriver, $database); + $executor = static::getExecutorWithoutDatabase($uri, 'postgres'); + static::createDatabaseIfNotExists($executor, $database); } /** - * @param DbDriverInterface $dbDriver + * @param DatabaseExecutor $executor * @param $database */ - protected static function createDatabaseIfNotExists(DbDriverInterface $dbDriver, string $database): void + protected static function createDatabaseIfNotExists(DatabaseExecutor $executor, string $database): void { - $currentDbName = $dbDriver->getScalar( + $currentDbName = $executor->getScalar( "SELECT datname FROM pg_catalog.pg_database WHERE lower(datname) = lower(:dbname)", ['dbname' => $database] ); if (empty($currentDbName)) { - $dbDriver->execute("CREATE DATABASE $database WITH encoding=\"UTF8\";"); + $executor->execute("CREATE DATABASE $database WITH encoding=\"UTF8\";"); } } @@ -46,17 +46,17 @@ protected static function createDatabaseIfNotExists(DbDriverInterface $dbDriver, public function createDatabase(): void { $database = static::getDatabaseName($this->getDbDriver()->getUri()); - static::createDatabaseIfNotExists($this->getDbDriver(), $database); + static::createDatabaseIfNotExists($this->getExecutor(), $database); } #[\Override] public function dropDatabase(): void { - $iterator = $this->getDbDriver()->getIterator( + $iterator = $this->getExecutor()->getIterator( "select 'drop table if exists \"' || tablename || '\" cascade;' command from pg_tables where schemaname = 'public';" ); foreach ($iterator as $singleRow) { - $this->getDbDriver()->execute($singleRow->get('command')); + $this->getExecutor()->execute($singleRow->get('command')); } } @@ -67,7 +67,7 @@ public function dropDatabase(): void #[\Override] public function createVersion(): void { - $this->getDbDriver()->execute('CREATE TABLE IF NOT EXISTS ' . $this->getMigrationTable() . ' (version int, status varchar(20), PRIMARY KEY (version))'); + $this->getExecutor()->execute('CREATE TABLE IF NOT EXISTS ' . $this->getMigrationTable() . ' (version int, status varchar(20), PRIMARY KEY (version))'); $this->checkExistsVersion(); } @@ -90,7 +90,7 @@ protected function executeSqlInternal(string $sql): void if (empty(trim($sql))) { return; } - $this->getDbDriver()->execute($sql); + $this->getExecutor()->execute($sql); } #[\Override] diff --git a/src/Database/SqliteDatabase.php b/src/Database/SqliteDatabase.php index 7e97d75..b206fb7 100644 --- a/src/Database/SqliteDatabase.php +++ b/src/Database/SqliteDatabase.php @@ -29,7 +29,7 @@ public function createDatabase(): void #[\Override] public function dropDatabase(): void { - $iterator = $this->getDbDriver()->getIterator(" + $iterator = $this->getExecutor()->getIterator(" select 'drop ' || type || ' ' || name || ';' as command from sqlite_master @@ -45,7 +45,7 @@ public function dropDatabase(): void $list = $iterator->toArray(); foreach ($list as $row) { - $this->getDbDriver()->execute($row['command']); + $this->getExecutor()->execute($row['command']); } } @@ -56,7 +56,7 @@ public function dropDatabase(): void #[\Override] public function createVersion(): void { - $this->getDbDriver()->execute('CREATE TABLE IF NOT EXISTS ' . $this->getMigrationTable() . ' (version int, status varchar(20), PRIMARY KEY (version))'); + $this->getExecutor()->execute('CREATE TABLE IF NOT EXISTS ' . $this->getMigrationTable() . ' (version int, status varchar(20), PRIMARY KEY (version))'); $this->checkExistsVersion(); } @@ -79,13 +79,13 @@ protected function executeSqlInternal(string $sql): void if (empty(trim($sql))) { return; } - $this->getDbDriver()->execute($sql); + $this->getExecutor()->execute($sql); } #[\Override] protected function isTableExists(?string $schema, string $table): bool { - $count = $this->getDbDriver()->getScalar( + $count = $this->getExecutor()->getScalar( "SELECT count(*) FROM sqlite_master WHERE type='table' AND name=:table", [ "table" => $table diff --git a/src/Migration.php b/src/Migration.php index b9ca5be..e83d4aa 100644 --- a/src/Migration.php +++ b/src/Migration.php @@ -2,6 +2,7 @@ namespace ByJG\DbMigration; +use ByJG\AnyDataset\Db\DatabaseExecutor; use ByJG\AnyDataset\Db\Interfaces\DbDriverInterface; use ByJG\DbMigration\Database\DatabaseInterface; use ByJG\DbMigration\Exception\DatabaseDoesNotRegistered; @@ -103,6 +104,15 @@ public function getDbDriver(): DbDriverInterface return $this->getDbCommand()->getDbDriver(); } + /** + * @return DatabaseExecutor + * @throws DatabaseDoesNotRegistered + */ + public function getExecutor(): DatabaseExecutor + { + return $this->getDbCommand()->getExecutor(); + } + /** * @return DatabaseInterface * @throws DatabaseDoesNotRegistered diff --git a/tests/BaseDatabase.php b/tests/BaseDatabase.php index d0562d3..7f59c62 100644 --- a/tests/BaseDatabase.php +++ b/tests/BaseDatabase.php @@ -186,12 +186,12 @@ protected function getExpectedPostsVersion2(): array */ protected function assertVersion0(): void { - $version = $this->migrate->getDbDriver()->getScalar('select version from '. $this->migrationTable); + $version = $this->migrate->getExecutor()->getScalar('select version from '. $this->migrationTable); $this->assertEquals(0, $version); - $status = $this->migrate->getDbDriver()->getScalar('select status from '. $this->migrationTable); + $status = $this->migrate->getExecutor()->getScalar('select status from '. $this->migrationTable); $this->assertEquals(MigrationStatus::complete->value, $status); - $iterator = $this->migrate->getDbDriver()->getIterator('select * from users'); + $iterator = $this->migrate->getExecutor()->getIterator('select * from users'); $this->assertNotNull($iterator->current()); $row = $iterator->current(); @@ -212,7 +212,7 @@ protected function assertVersion0(): void $this->assertNull($iterator->current()); try { - $this->migrate->getDbDriver()->getIterator('select * from roles'); + $this->migrate->getExecutor()->getIterator('select * from roles'); } catch (\PDOException $ex) { $this->assertTrue(true); } @@ -223,12 +223,12 @@ protected function assertVersion0(): void */ protected function assertVersion1(): void { - $version = $this->migrate->getDbDriver()->getScalar('select version from '. $this->migrationTable); + $version = $this->migrate->getExecutor()->getScalar('select version from '. $this->migrationTable); $this->assertEquals(1, $version); - $status = $this->migrate->getDbDriver()->getScalar('select status from '. $this->migrationTable); + $status = $this->migrate->getExecutor()->getScalar('select status from '. $this->migrationTable); $this->assertEquals(MigrationStatus::complete->value, $status); - $iterator = $this->migrate->getDbDriver()->getIterator($this->getSelectUsersVersion1()); + $iterator = $this->migrate->getExecutor()->getIterator($this->getSelectUsersVersion1()); $this->assertNotNull($iterator->current()); $row = $iterator->current(); @@ -249,7 +249,7 @@ protected function assertVersion1(): void $this->assertNull($iterator->current()); try { - $this->migrate->getDbDriver()->getIterator('select * from roles'); + $this->migrate->getExecutor()->getIterator('select * from roles'); } catch (\PDOException $ex) { $this->assertTrue(true); } @@ -261,13 +261,13 @@ protected function assertVersion1(): void */ protected function assertVersion2(): void { - $version = $this->migrate->getDbDriver()->getScalar('select version from '. $this->migrationTable); + $version = $this->migrate->getExecutor()->getScalar('select version from '. $this->migrationTable); $this->assertEquals(2, $version); - $status = $this->migrate->getDbDriver()->getScalar('select status from '. $this->migrationTable); + $status = $this->migrate->getExecutor()->getScalar('select status from '. $this->migrationTable); $this->assertEquals(MigrationStatus::complete->value, $status); // Users - $iterator = $this->migrate->getDbDriver()->getIterator($this->getSelectUsersVersion1()); + $iterator = $this->migrate->getExecutor()->getIterator($this->getSelectUsersVersion1()); $this->assertNotNull($iterator->current()); $row = $iterator->current(); @@ -288,7 +288,7 @@ protected function assertVersion2(): void $this->assertNull($iterator->current()); // Posts - $iterator = $this->migrate->getDbDriver()->getIterator('select * from posts'); + $iterator = $this->migrate->getExecutor()->getIterator('select * from posts'); $this->assertNotNull($iterator->current()); $row = $iterator->current(); @@ -320,7 +320,7 @@ public function testCreateVersion(): void $this->markTestSkipped($this->skipTest); } $this->migrate->createVersion(); - $records = $this->migrate->getDbDriver()->getIterator("select * from " . $this->migrationTable)->toArray(); + $records = $this->migrate->getExecutor()->getIterator("select * from " . $this->migrationTable)->toArray(); $this->assertEquals([ [ 'version' => '0', @@ -330,7 +330,7 @@ public function testCreateVersion(): void // Check Bug (cannot create twice) $this->migrate->createVersion(); - $records = $this->migrate->getDbDriver()->getIterator("select * from " . $this->migrationTable)->toArray(); + $records = $this->migrate->getExecutor()->getIterator("select * from " . $this->migrationTable)->toArray(); $this->assertEquals([ [ 'version' => '0',