跳到主要内容

在 Ent Schema 中使用 Postgres 枚举类型

枚举类型是由预定义有序值集合组成的数据结构。默认情况下,在 Ent schema 中使用 field.Enum 时,Ent 会使用简单的字符串类型来表示 PostgreSQL 和 SQLite 中的枚举值。但在某些情况下,您可能需要使用数据库本身提供的原生枚举类型。

本指南将介绍如何定义使用原生 PostgreSQL 枚举类型的 schema 字段,并配置 schema 迁移,使用 Atlas 将 Postgres 枚举和 Ent schema 作为单一迁移单元进行管理。

本指南中使用的 Atlas 组合式 Schema 支持是 Pro 用户的专享功能。要使用此功能,请运行:

atlas login

安装 Atlas

To install the latest release of Atlas, simply run one of the following commands in your terminal, or check out the Atlas website:

curl -sSf https://atlasgo.sh | sh

登录 Atlas

$ atlas login a8m
您现已连接至 Atlas Cloud 上的 "a8m" 账户。

组合式 Schema

ent/schema 包主要用于定义 Ent 类型(对象)、它们的字段、边和逻辑。外部枚举类型或任何其他数据库对象在 Ent 模型中没有表示形式——Postgres 枚举类型可以在 Postgres schema 中定义一次,并在不同字段和模型中多次使用。

为了扩展我们的 PostgreSQL schema 以包含自定义枚举类型和 Ent 类型,我们配置 Atlas 从组合式 Schema 数据源读取 schema 状态。请按照以下步骤为您的项目进行配置:

1. 创建一个 schema.sql 文件,在其中定义必要的枚举类型。同样地,您也可以用 Atlas Schema HCL 语言定义枚举类型:

schema.sql
CREATE TYPE status AS ENUM ('active', 'inactive', 'pending');

2. 在您的 Ent schema 中,定义一个使用底层 Postgres ENUM 类型的枚举字段:

ent/schema/user.go
// User 的字段。
func (User) Fields() []ent.Field {
return []ent.Field{
field.Enum("status").
Values("active", "inactive", "pending").
SchemaType(map[string]string{
dialect.Postgres: "status",
}),
}
}
备注

如果使用了带有自定义驱动程序特定类型的 schema 与其他数据库一起使用,Ent 将回退到驱动程序使用的默认类型(例如,SQLite 中的 TEXT 以及 MariaDB 或 MySQL 中的 ENUM (...))。

3. 创建一个简单的 atlas.hcl 配置文件,其中包含一个 composite_schema,它同时包含了在 schema.sql 中定义的自定义枚举类型和您的 Ent schema:

atlas.hcl
data "composite_schema" "app" {
# 首先加载自定义类型。
schema "public" {
url = "file://schema.sql"
}
# 其次加载 Ent schema。
schema "public" {
url = "ent://ent/schema"
}
}

env "local" {
src = data.composite_schema.app.url
dev = "docker://postgres/15/dev?search_path=public"
}

使用方式

设置好组合式 schema 后,我们可以使用 atlas schema inspect 命令获取其表示形式,为其生成 schema 迁移,将其应用到数据库等。以下是一些让您开始使用 Atlas 的命令:

检查 Schema

atlas schema inspect 命令通常用于检查数据库。但我们也可以使用它来检查我们的 composite_schema 并打印其 SQL 表示形式:

atlas schema inspect \
--env local \
--url env://src \
--format '{{ sql . }}'

上述命令会打印以下 SQL。请注意,status 枚举类型在 users.status 列中使用之前已在 schema 中定义:

-- 创建枚举类型 "status"
CREATE TYPE "status" AS ENUM ('active', 'inactive', 'pending');
-- 创建 "users" 表
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "status" "status" NOT NULL, PRIMARY KEY ("id"));

为 Schema 生成迁移

要为 schema 生成迁移,请运行以下命令:

atlas migrate diff \
--env local

请注意,这会创建一个新的迁移文件,其内容如下:

migrations/20240712090543.sql
-- 创建枚举类型 "status"
CREATE TYPE "status" AS ENUM ('active', 'inactive', 'pending');
-- 创建 "users" 表
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "status" "status" NOT NULL, PRIMARY KEY ("id"));

应用迁移

要将上面生成的迁移应用到数据库,请运行以下命令:

atlas migrate apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
直接在数据库上应用 Schema

有时需要直接在数据库上应用 schema 而不生成迁移文件。例如,在试验 schema 更改、启动测试数据库等情况下。在这种情况下,您可以使用以下命令直接将 schema 应用到数据库:

atlas schema apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"

或者,使用 Atlas Go SDK

ac, err := atlasexec.NewClient(".", "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %w", err)
}
// 自动使用期望的 schema 更新数据库。
// 另一种选择是手动使用 'migrate apply' 或 'schema apply'。
if _, err := ac.SchemaApply(ctx, &atlasexec.SchemaApplyParams{
Env: "local",
URL: "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable",
AutoApprove: true,
}); err != nil {
log.Fatalf("failed to apply schema changes: %w", err)
}

本指南的代码可以在 GitHub 上找到。