Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[11.x] Introduce method Blueprint::rawColumn() #53496

Merged
merged 6 commits into from
Nov 15, 2024

Conversation

Jacobs63
Copy link
Contributor

@Jacobs63 Jacobs63 commented Nov 13, 2024

This PR introduces a new column method when creating/updating table schema.

Currently, when trying to create columns which are not natively supported by any of the grammars, we have to instead use database statements. This creates a rather big inconvenience as we cannot use a single table creation callback, because database statements are fired immediately and therefore cannot be used in Schema::create(<table>, <callback>).

Imagine a scenario, where we would like to create a:

  1. Table named posts
  2. Containing auto-increment column id
  3. Containing an integer column of display width 1 named legacy_boolean with a default value of 0
  4. Containing a composite index for these two columns

The example code to solve this would likely be as follows:

new class extends Migration {
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
        });

        DB::statement('alter table `posts` add `legacy_boolean` int(1) default 0 not null');

        Schema::table('posts', function (Blueprint $table) {
            $table->index(['id', 'legacy_boolean']);
        });
    }
};

This PR introduces a new column creation method which supports directly specifiying the column type definition used for creating a column:

new class extends Migration {
    public function up()
    {
        Schema::create('table', function (Blueprint $table) {
            $table->id();
            $table->rawColumn('legacy_boolean', 'int(1)')->default(0);
            $table->index(['id', 'legacy_boolean']);
        });
    }
};

This however has one possible drawback - this is not grammar-agnostic and therefore would be specific to the database driver used, even though, by-default, working with columns is grammar-agnostic as the underlying column definitions are compiled by the grammar implementation used by the driver.
On the other hand, the previous solution using database statements is also not grammar-agnostic and therefore we're just moving the drawback from one place to another, meaning, this should not be an issue after all, as we were already facing it elsewhere.

@taylorotwell
Copy link
Member

I think rawColumn would be a more fitting name as @morloderex notes. Please mark as ready for review when the requested changes have been made.

@taylorotwell taylorotwell marked this pull request as draft November 14, 2024 18:19
Copy link
Contributor

@hafezdivandari hafezdivandari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can simply be called column, $table->column('name', 'bit').

I also suggest to accept the type argument as string and also Closure. The Closure may have Connection as the first argument:

$table->column('name', function ($connection) {
    return $connection->isMaria() ? 'mariadb_type' : 'mysql_type';
})

$table->column('name', function ($connection) {
    return version_compare($connection->getServerVersion(), '>=', '3.35')
        ? 'new_type'
        : 'old_type';
})

src/Illuminate/Database/Schema/Grammars/Grammar.php Outdated Show resolved Hide resolved
Comment on lines 1609 to 1619
/**
* Create a new custom column on the table.
*
* @param string $column
* @param string $statement
* @return \Illuminate\Database\Schema\ColumnDefinition
*/
public function custom($column, $statement)
{
return $this->addColumn('custom', $column, compact('statement'));
}
Copy link
Contributor

@hafezdivandari hafezdivandari Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second argument is not a SQL statement, a but SQL type.

Suggested change
/**
* Create a new custom column on the table.
*
* @param string $column
* @param string $statement
* @return \Illuminate\Database\Schema\ColumnDefinition
*/
public function custom($column, $statement)
{
return $this->addColumn('custom', $column, compact('statement'));
}
/**
* Create a new custom type column on the table.
*
* @param string $column
* @param string|(\Closure(\Illuminate\Database\Connection): string) $type
* @return \Illuminate\Database\Schema\ColumnDefinition
*/
public function column(string $column, string|Closure $type)
{
return $this->addColumn('custom', $column, ['definition' => $type]);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I feel like the closure has an added value, perhaps Taylor might feel otherwise, still open to that.

@Jacobs63 Jacobs63 changed the title [11.x] Introduce method Blueprint::custom() [11.x] Introduce method Blueprint::rawColumn() Nov 14, 2024
@Jacobs63
Copy link
Contributor Author

Jacobs63 commented Nov 14, 2024

Not sure that I'm a fan of using the callback as I feel like it doesn't really have added value. The connection is already accessible via DB::connection().

Requested changes have been applied, feel free to re-check.

@Jacobs63 Jacobs63 marked this pull request as ready for review November 14, 2024 20:07
@taylorotwell taylorotwell merged commit 29907b2 into laravel:11.x Nov 15, 2024
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants