Skip to content

Commit

Permalink
feat: Support addColumn in migration helper (#1808)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolicaleksa committed Dec 30, 2023
1 parent a3614a1 commit b96c1a9
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 153 deletions.
349 changes: 198 additions & 151 deletions src/Properties/SchemaAggregator.php
Original file line number Diff line number Diff line change
Expand Up @@ -286,157 +286,18 @@ private function processColumnUpdates(string $tableName, string $argName, array
}
}

switch (strtolower($firstMethodCall->name->name)) {
case 'biginteger':
case 'increments':
case 'integer':
case 'integerincrements':
case 'mediumincrements':
case 'mediuminteger':
case 'smallincrements':
case 'smallinteger':
case 'tinyincrements':
case 'tinyinteger':
case 'unsignedbiginteger':
case 'unsignedinteger':
case 'unsignedmediuminteger':
case 'unsignedsmallinteger':
case 'unsignedtinyinteger':
case 'bigincrements':
case 'foreignid':
$table->setColumn(new SchemaColumn($columnName, 'int', $nullable));
break;

case 'char':
case 'datetimetz':
case 'date':
case 'datetime':
case 'ipaddress':
case 'json':
case 'jsonb':
case 'linestring':
case 'longtext':
case 'macaddress':
case 'mediumtext':
case 'multilinestring':
case 'string':
case 'text':
case 'time':
case 'timestamp':
case 'uuid':
case 'binary':
$table->setColumn(new SchemaColumn($columnName, 'string', $nullable));
break;

case 'boolean':
$table->setColumn(new SchemaColumn($columnName, 'bool', $nullable));
break;

case 'geometry':
case 'geometrycollection':
case 'multipoint':
case 'multipolygon':
case 'multipolygonz':
case 'point':
case 'polygon':
case 'computed':
$table->setColumn(new SchemaColumn($columnName, 'mixed', $nullable));
break;

case 'double':
case 'float':
case 'unsigneddecimal':
case 'decimal':
$table->setColumn(new SchemaColumn($columnName, 'float', $nullable));
break;

case 'after':
if ($secondArg instanceof PhpParser\Node\Expr\Closure
&& $secondArg->params[0]->var instanceof PhpParser\Node\Expr\Variable
&& ! ($secondArg->params[0]->var->name instanceof PhpParser\Node\Expr)) {
$argName = $secondArg->params[0]->var->name;
$this->processColumnUpdates($tableName, $argName, $secondArg->stmts);
}
break;

case 'dropcolumn':
case 'dropifexists':
case 'dropsoftdeletes':
case 'dropsoftdeletestz':
case 'removecolumn':
case 'drop':
$table->dropColumn($columnName);
break;

case 'dropforeign':
case 'dropindex':
case 'dropprimary':
case 'dropunique':
case 'foreign':
case 'index':
case 'primary':
case 'renameindex':
case 'spatialIndex':
case 'unique':
case 'dropspatialindex':
break;

case 'dropmorphs':
$table->dropColumn($columnName.'_type');
$table->dropColumn($columnName.'_id');
break;

case 'enum':
$table->setColumn(new SchemaColumn($columnName, 'enum', $nullable, $secondArgArray));
break;

case 'morphs':
$table->setColumn(new SchemaColumn($columnName.'_type', 'string', $nullable));
$table->setColumn(new SchemaColumn($columnName.'_id', 'int', $nullable));
break;

case 'nullablemorphs':
$table->setColumn(new SchemaColumn($columnName.'_type', 'string', true));
$table->setColumn(new SchemaColumn($columnName.'_id', 'int', true));
break;

case 'nullableuuidmorphs':
$table->setColumn(new SchemaColumn($columnName.'_type', 'string', true));
$table->setColumn(new SchemaColumn($columnName.'_id', 'string', true));
break;

case 'rename':
$this->renameTableThroughMethodCall($table, $stmt->expr);
break;

case 'renamecolumn':
if ($secondArg instanceof PhpParser\Node\Scalar\String_) {
$table->renameColumn($columnName, $secondArg->value);
}
break;

case 'set':
$table->setColumn(new SchemaColumn($columnName, 'set', $nullable, $secondArgArray));
break;

case 'softdeletestz':
case 'timestamptz':
case 'timetz':
case 'year':
case 'softdeletes':
$table->setColumn(new SchemaColumn($columnName, 'string', true));
break;

case 'uuidmorphs':
$table->setColumn(new SchemaColumn($columnName.'_type', 'string', $nullable));
$table->setColumn(new SchemaColumn($columnName.'_id', 'string', $nullable));
break;

default:
// We know a property exists with a name, we just don't know its type.
$table->setColumn(new SchemaColumn($columnName, 'mixed', $nullable));
break;
}
$this->processStatementAlterMethod(
strtolower($firstMethodCall->name->name),
$firstMethodCall,
$table,
$columnName,
$nullable,
$secondArg,
$argName,
$tableName,
$secondArgArray,
$stmt
);
}
}
}
Expand Down Expand Up @@ -577,4 +438,190 @@ private function getUpdateStatements(PhpParser\Node\Expr $updateClosure): array

