pmatseykanets/laravel-sql-migrations

Laravel的原生SQL迁移

v1.2.0 2022-05-06 05:58 UTC

This package is auto-updated.

Last update: 2024-09-06 10:58:59 UTC


README

tests Total Downloads

使用纯SQL编写Laravel迁移。

如果你觉得这个包很有用,请考虑请我喝杯咖啡。

Buy Me a Coffee at ko-fi.com

内容

原因

不要误会,Laravel的SchemaBuilder绝对很棒,你可以从中获得很多好处。

但有时候它却成了绊脚石。以下是一些SchemaBuilder力不从心的例子。

使用额外的/更丰富的数据类型

例如,如果你使用PostgreSQL并且想要为字符串/文本数据使用不区分大小写的数据类型,你可能可以考虑使用CITEXT。这意味着我们必须求助于如下这种技巧

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrement('id');
            $table->string('email')->unique();
            // ...
        });

        DB::unprepared('ALTER TABLE users ALTER COLUMN email TYPE CITEXT');
    }
}

而不是简单地

CREATE TABLE IF NOT EXISTS users (
    id BIGSERIAL PRIMARY KEY,
    email CITEXT UNIQUE,
    ...
);

当然还有许多其他数据类型(例如,PostgreSQL中的范围文本搜索数据类型)可能非常有用,但SchemaBuilder却不知道,也不会知道。

管理存储函数、过程和触发器

这是一个很大的问题,尤其是如果你还在使用反向(down())迁移。这意味着你需要在迁移文件的up()down()方法中同时包含函数/过程/触发器的新旧源代码,并将它们放在字符串变量中,这并不利于可读性和可维护性。

即使在php中使用heredoc / nowdoc语法,这仍然很糟糕。

利用IF [NOT] EXISTS等语句

DDL语句中存在许多重要和有用的SQL标准兼容和供应商特定子句,可以让你生活更轻松。其中最著名和经常使用的是IF [NOT] EXISTS

而不是让ShemaBuilder执行到information_schema的单独查询

if (! Schema::hasTable('users')) {
    // create the table
}

if (! Schema::hasColumn('users', 'notes')) {
    // create the column
}

你只需在一条语句中本地编写它

CREATE TABLE IF NOT EXISTS users (id BIGSERIAL PRIMARY KEY, ...);
ALTER TABLE users ADD IF NOT EXISTS notes TEXT;

创建索引时使用额外选项

某些数据库(例如PostgreSQL)允许你在不锁定表的情况下(重新)创建索引。

CREATE INDEX CONCURRENTLY IF NOT EXISTS some_big_table_important_column_id 
    ON some_big_table (important_column);

CREATE INDEX IF NOT EXISTS table_json_column_idx USING GIN ON table (json_column);

你可能需要创建特定类型的索引而不是默认的btree

CREATE INDEX IF NOT EXISTS some_table_json_column_idx ON some_table (json_column) USING GIN;

或创建部分/函数索引

CREATE INDEX IF NOT EXISTS some_table_nullable_column_idx 
    ON some_table (nullable_column) 
    WHERE nullable_column IS NOT NULL;

利用数据库本地的过程代码(例如PL/pgSQL)

当使用PostgreSQL时,如果你需要,可以使用匿名PL/pgSQL代码块。例如,动态(在不提前知道数据库名的情况下)设置search_path,如果你想在一个专门的架构中安装所有扩展而不是污染public

迁移文件.up.sql可能看起来像这样

DO $$
BEGIN
  EXECUTE 'ALTER DATABASE ' || current_database() || ' SET search_path TO "$user",public,extensions';
END;
$$;

以及反向的.down.sql

DO $$
BEGIN
  EXECUTE 'ALTER DATABASE ' || current_database() || ' SET search_path TO "$user",public';
END;
$$;

安装

你可以通过composer安装这个包

composer require pmatseykanets/laravel-sql-migrations

如果你使用的是Laravel < 5.5或如果你已关闭包自动发现,你必须手动注册服务提供者

// config/app.php
'providers' => [
    ...
    SqlMigrations\SqlMigrationsServiceProvider::class,
],

使用

制作SQL迁移

创建SQL迁移最方便的方式是使用带--sql选项的artisan make:migration命令

php artisan make:migration create_users_table --sql

这将生成三个文件

database
└── migrations
    ├── 2018_06_15_000000_create_users_table.down.sql
    ├── 2018_06_15_000000_create_users_table.php
    └── 2018_06_15_000000_create_users_table.up.sql

我知道,这会增加migrations目录中额外的文件,但这种方法允许您轻松混合使用传统和纯SQL迁移。如果您不使用反向(down)迁移,只需删除*.down.sql文件即可。

注意:如果您手动创建文件,请确保

  1. 基本php迁移类扩展了SqlMigration类,并且不包含up()down()方法,除非您打算重写默认行为。
  2. .up.sql.down.sql文件的名称(不包括扩展名)与基本php迁移的文件名完全匹配(包括时间戳部分)。

到了这一步,您就可以忘记2018_06_15_000000_create_users_table.php了,除非您想配置或重写此特定迁移的行为。

SqlMigration扩展了内置的Migration,因此您可以以相同的方式微调您的迁移。

class CreateNextIdFunction extends SqlMigration
{
    // Use a non default connection
    public $connection = 'pgsql2';
    // Wrap migration in a transaction if the database suports transactional DDL
    public $withinTransaction = true;
}

现在,打开*.sql文件并编写您的迁移代码。

例如,2018_06_15_000000_create_users_table.up.sql可能看起来像这样

CREATE TABLE IF NOT EXISTS users (
    id BIGSERIAL PRIMARY KEY,
    name CITEXT,
    email CITEXT,
    password TEXT,
    remember_token TEXT,
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE UNIQUE INDEX IF NOT EXISTS users_email_idx ON users (email);

2018_06_15_000000_create_users_table.down.sql

DROP TABLE IF EXISTS users;

您还可以将--sql选项传递给make:model artisan命令,以指示它为您的全新模型创建纯SQL迁移。

php artisan make:model Post --migration --sql

运行SQL迁移

使用migratemigrate:rollback和其他内置命令进行常规操作。

示例项目

您可以在以下位置找到带有默认SQL迁移的裸Laravel 5.6项目

变更日志

有关最近更改的更多信息,请参阅CHANGELOG

贡献

有关详细信息,请参阅CONTRIBUTING

致谢

许可

MIT许可(MIT)。有关更多信息,请参阅许可文件