跳到主要内容

宣布 v0.10:Ent 获得全新的迁移引擎

· 阅读需 7 分钟

亲爱的社区,

我很高兴宣布 Ent 的下一版本 v0.10 已发布。它自 v0.9.1 以来已经过去近六个月,因而在本次发布中自然包含了大量新内容。

尽管如此,我想花时间介绍我们过去几个月一直在努力的重大改进:全新的迁移引擎。

进入: Atlas

Ent 现有的迁移引擎非常出色,它完成了一些非常实用的工作,社区已经在生产环境使用多年。但随着时间推移,一些我们无法通过现有架构解决的问题开始堆积。再者,我们认为现有数据库迁移框架尚有许多不足。行业在过去十年里对安全管理生产系统变更的原则(如基础设施即代码、声明式配置管理)有了大量经验,而这些在大多数此类项目创立时并不存在。

鉴于这些问题相对通用且与应用无论使用何种框架或编程语言相关,我们看到了将其作为任何项目都可使用的公共基础设施进行修复的机会。因此,除了重写 Ent 的迁移引擎外,我们决定将该解决方案提取为新的开源项目,[Atlas]

Atlas 以 CLI 工具形式发布,使用基于 HCL(类似 Terraform)的新 [DDL],但也可以作为 [Go 包] 使用。
与 Ent 一样,Atlas 采用 Apache License 2.0 许可。

最终,在大量工作和测试后,Atlas 与 Ent 的集成已可供使用。对于许多在现有迁移系统中无法充分解决的用户(如 #1652、#1631、#1625、#1546 和 #1845),这无疑是好消息;现在他们的问题已通过 Atlas 引擎得到解决。

像任何重大变更一样,当前使用 Atlas 作为迁移引擎是可选的。未来我们将切换为默认使用,并最终废弃现有引擎。此过程将逐步推进,我们会根据社区的正面反馈来加速。

开始使用 Atlas 迁移(Ent)

首先,将 Ent 升级到最新版本:

go get entgo.io/ent@v0.10.0
package main
import (
"context"
"log"
"<project>/ent"
"<project>/ent/migrate"
"entgo.io/ent/dialect/sql/schema"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("连接到 MySQL 失败: %v", err)
}
defer client.Close()
ctx := context.Background()
// 运行迁移。
err = client.Schema.Create(ctx, schema.WithAtlas(true))
if err != nil {
log.Fatalf("创建模式资源失败: %v", err)
}
}

就这么完事了!

Atlas 引擎相较于现有 Ent 代码的一个显著优势是其分层结构,能够清晰地区分 Inspection(了解数据库的当前状态)、Diffing(计算当前与期望状态之间的差异)、Planning(计算具体的修复计划)和 Applying(执行应用)。
atlas-migration-process

除了标准选项(如 WithDropColumnWithGlobalUniqueID)外,Atlas 集成还提供了额外选项,用于钩入架构迁移步骤。

下面给出两个示例,展示如何钩入 Atlas 的 DiffApply 步骤。

package main
import (
"context"
"log"
"<project>/ent"
"<project>/ent/migrate"
"ariga.io/atlas/sql/migrate"
atlas "ariga.io/atlas/sql/schema"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql/schema"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("连接到 MySQL 失败: %v", err)
}
defer client.Close()
ctx := context.Background()
// 运行迁移。
err := client.Schema.Create(
ctx,
// 钩住 Atlas Diff 过程。
schema.WithDiffHook(func(next schema.Differ) schema.Differ {
return schema.DiffFunc(func(current, desired *atlas.Schema) ([]atlas.Change, error) {
// 在计算更改之前。
changes, err := next.Diff(current, desired)
if err != nil {
return nil, err
}
// diff后,可以过滤
// 更改或返回新更改。
return changes, nil
})
}),
// 钩住 Atlas Apply 过程。
schema.WithApplyHook(func(next schema.Applier) schema.Applier {
return schema.ApplyFunc(func(ctx context.Context, conn dialect.ExecQuerier, plan *migrate.Plan) error {
// 示例:钩住应用过程,或实现
// 自定义应用器。例如,写入文件。
//
// for _, c := range plan.Changes {
// fmt.Printf("%s: %s", c.Comment, c.Cmd)
// if err := conn.Exec(ctx, c.Cmd, c.Args, nil); err != nil {
// return err
// }
// }
//
return next.Apply(ctx, conn, plan)
})
}),
)
if err != nil {
log.Fatalf("创建模式资源失败: %v", err)
}
}

接下来是什么:v0.11

我知道我们花了一段时间才把这个版本推出,但下一个版本正近在咫尺。以下是 v0.11 的内容:

  • 为边缘/关系模式添加支持 - 支持在关系中附加元数据字段。
  • 重新实现 GraphQL 集成,以完全兼容 Relay 规范。
  • 为“迁移编写”添加支持:Atlas 库提供了用于创建“版本化”迁移目录的基础设施,这在许多迁移框架(如 Flyway、Liquibase、go-migrate 等)中常见。许多用户已为此类系统构建集成方案,我们计划利用 Atlas 提供稳固的基础设施。
  • 查询钩子(拦截器) - 目前仅为 Mutations 提供钩子。许多用户也请求为读取操作添加支持。
  • 多态边缘 - 关于为多态添加支持的问题已开放超过一年。随着 Go 泛型类型支持在 1.18 中推出,我们想重新开启关于使用它们实现的讨论。

收尾

除了关于新迁移引擎的激动人心的宣布之外,本次发布在规模和内容上都非常庞大,包含 199 次提交来自 42 位独特贡献者。Ent 是一次社区协作,凭借大家的努力日益完善。因此,向所有参与此次发布的成员致以衷心感谢与无限赞誉(按字母顺序):

attackordie,
bbkane,
bodokaiser,
cjraa,
dakimura,
dependabot,
EndlessIdea,
ernado,
evanlurvey,
freb,
genevieve,
giautm,
grevych,
hedwigz,
heliumbrain,
hilakashai,
HurSungYun,
idc77,
isoppp,
JeremyV2014,
Laconty,
lenuse,
masseelch,
mattn,
mookjp,
msal4,
naormatania,
odeke-em,
peanut-cc,
posener,
RiskyFeryansyahP,
rotemtam,
s-takehana,
sadmansakib,
sashamelentyev,
seiichi1101,
sivchari,
storyicon,
tarrencev,
ThinkontrolSY,
timoha,
vecpeng,
yonidavidson, 以及
zeevmoney

祝好,
Ariel

更多 Ent 新闻与更新: