Skip to content

Commit

Permalink
Add ignore table and only table
Browse files Browse the repository at this point in the history
  • Loading branch information
fezfez committed Jan 8, 2023
1 parent 09dd831 commit 34036fa
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 31 deletions.
4 changes: 3 additions & 1 deletion src/Databases/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

interface Database
{
public function getDumpCommandLine(string $path): string;
public function getDumpStructCommandLine(string $path): string;

public function getDumpDataCommandLine(string $path): string;

public function getRestoreCommandLine(string $path): string;
}
82 changes: 74 additions & 8 deletions src/Databases/MysqlDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
use function sprintf;
use function trim;

/** @psalm-immutable */
final class MysqlDatabase implements Database
{
/**
* @param array<int, string> $extraParams
* @param array<int, string> $ignoreTables
*/
/** @param array<int, string> $ignoreTables */

/** @param array<int, string> $onlyTables */
public function __construct(
private readonly string $host,
private readonly string $port,
Expand All @@ -24,27 +24,82 @@ public function __construct(
private readonly string $database,
private readonly bool $singleTransaction = false,
private readonly bool $ssl = false,
private readonly array $extraParams = [],
private readonly array $ignoreTables = [],
private readonly array $onlyTables = [],
) {
}

public function getDumpCommandLine(string $path): string
/** @param array<int, string> $onlyTables */
public function withOnlyTable(array $onlyTables): self
{
return new self(
$this->host,
$this->port,
$this->user,
$this->password,
$this->database,
$this->singleTransaction,
$this->ssl,
$this->ignoreTables,
$onlyTables,
);
}

/** @param array<int, string> $ignoreTables */
public function withIgnoreTable(array $ignoreTables): self
{
return new self(
$this->host,
$this->port,
$this->user,
$this->password,
$this->database,
$this->singleTransaction,
$this->ssl,
$ignoreTables,
$this->onlyTables,
);
}

public function getDumpDataCommandLine(string $path): string
{
return sprintf(
'mysqldump %s %s > %s',
self::addConnectionInformation([
'--routines',
'--no-create-info',
$this->singleTransaction ? '--single-transaction' : '',
$this->ssl ? '--ssl' : '',
...$this->getIgnoreTableParameter(),
...$this->extraParams,
]),
escapeshellarg($this->database),
$this->getDbAndTables(),
escapeshellarg($path),
);
}

public function getDumpStructCommandLine(string $path): string
{
return sprintf(
'mysqldump %s %s > %s',
self::addConnectionInformation([
'--routines',
'--no-data',
$this->singleTransaction ? '--single-transaction' : '',
$this->ssl ? '--ssl' : '',
]),
$this->getDbAndTables(),
escapeshellarg($path),
);
}

private function getDbAndTables(): string
{
return implode(' ', [
escapeshellarg($this->database),
...$this->getOnlyTable(),
]);
}

public function getRestoreCommandLine(string $path): string
{
return sprintf(
Expand All @@ -66,6 +121,17 @@ private function getIgnoreTableParameter(): iterable
}
}

/**
* @return iterable<int, string>
* @psalm-return iterable<int, string>
*/
private function getOnlyTable(): iterable
{
foreach ($this->onlyTables as $table) {
yield sprintf('%s', escapeshellarg($table));
}
}

/**
* @param array<int|string, string> $value
*
Expand Down
17 changes: 15 additions & 2 deletions src/Databases/PostgresqlDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,23 @@ public function __construct(
) {
}

public function getDumpCommandLine(string $path): string
public function getDumpDataCommandLine(string $path): string
{
return sprintf(
'PGPASSWORD=%s pg_dump --clean --host=%s --port=%s --username=%s %s -f %s',
'PGPASSWORD=%s pg_dump --column-inserts --data-only --clean --host=%s --port=%s --username=%s %s -f %s',
escapeshellarg($this->password),
escapeshellarg($this->host),
escapeshellarg($this->port),
escapeshellarg($this->user),
escapeshellarg($this->database),
escapeshellarg($path),
);
}

public function getDumpStructCommandLine(string $path): string
{
return sprintf(
'PGPASSWORD=%s pg_dump --schema-only --section=pre-data --clean --host=%s --port=%s --username=%s %s -f %s',
escapeshellarg($this->password),
escapeshellarg($this->host),
escapeshellarg($this->port),
Expand Down
11 changes: 6 additions & 5 deletions src/Procedures/Backup.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Fezfez\BackupManager\ShellProcessing\ShellProcessor;
use Symfony\Component\Process\Process;

use function basename;
use function date;
use function sprintf;
use function uniqid;

Expand All @@ -31,20 +31,21 @@ public function __invoke(
array $destinations,
Compressor ...$compressorList,
): void {
$tmpPath = sprintf('%s/%s', $localFileSystem->getRootPath(), uniqid());
$tmpPath = sprintf('%s/%s-%s.sql', $localFileSystem->getRootPath(), date('d-m-Y-H-i-s'), uniqid());

$this->shellProcessor->__invoke(Process::fromShellCommandline($database->getDumpCommandLine($tmpPath)));
$this->shellProcessor->__invoke(Process::fromShellCommandline($database->getDumpStructCommandLine($tmpPath)));
$this->shellProcessor->__invoke(Process::fromShellCommandline($database->getDumpDataCommandLine($tmpPath)));

foreach ($compressorList as $compressor) {
$tmpPath = $compressor->compress($tmpPath);
}

// upload the archive
foreach ($destinations as $destination) {
$destination->destinationFilesystem()->writeStream($destination->destinationPath(), $localFileSystem->readStream(basename($tmpPath)));
$destination->destinationFilesystem()->writeStream($destination->destinationPath(), $localFileSystem->readStream($tmpPath));
}

// cleanup the local archive
$localFileSystem->delete(basename($tmpPath));
$localFileSystem->delete($tmpPath);
}
}
5 changes: 2 additions & 3 deletions src/Procedures/Restore.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use Fezfez\BackupManager\ShellProcessing\ShellProcessor;
use Symfony\Component\Process\Process;

use function basename;
use function sprintf;
use function uniqid;

Expand All @@ -36,7 +35,7 @@ public function __invoke(

// download or retrieve the archived backup file

$localFileSystem->writeStream(basename($workingFile), $to->readStream($sourcePath));
$localFileSystem->writeStream($workingFile, $to->readStream($sourcePath));

// decompress the archived backup
foreach ($compressorList as $compressor) {
Expand All @@ -45,6 +44,6 @@ public function __invoke(

$this->shellProcessor->__invoke(Process::fromShellCommandline($databaseName->getRestoreCommandLine($workingFile)));

$localFileSystem->delete(basename($workingFile));
$localFileSystem->delete($workingFile);
}
}
38 changes: 30 additions & 8 deletions tests/Databases/MysqlDatabaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@

final class MysqlDatabaseTest extends TestCase
{
public function testWith(): void
{
$sUT = new MysqlDatabase(
'foo',
'3306',
'bar',
'baz',
'test',
);

self::assertSame("mysqldump --routines --no-create-info --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpDataCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-data --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpStructCommandLine('outputPath'));

$sUT = $sUT->withOnlyTable(['toto']);
self::assertSame("mysqldump --routines --no-create-info --host='foo' --port='3306' --user='bar' --password='baz' 'test' 'toto' > 'outputPath'", $sUT->getDumpDataCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-data --host='foo' --port='3306' --user='bar' --password='baz' 'test' 'toto' > 'outputPath'", $sUT->getDumpStructCommandLine('outputPath'));
$sUT = $sUT->withIgnoreTable(['tutu']);
self::assertSame("mysqldump --routines --no-create-info --ignore-table='test.tutu' --host='foo' --port='3306' --user='bar' --password='baz' 'test' 'toto' > 'outputPath'", $sUT->getDumpDataCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-data --host='foo' --port='3306' --user='bar' --password='baz' 'test' 'toto' > 'outputPath'", $sUT->getDumpStructCommandLine('outputPath'));
}

public function testGenerateAValidDatabaseDumpCommand(): void
{
$sUT = new MysqlDatabase(
Expand All @@ -19,7 +40,8 @@ public function testGenerateAValidDatabaseDumpCommand(): void
'test',
);

self::assertSame("mysqldump --routines --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-create-info --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpDataCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-data --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpStructCommandLine('outputPath'));
}

public function testGenerateAValidDatabaseDumpCommandWithEmptyPassword(): void
Expand All @@ -28,11 +50,12 @@ public function testGenerateAValidDatabaseDumpCommandWithEmptyPassword(): void
'foo',
'3306',
'bar',
'',
' ',
'test',
);

self::assertSame("mysqldump --routines --host='foo' --port='3306' --user='bar' 'test' > 'outputPath'", $sUT->getDumpCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-create-info --host='foo' --port='3306' --user='bar' 'test' > 'outputPath'", $sUT->getDumpDataCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-data --host='foo' --port='3306' --user='bar' 'test' > 'outputPath'", $sUT->getDumpStructCommandLine('outputPath'));
}

public function testGenerateAValidDatabaseDumpCommandWithSsl(): void
Expand All @@ -45,11 +68,11 @@ public function testGenerateAValidDatabaseDumpCommandWithSsl(): void
'test',
true,
true,
['tutu', ' '],
['test'],
);

self::assertSame("mysqldump --routines --single-transaction --ssl --ignore-table='test.test' tutu --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-create-info --single-transaction --ssl --ignore-table='test.test' --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpDataCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-data --single-transaction --ssl --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpStructCommandLine('outputPath'));
}

public function testGenerateAValidDatabaseDumpCommandWithSingleTransaction(): void
Expand All @@ -63,7 +86,8 @@ public function testGenerateAValidDatabaseDumpCommandWithSingleTransaction(): vo
true,
);

self::assertSame("mysqldump --routines --single-transaction --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-create-info --single-transaction --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpDataCommandLine('outputPath'));
self::assertSame("mysqldump --routines --no-data --single-transaction --host='foo' --port='3306' --user='bar' --password='baz' 'test' > 'outputPath'", $sUT->getDumpStructCommandLine('outputPath'));
}

public function testGenerateAValidDatabaseRestoreCommand(): void
Expand All @@ -88,8 +112,6 @@ public function testGenerateAValidDatabaseRestoreCommandWithSsl(): void
'test',
true,
true,
['toto'],
['test'],
);
self::assertSame("mysql --ssl --host='foo' --port='3306' --user='bar' --password='baz' 'test' -e \"source outputPath\"", $sUT->getRestoreCommandLine('outputPath'));
}
Expand Down
3 changes: 2 additions & 1 deletion tests/Databases/PostgresqlDatabaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public function testGenerateAValidDatabaseDumpCommand(): void
'test',
);

self::assertSame("PGPASSWORD='baz' pg_dump --clean --host='foo' --port='3306' --username='bar' 'test' -f 'outputPath'", $sUT->getDumpCommandLine('outputPath'));
self::assertSame("PGPASSWORD='baz' pg_dump --column-inserts --data-only --clean --host='foo' --port='3306' --username='bar' 'test' -f 'outputPath'", $sUT->getDumpDataCommandLine('outputPath'));
self::assertSame("PGPASSWORD='baz' pg_dump --schema-only --section=pre-data --clean --host='foo' --port='3306' --username='bar' 'test' -f 'outputPath'", $sUT->getDumpStructCommandLine('outputPath'));
}

public function testGenerateAValidDatabaseRestoreCommand(): void
Expand Down
6 changes: 4 additions & 2 deletions tests/Procedures/BackupTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ public function testOk(): void

$sUT = new Backup($shellProcessor);

$database->expects(self::once())->method('getDumpCommandLine')->with(self::anything())->willReturn('a script');
$shellProcessor->expects(self::once())->method('__invoke')->with(self::callback(static function (Process $process) {
$database->expects(self::once())->method('getDumpDataCommandLine')->with(self::anything())->willReturn('a script');
$database->expects(self::once())->method('getDumpStructCommandLine')->with(self::anything())->willReturn('a script');
$shellProcessor->expects(self::exactly(2))->method('__invoke')->with(self::callback(static function (Process $process) {
return $process->getCommandLine() === 'a script';
}));
$compressor->expects(self::once())->method('compress')->with(self::anything())->willReturn('my compressd path');
Expand All @@ -39,6 +40,7 @@ public function testOk(): void
$to->expects(self::once())->method('writeStream')->with('my dest path', $ressource);
$local->expects(self::once())->method('readStream')->with('my compressd path')->willReturn($ressource);
$local->expects(self::once())->method('delete')->with('my compressd path');
$local->expects(self::once())->method('getRootPath')->willReturn('/myrootpath/');

$sUT->__invoke($local, $database, [$destination], $compressor);
}
Expand Down
3 changes: 2 additions & 1 deletion tests/Procedures/RestoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public function testOk(): void

$sUT = new Restore($shellProcessor);

$local->expects(self::once())->method('writeStream')->with(self::anything(), $ressource);
$local->expects(self::once())->method('getRootPath')->willReturn('myrootpath');
$local->expects(self::once())->method('writeStream')->with(self::matchesRegularExpression('/myrootpath\/.*\.gz/'), $ressource);
$to->expects(self::once())->method('readStream')->with('toto')->willReturn($ressource);
$compressor->expects(self::once())->method('decompress')->with(self::anything())->willReturn('toto');
$database->expects(self::once())->method('getRestoreCommandLine')->with('toto')->willReturn('a script');
Expand Down

0 comments on commit 34036fa

Please sign in to comment.