Skip to content

Commit 0074e7e

Browse files
conflicts with upstream Laravel changes (resolves #85, resolves #87)
Co-authored-by: Hafez Divandari <[email protected]>
1 parent d70c72a commit 0074e7e

File tree

3 files changed

+79
-49
lines changed

3 files changed

+79
-49
lines changed

src/Schema/Grammars/GrammarTable.php

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Tpetry\PostgresqlEnhanced\Schema\Grammars;
66

7+
use Arr;
78
use Illuminate\Database\Schema\Blueprint;
89
use Illuminate\Support\Fluent;
910

@@ -16,36 +17,32 @@ trait GrammarTable
1617
*/
1718
public function compileAdd(Blueprint $blueprint, Fluent $command): array
1819
{
19-
$sql = [];
20+
// In Laravel 11.15.0 the logic was changed that compileAdd is only for one column (the one in the command) of
21+
// the blueprint and not all ones of the blueprint as before.
22+
/** @var \Illuminate\Database\Schema\ColumnDefinition[] $columns */
23+
$columns = isset($command['column']) ? [$command['column']] : $blueprint->getAddedColumns();
2024

21-
foreach (array_reverse($blueprint->getAddedColumns()) as $column) {
25+
$sqlChangeDefault = [];
26+
foreach ($columns as $column) {
2227
$attributes = $column->getAttributes();
2328
if (!\array_key_exists('initial', $attributes)) {
2429
continue;
2530
}
2631

27-
if (\array_key_exists('default', $attributes)) {
28-
$sql[] = sprintf('alter table %s alter column %s set default %s',
29-
$this->wrapTable($blueprint),
30-
$this->wrap($column),
31-
$this->getDefaultValue($column['default'])
32-
);
33-
} else {
34-
$sql[] = sprintf('alter table %s alter column %s drop default',
35-
$this->wrapTable($blueprint),
36-
$this->wrap($column),
37-
);
38-
}
39-
32+
// Transform the column definition to a standard one understood by Laravel:
33+
// - The `initial` modifier is saved to the `default` modifier to set the initial value when creating the column.
34+
// - A SQL query is created to reset the `default` value afterward to NULL or the specified value.
35+
$sqlChangeDefault[] = match (\array_key_exists('default', $attributes)) {
36+
true => "alter table {$this->wrapTable($blueprint)} alter column {$this->wrap($column)} set default {$this->getDefaultValue($column['default'])}",
37+
false => "alter table {$this->wrapTable($blueprint)} alter column {$this->wrap($column)} drop default",
38+
};
4039
$column['default'] = $column['initial'];
4140
}
4241

43-
$sql[] = sprintf('alter table %s %s',
44-
$this->wrapTable($blueprint),
45-
implode(', ', $this->prefixArray('add column', $this->getColumns($blueprint)))
46-
);
47-
48-
return array_reverse($sql);
42+
return [
43+
...Arr::wrap(parent::compileAdd($blueprint, $command)), // Some Laravel versions produce a single string while others an array.
44+
...$sqlChangeDefault,
45+
];
4946
}
5047

5148
/**

src/Schema/Grammars/GrammarTypes.php

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,33 @@ trait GrammarTypes
1717
*/
1818
public function compileChange(BaseBlueprint $blueprint, Fluent $command, Connection $connection): array
1919
{
20-
$queries = [];
21-
2220
// The table prefix is accessed differently based on Laravel version. In old version the $prefix was public,
2321
// while with new ones the $blueprint->prefix() method should be used. The issue is solved by invading the
2422
// object and getting the property directly.
2523
$prefix = (fn () => $this->prefix)->call($blueprint);
2624

27-
foreach ($blueprint->getChangedColumns() as $changedColumn) {
28-
$blueprintColumn = new BaseBlueprint($blueprint->getTable(), null, $prefix);
29-
$blueprintColumn->addColumn(
30-
$changedColumn['type'],
31-
$changedColumn['name'],
32-
Arr::except($changedColumn->toArray(), ['compression']),
33-
);
34-
35-
// Remove Compression modifier because Laravel 11 won't work correctly with it (migrator builts incorrectly SQL).
36-
$_modifiers = $this->modifiers;
37-
$this->modifiers = array_filter($this->modifiers, fn ($str) => !\in_array($str, ['Compression']));
38-
$changes = Arr::wrap(parent::compileChange($blueprintColumn, $command, $connection));
39-
$this->modifiers = $_modifiers;
40-
41-
foreach ($changes as $sql) {
25+
// In Laravel 11.15.0 the logic was changed that compileChange is only for one column (the one in the command)
26+
// of the blueprint and not all ones of the blueprint as before.
27+
/** @var \Illuminate\Database\Schema\ColumnDefinition[] $columns */
28+
$columns = isset($command['column']) ? [$command['column']] : $blueprint->getChangedColumns();
29+
30+
$queries = [];
31+
foreach ($columns as $column) {
32+
$modifierCompression = $column['compression'];
33+
$modifierUsing = $column['using'];
34+
unset($column['compression'], $column['using']);
35+
36+
$blueprintColumnExtract = new BaseBlueprint($blueprint->getTable(), null, $prefix);
37+
$blueprintColumnExtract->addColumn($column['type'], $column['name'], $column->toArray());
38+
$blueprintColumnExtractQueries = Arr::wrap(parent::compileChange($blueprint, $command, $connection));
39+
40+
foreach ($blueprintColumnExtractQueries as $sql) {
4241
$regex = Regex::match('/^ALTER table (?P<table>.*?) alter (column )?(?P<column>.*?) type (?P<type>\w+)(?P<modifiers>,.*)?/i', $sql);
4342

44-
if (filled($changedColumn['using']) && $regex->hasMatch()) {
45-
$using = match ($connection->getSchemaGrammar()->isExpression($changedColumn['using'])) {
46-
true => $connection->getSchemaGrammar()->getValue($changedColumn['using']),
47-
false => $changedColumn['using'],
43+
if (filled($modifierUsing) && $regex->hasMatch()) {
44+
$using = match ($connection->getSchemaGrammar()->isExpression($modifierUsing)) {
45+
true => $connection->getSchemaGrammar()->getValue($modifierUsing),
46+
false => $modifierUsing,
4847
};
4948

5049
$queries[] = match (filled($modifiers = $regex->groupOr('modifiers', ''))) {
@@ -56,13 +55,8 @@ public function compileChange(BaseBlueprint $blueprint, Fluent $command, Connect
5655
}
5756
}
5857

59-
if (filled($changedColumn['compression'])) {
60-
$queries[] = sprintf(
61-
'alter table %s alter %s set compression %s',
62-
$this->wrapTable($blueprint->getTable()),
63-
$this->wrap($changedColumn['name']),
64-
$this->wrap($changedColumn['compression']),
65-
);
58+
if (filled($modifierCompression)) {
59+
$queries[] = "alter table {$this->wrapTable($blueprint)} alter {$this->wrap($column['name'])} set compression {$this->wrap($modifierCompression)}";
6660
}
6761
}
6862

tests/CompatibilityTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tpetry\PostgresqlEnhanced\Tests;
6+
7+
use DB;
8+
use Illuminate\Database\Schema\Blueprint;
9+
use Illuminate\Support\Facades\App;
10+
use Illuminate\Support\Facades\Schema;
11+
12+
class CompatibilityTest extends TestCase
13+
{
14+
// With Laravel 11.15.0 the behaviour of commands within a migration has been changed. The ordering is now important
15+
// which is a BC behaviour break (https://github.com/laravel/framework/pull/51373). So the implementation has been
16+
// changed drastically which has lead to issue (https://github.com/tpetry/laravel-postgresql-enhanced/issues/85).
17+
public function testCompatabilityMigrationOrdering(): void
18+
{
19+
DB::statement('create table test()');
20+
$queries = $this->withQueryLog(function (): void {
21+
Schema::table('test', static function (Blueprint $table): void {
22+
$table->text('column_one');
23+
$table->text('column_two');
24+
});
25+
});
26+
27+
$expected = match (true) {
28+
version_compare(App::version(), '11.15.0', '>=') => [
29+
'alter table "test" add column "column_one" text not null',
30+
'alter table "test" add column "column_two" text not null',
31+
],
32+
default => [
33+
'alter table "test" add column "column_one" text not null, add column "column_two" text not null',
34+
],
35+
};
36+
37+
$this->assertEquals($expected, array_column($queries, 'query'));
38+
}
39+
}

0 commit comments

Comments
 (0)