return $statements;
}

/**
* @param array<int, mixed> $secondArgArray
*
* @throws \Exception
*/
private function processStatementAlterMethod(
string $method,
PhpParser\Node\Expr\MethodCall|null $firstMethodCall,
SchemaTable $table,
string $columnName,
bool $nullable,
mixed $secondArg,
PhpParser\Node\Expr|string $argName,
string $tableName,
?array $secondArgArray,
PhpParser\Node\Stmt\Expression $stmt
): void {
switch ($method) {
case 'addcolumn':
$this->processStatementAlterMethod(
strtolower($firstMethodCall->args[0]->value->value ?? ''),
null,
$table,
$firstMethodCall->args[1]->value->value ?? '',
$nullable,
$secondArg,
$argName,
$tableName,
$secondArgArray,
$stmt
);
return;

case 'biginteger':
case 'increments':
case 'integer':
case 'integerincrements':
case 'mediumincrements':
case 'mediuminteger':
case 'smallincrements':
case 'smallinteger':
case 'tinyincrements':
case 'tinyinteger':
case 'unsignedbiginteger':
case 'unsignedinteger':
case 'unsignedmediuminteger':
case 'unsignedsmallinteger':
case 'unsignedtinyinteger':
case 'bigincrements':
case 'foreignid':
$table->setColumn(new SchemaColumn($columnName, 'int', $nullable));
return;

case 'char':
case 'datetimetz':
case 'date':
case 'datetime':
case 'ipaddress':
case 'json':
case 'jsonb':
case 'linestring':
case 'longtext':
case 'macaddress':
case 'mediumtext':
case 'multilinestring':
case 'string':
case 'text':
case 'time':
case 'timestamp':
case 'uuid':
case 'binary':
$table->setColumn(new SchemaColumn($columnName, 'string', $nullable));
return;

case 'boolean':
$table->setColumn(new SchemaColumn($columnName, 'bool', $nullable));
return;

case 'geometry':
case 'geometrycollection':
case 'multipoint':
case 'multipolygon':
case 'multipolygonz':
case 'point':
case 'polygon':
case 'computed':
$table->setColumn(new SchemaColumn($columnName, 'mixed', $nullable));
return;

case 'double':
case 'float':
case 'unsigneddecimal':
case 'decimal':
$table->setColumn(new SchemaColumn($columnName, 'float', $nullable));
return;

case 'after':
if ($secondArg instanceof PhpParser\Node\Expr\Closure
&& $secondArg->params[0]->var instanceof PhpParser\Node\Expr\Variable
&& !($secondArg->params[0]->var->name instanceof PhpParser\Node\Expr)) {
$argName = $secondArg->params[0]->var->name;
$this->processColumnUpdates($tableName, $argName, $secondArg->stmts);
}
return;

case 'dropcolumn':
case 'dropifexists':
case 'dropsoftdeletes':
case 'dropsoftdeletestz':
case 'removecolumn':
case 'drop':
$table->dropColumn($columnName);
return;

case 'dropforeign':
case 'dropindex':
case 'dropprimary':
case 'dropunique':
case 'foreign':
case 'index':
case 'primary':
case 'renameindex':
case 'spatialIndex':
case 'unique':
case 'dropspatialindex':
return;

case 'dropmorphs':
$table->dropColumn($columnName . '_type');
$table->dropColumn($columnName . '_id');
return;

case 'enum':
$table->setColumn(new SchemaColumn($columnName, 'enum', $nullable, $secondArgArray));
return;

case 'morphs':
$table->setColumn(new SchemaColumn($columnName . '_type', 'string', $nullable));
$table->setColumn(new SchemaColumn($columnName . '_id', 'int', $nullable));
return;

case 'nullablemorphs':
$table->setColumn(new SchemaColumn($columnName . '_type', 'string', true));
$table->setColumn(new SchemaColumn($columnName . '_id', 'int', true));
return;

case 'nullableuuidmorphs':
$table->setColumn(new SchemaColumn($columnName . '_type', 'string', true));
$table->setColumn(new SchemaColumn($columnName . '_id', 'string', true));
return;

case 'rename':
/** @var PhpParser\Node\Expr\MethodCall $methodCall */
$methodCall = $stmt->expr;
$this->renameTableThroughMethodCall($table, $methodCall);
return;

case 'renamecolumn':
if ($secondArg instanceof PhpParser\Node\Scalar\String_) {
$table->renameColumn($columnName, $secondArg->value);
}
return;

case 'set':
$table->setColumn(new SchemaColumn($columnName, 'set', $nullable, $secondArgArray));
return;

case 'softdeletestz':
case 'timestamptz':
case 'timetz':
case 'year':
case 'softdeletes':
$table->setColumn(new SchemaColumn($columnName, 'string', true));
return;

case 'uuidmorphs':
$table->setColumn(new SchemaColumn($columnName . '_type', 'string', $nullable));
$table->setColumn(new SchemaColumn($columnName . '_id', 'string', $nullable));
return;

default:
// We know a property exists with a name, we just don't know its type.
$table->setColumn(new SchemaColumn($columnName, 'mixed', $nullable));
}
}
}
8 changes: 6 additions & 2 deletions tests/Unit/MigrationHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,15 @@ public function it_can_read_schema_definitions_with_multiple_create_and_drop_met

