Skip to content

Commit

Permalink
Merge pull request #36 from packbackbooks/add-statement-batching
Browse files Browse the repository at this point in the history
Add Statement Batching For PtOnlineSchemaChangeConnection
  • Loading branch information
Daursu authored Dec 15, 2023
2 parents 37b946b + f88daf2 commit 4ebfa5c
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 13 deletions.
25 changes: 25 additions & 0 deletions src/BatchableBlueprint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Daursu\ZeroDowntimeMigration;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Connection;
use Illuminate\Database\Schema\Grammars\Grammar;

/**
* A variant of `Blueprint` that allows for connection types to define a `statements`
* method to process an array of SQL query strings at once. For example, pt-online-schema-change
* lets you pass multiple alter operations to be run on the cloned table.
*/
class BatchableBlueprint extends Blueprint
{
public function build(Connection $connection, Grammar $grammar)
{
if (method_exists($connection, 'statements')) {
$statements = $this->toSql($connection, $grammar);
return !empty($statements) ? $connection->statements($statements) : null;
}

return parent::build($connection, $grammar);
}
}
54 changes: 41 additions & 13 deletions src/Connections/PtOnlineSchemaChangeConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ class PtOnlineSchemaChangeConnection extends BaseConnection
*/
public function statement($query, $bindings = [])
{
$table = $this->extractTableFromQuery($query);
return $this->runQueries([$query]);
}

return $this->runProcess(array_merge(
[
'pt-online-schema-change',
$this->isPretending() ? '--dry-run' : '--execute',
],
$this->getAdditionalParameters(),
[
'--alter',
$this->cleanQuery($query),
$this->getAuthString($table),
]
));
/**
* A custom connection method called by our custom schema builder to help batch
* operations on the cloned table.
*
* @see \Daursu\ZeroDowntimeMigration\BatchableBlueprint
*
* @param string[] $queries
* @return bool|int
*/
public function statements($queries)
{
return $this->runQueries($queries);
}

/**
Expand Down Expand Up @@ -60,4 +61,31 @@ protected function maskSensitiveInformation(array $command): string
return preg_replace('/('.preg_quote($this->getConfig('username'), '/').'),/', '*****,', $config);
})->implode(' ');
}

/**
* @param string[] $queries
* @return bool|int
*/
protected function runQueries($queries)
{
$table = $this->extractTableFromQuery($queries[0]);

$cleanQueries = [];
foreach($queries as $query) {
$cleanQueries[] = $this->cleanQuery($query);
}

return $this->runProcess(array_merge(
[
'pt-online-schema-change',
$this->isPretending() ? '--dry-run' : '--execute',
],
$this->getAdditionalParameters(),
[
'--alter',
implode(', ', $cleanQueries),
$this->getAuthString($table),
]
));
}
}
6 changes: 6 additions & 0 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
use Daursu\ZeroDowntimeMigration\Connections\PtOnlineSchemaChangeConnection;
use Illuminate\Database\Connection;
use Illuminate\Database\Connectors\MySqlConnector;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\ServiceProvider as IlluminateServiceProvider;
use ReflectionClass;

class ServiceProvider extends IlluminateServiceProvider
{
Expand Down Expand Up @@ -42,5 +44,9 @@ public function register()
$this->app->bind('db.connector.gh-ost', function () {
return new MySqlConnector;
});

$this->app->bind(Blueprint::class, function ($app, $args = []) {
return new BatchableBlueprint(...$args);
});
}
}
20 changes: 20 additions & 0 deletions tests/Unit/PtOnlineSchemaChangeConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,26 @@ public function testItRemovesAlterTableStatementFromTheQuery()
$connection->statement($query);
}

public function testItConcatenatesMultipleStatements()
{
$queries = [
"alter table `users` add `middle_name` varchar(255)",
"alter table `users` drop foreign key `created_by_foreign`",
];
$connection = $this->getConnectionWithMockedProcess();

$connection->expects($this->once())
->method('runProcess')
->with($this->callback(function ($command) {
$command = implode(' ', $command);
return Str::contains($command, '--alter add `middle_name` varchar(255), '.
'drop foreign key `created_by_foreign`');
}))
->willReturn(0);

$connection->statements($queries);
}

public function testAdditionalOptionsAreLoadedIn()
{
$query = 'alter table `users` ADD `email` varchar(255)';
Expand Down

0 comments on commit 4ebfa5c

Please sign in to comment.