Skip to content

Commit 6cfa9f5

Browse files
committed
Allow ALTER TABLE with conditions
1 parent 3180a5d commit 6cfa9f5

3 files changed

Lines changed: 156 additions & 17 deletions

File tree

src/Definition/AlterTable.php

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,30 @@ protected function renderNoWait() : ?string
170170

171171
/**
172172
* @param callable $definition
173+
* @param bool $ifNotExists
173174
*
174175
* @return static
175176
*/
176-
public function add(callable $definition) : static
177+
public function add(callable $definition, bool $ifNotExists = false) : static
177178
{
178-
$this->sql['add'] = $definition;
179+
$this->sql['add'][] = [
180+
'definition' => $definition,
181+
'if_not_exists' => $ifNotExists,
182+
];
183+
return $this;
184+
}
185+
186+
/**
187+
* @param callable $definition
188+
*
189+
* @return static
190+
*/
191+
public function addIfNotExists(callable $definition) : static
192+
{
193+
$this->sql['add'][] = [
194+
'definition' => $definition,
195+
'if_not_exists' => true,
196+
];
179197
return $this;
180198
}
181199

@@ -184,19 +202,42 @@ protected function renderAdd() : ?string
184202
if ( ! isset($this->sql['add'])) {
185203
return null;
186204
}
187-
$definition = new TableDefinition($this->database);
188-
$this->sql['add']($definition);
189-
return $definition->sql('ADD') ?: null;
205+
$parts = [];
206+
foreach ($this->sql['add'] as $add) {
207+
$definition = new TableDefinition(
208+
$this->database,
209+
$add['if_not_exists'] ? 'IF NOT EXISTS' : null
210+
);
211+
$add['definition']($definition);
212+
$part = $definition->sql('ADD');
213+
if ($part) {
214+
$parts[] = $part;
215+
}
216+
}
217+
return $parts ? \implode(',' . \PHP_EOL, $parts) : null;
190218
}
191219

192220
/**
193221
* @param callable $definition
222+
* @param bool $ifExists
194223
*
195224
* @return static
196225
*/
197-
public function change(callable $definition) : static
226+
public function change(callable $definition, bool $ifExists = false) : static
227+
{
228+
$this->sql['change'][] = [
229+
'definition' => $definition,
230+
'if_exists' => $ifExists,
231+
];
232+
return $this;
233+
}
234+
235+
public function changeIfExists(callable $definition) : static
198236
{
199-
$this->sql['change'] = $definition;
237+
$this->sql['change'][] = [
238+
'definition' => $definition,
239+
'if_exists' => true,
240+
];
200241
return $this;
201242
}
202243

@@ -205,19 +246,42 @@ protected function renderChange() : ?string
205246
if ( ! isset($this->sql['change'])) {
206247
return null;
207248
}
208-
$definition = new TableDefinition($this->database);
209-
$this->sql['change']($definition);
210-
return $definition->sql('CHANGE') ?: null;
249+
$parts = [];
250+
foreach ($this->sql['change'] as $change) {
251+
$definition = new TableDefinition(
252+
$this->database,
253+
$change['if_exists'] ? 'IF EXISTS' : null
254+
);
255+
$change['definition']($definition);
256+
$part = $definition->sql('CHANGE');
257+
if ($part) {
258+
$parts[] = $part;
259+
}
260+
}
261+
return $parts ? \implode(',' . \PHP_EOL, $parts) : null;
211262
}
212263

213264
/**
214265
* @param callable $definition
266+
* @param bool $ifExists
215267
*
216268
* @return static
217269
*/
218-
public function modify(callable $definition) : static
270+
public function modify(callable $definition, bool $ifExists = false) : static
271+
{
272+
$this->sql['modify'][] = [
273+
'definition' => $definition,
274+
'if_exists' => $ifExists,
275+
];
276+
return $this;
277+
}
278+
279+
public function modifyIfExists(callable $definition) : static
219280
{
220-
$this->sql['modify'] = $definition;
281+
$this->sql['modify'][] = [
282+
'definition' => $definition,
283+
'if_exists' => true,
284+
];
221285
return $this;
222286
}
223287

@@ -226,9 +290,19 @@ protected function renderModify() : ?string
226290
if ( ! isset($this->sql['modify'])) {
227291
return null;
228292
}
229-
$definition = new TableDefinition($this->database);
230-
$this->sql['modify']($definition);
231-
return $definition->sql('MODIFY') ?: null;
293+
$parts = [];
294+
foreach ($this->sql['modify'] as $modify) {
295+
$definition = new TableDefinition(
296+
$this->database,
297+
$modify['if_exists'] ? 'IF EXISTS' : null
298+
);
299+
$modify['definition']($definition);
300+
$part = $definition->sql('MODIFY');
301+
if ($part) {
302+
$parts[] = $part;
303+
}
304+
}
305+
return $parts ? \implode(',' . \PHP_EOL, $parts) : null;
232306
}
233307