self::assertCount(1, $tables);
self::assertArrayHasKey('users', $tables);
self::assertCount(6, $tables['users']->columns);
self::assertSame(['id', 'email', 'birthday', 'created_at', 'updated_at', 'active'], array_keys($tables['users']->columns));
self::assertCount(8, $tables['users']->columns);
self::assertSame(['id', 'email', 'birthday', 'city', 'zip', 'created_at', 'updated_at', 'active'], array_keys($tables['users']->columns));
self::assertSame('int', $tables['users']->columns['id']->readableType);
self::assertSame('string', $tables['users']->columns['email']->readableType);
self::assertSame('string', $tables['users']->columns['birthday']->readableType);
self::assertSame('string', $tables['users']->columns['city']->readableType);
self::assertSame(true, $tables['users']->columns['city']->nullable);
self::assertSame('int', $tables['users']->columns['zip']->readableType);
self::assertSame(false, $tables['users']->columns['zip']->nullable);
self::assertSame('string', $tables['users']->columns['created_at']->readableType);
self::assertSame('string', $tables['users']->columns['updated_at']->readableType);
self::assertSame('int', $tables['users']->columns['active']->readableType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ private function createTable(): void
$table->string('address1')->nullable();
$table->string('address2')->nullable();
$table->date('birthday');
$table->addColumn('string', 'city')->nullable();
$table->addColumn('integer', 'zip');
$table->timestamps();
});
}
Expand Down

0 comments on commit b96c1a9

Please sign in to comment.