附录:程序化规划
在之前的部分我们看到了如何使用 Atlas CLI 来生成迁移文件。然而我们也能程序化生成这些文件。 在本部分我们将会回顾如何编写 Go 语言代码被程序化规划迁移文件所使用。
1. 开启版本化迁移功能标志
本部分描述的修改可以在支持的代码仓库中的 PR #2 找到。
第一步是通过传递 sql/versioned-migration 功能标志开启版本化迁移功能。
取决于你如何执行 Ent 代码生成,你可以使用以下两个选项之一:
- Using Ent CLI
- Using the entc package
如果你正在使用默认的生成配置,简单添加 --feature sql/versioned-migration 到 ent/generate.go 文件,如下:
package ent
//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate --feature sql/versioned-migration ./schema
如果你正在使用代码生成包(例如 entgql 一类的 Ent 扩展),像如下添加功能标志:
//go:build ignore
package main
import (
"log"
"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
)
func main() {
err := entc.Generate("./schema", &gen.Config{
Features: []gen.Feature{gen.FeatureVersionedMigration},
})
if err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}
下一步重新运行代码生成:
go generate ./...
运行代码生成后你可以看到如下 方法添加
到 ent/migrate/migrate.go:
DiffNamedDiff
这些方法被用来比较连接的数据库或迁移目录读取的状态与 Ent 模式定义的状态。
2. 自动迁移规划脚本
本部分描述的修改可以在支持的代码仓库中的 PR #4 找到。
开发数据库
为了能够规划准确且一致的迁移文件,Atlas 引入了 开发数据库(Dev database)的概念, 这是一个用来模拟不同变更后数据库状态的临时数据库。 因此使用 Atlas 自动化规划迁移我们需要向迁移脚本提供一个连接字符串到这样一个数据库。 此类数据库通常通过 Docker 容器启动。让我们通过运行以下命令来实现它:
docker run --rm --name atlas-db-dev -d -p 3306:3306 -e MYSQL_DATABASE=dev -e MYSQL_ROOT_PASSWORD=pass mysql:8
通过使用我们刚刚配置的开发数据库,我们可以编写一个脚本使用 Atlas 规划迁移文件。
让我们在项目 ent/migrate 目录中创建一个名为 main.go 的新文件:
//go:build ignore
package main
import (
"context"
"log"
"os"
"<project>/ent/migrate"
atlas "ariga.io/atlas/sql/migrate"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql/schema"
_ "github.com/go-sql-driver/mysql"
)
const (
dir = "ent/migrate/migrations"
)
func main() {
ctx := context.Background()
// Create a local migration directory able to understand Atlas migration file format for replay.
if err := os.MkdirAll(dir, 0755); err != nil {
log.Fatalf("creating migration directory: %v", err)
}
dir, err := atlas.NewLocalDir(dir)
if err != nil {
log.Fatalf("failed creating atlas migration directory: %v", err)
}
// Migrate diff options.
opts := []schema.MigrateOption{
schema.WithDir(dir), // provide migration directory
schema.WithMigrationMode(schema.ModeReplay), // provide migration mode
schema.WithDialect(dialect.MySQL), // Ent dialect to use
schema.WithFormatter(atlas.DefaultFormatter),
}
if len(os.Args) != 2 {
log.Fatalln("migration name is required. Use: 'go run -mod=mod ent/migrate/main.go <name>'")
}
// Generate migrations using Atlas support for MySQL (note the Ent dialect option passed above).
err = migrate.NamedDiff(ctx, "mysql://root:pass@localhost:3306/dev", os.Args[1], opts...)
if err != nil {
log.Fatalf("failed generating migration file: %v", err)
}
}
需注意你需要在上面高亮的行中做出一些脚本修改。
编辑 migrate 包的导入路径以匹配你自己的项目并提供连接到你自己开发数据库的连接字符串。
若要运行此脚本,首先在项目的 ent/migrate 目录创建一个 migrations 目录:
mkdir ent/migrate/migrations
然后运行脚本创建初始的迁移文件:
go run -mod=mod ent/migrate/main.go initial
需注意此处的 initial 只是迁移文件的标签。你可以使用任何其他名称。
可以看到在脚本运行后,在 ent/migrate/migrations 目录中创建了两个新的文件。
第一个文件为 atlas.sum,这是 Atlas 用来强制迁移为线性历史的校验文件:
h1:Dt6N5dIebSto365ZEyIqiBKDqp4INvd7xijLIokqWqA=
20221114165732_initialize.sql h1:/33+7ubMlxuTkW6Ry55HeGEZQ58JqrzaAl2x1TmUTdE=
第二个文件是实际的迁移文件,以我们传入脚本的标签作为命名的结尾:
-- create "users" table
CREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE INDEX `email` (`email`)) CHARSET utf8mb4 COLLATE utf8mb4_bin;
-- create "blogs" table
CREATE TABLE `blogs` (`id` bigint NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `body` longtext NOT NULL, `created_at` timestamp NOT NULL, `user_blog_posts` bigint NULL, PRIMARY KEY (`id`), CONSTRAINT `blogs_users_blog_posts` FOREIGN KEY (`user_blog_posts`) REFERENCES `users` (`id`) ON DELETE SET NULL) CHARSET utf8mb4 COLLATE utf8mb4_bin;
其他迁移工具
Atlas 与 Ent 集成良好,但并不是 Ent 项目用来管理数据库模式的唯一迁移工具。 以下是受支持的其他迁移工具列表:
若要了解这些工具在 Ent 中的使用,参见 文档 中的这一主题。