234308
public function dropColumn(string $name, bool $ifExists = false) : static
@@ -652,7 +726,7 @@ protected function joinParts(array $parts) : string
652726
*
653727
* @return int|string The number of affected rows
654728
*/
655-
public function run() : int|string
729+
public function run() : int | string
656730
{
657731
return $this->database->exec($this->sql());
658732
}

src/Definition/Table/TableDefinition.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,18 @@ class TableDefinition extends DefinitionPart
3434
* @var array<int,Check>
3535
*/
3636
protected array $checks = [];
37+
protected ?string $condition = null;
3738

3839
/**
3940
* TableDefinition constructor.
4041
*
4142
* @param Database $database
43+
* @param string|null $condition
4244
*/
43-
public function __construct(Database $database)
45+
public function __construct(Database $database, string $condition = null)
4446
{
4547
$this->database = $database;
48+
$this->condition = $condition;
4649
}
4750

4851
/**
@@ -99,6 +102,9 @@ protected function renderColumns(string $prefix = null) : string
99102
if ($prefix) {
100103
$prefix .= ' COLUMN';
101104
}
105+
if ($this->condition) {
106+
$prefix .= ' ' . $this->condition;
107+
}
102108
$sql = [];
103109
foreach ($this->columns as $column) {
104110
$name = $this->database->protectIdentifier($column['name']);
@@ -116,6 +122,10 @@ protected function renderIndexes(string $prefix = null) : string
116122
$sql = [];
117123
foreach ($this->indexes as $index) {
118124
$definition = $index['definition']->sql();
125+
if ($this->condition) {
126+
$definition = \explode('(', $definition, 2);
127+
$definition = $definition[0] . $this->condition . ' (' . $definition[1];
128+
}
119129
$sql[] = " {$prefix}{$definition}";
120130
}
121131
return \implode(',' . \PHP_EOL, $sql);

tests/Definition/AlterTableTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ public function testAddEmpty() : void
7878
);
7979
}
8080

81+
public function testAddIfNotExists() : void
82+
{
83+
$sql = $this->alterTable->table('t1')
84+
->addIfNotExists(static function (TableDefinition $definition) : void {
85+
$definition->column('c1')->varchar(255);
86+
$definition->column('c5')->int()->null();
87+
$definition->index()->key('c1');
88+
})->add(static function (TableDefinition $definition) : void {
89+
$definition->column('c2')->int();
90+
});
91+
self::assertSame(
92+
"ALTER TABLE `t1`\n ADD COLUMN IF NOT EXISTS `c1` varchar(255) NOT NULL,\n"
93+
. " ADD COLUMN IF NOT EXISTS `c5` int NULL,\n"
94+
. " ADD KEY IF NOT EXISTS (`c1`),\n"
95+
. ' ADD COLUMN `c2` int NOT NULL',
96+
$sql->sql()
97+
);
98+
}
99+
81100
public function testChange() : void
82101
{
83102
$sql = $this->alterTable->table('t1')
@@ -101,6 +120,24 @@ public function testChangeEmpty() : void
101120
);
102121
}
103122

123+
public function testChangeIfExists() : void
124+
{
125+
$sql = $this->alterTable->table('t1')
126+
->change(static function (TableDefinition $definition) : void {
127+
$definition->column('c2')->int();
128+
})
129+
->changeIfExists(static function (TableDefinition $definition) : void {
130+
$definition->column('c1')->varchar(255);
131+
$definition->column('c5')->int()->null();
132+
});
133+
self::assertSame(
134+
"ALTER TABLE `t1`\n CHANGE COLUMN `c2` int NOT NULL,\n"
135+
. " CHANGE COLUMN IF EXISTS `c1` varchar(255) NOT NULL,\n"
136+
. ' CHANGE COLUMN IF EXISTS `c5` int NULL',
137+
$sql->sql()
138+
);
139+
}
140+
104141
public function testModify() : void
105142
{
106143
$sql = $this->alterTable->table('t1')
@@ -124,6 +161,24 @@ public function testModifyEmpty() : void
124161
);
125162
}
126163

164+
public function testModifyIfExists() : void
165+
{
166+
$sql = $this->alterTable->table('t1')
167+
->modify(static function (TableDefinition $definition) : void {
168+
$definition->column('c2')->int();
169+
})
170+
->modifyIfExists(static function (TableDefinition $definition) : void {
171+
$definition->column('c1')->varchar(255);
172+
$definition->column('c5')->int()->null();
173+
});
174+
self::assertSame(
175+
"ALTER TABLE `t1`\n MODIFY COLUMN `c2` int NOT NULL,\n"
176+
. " MODIFY COLUMN IF EXISTS `c1` varchar(255) NOT NULL,\n"
177+
. ' MODIFY COLUMN IF EXISTS `c5` int NULL',
178+
$sql->sql()
179+
);
180+
}
181+
127182
public function testDropColumnIfExists() : void
128183
{
129184
$alterTable = $this->alterTable->table('t1')->dropColumnIfExists('foo');

0 commit comments

Comments
 (0)