跳到主要内容

在 Ent Schema 中使用域类型

PostgreSQL 域类型是一种用户自定义的数据类型,它扩展了现有类型,允许您添加约束来限制其可保存的值。将字段类型设置为域类型能使您在数据库级别强制执行数据完整性和验证规则。

本指南将说明如何在 Ent schema 中将字段类型定义为域类型,并配置 schema 迁移,以便使用 Atlas 将域和 Ent schema 作为单个迁移单元进行管理。

Atlas 对域类型的支持仅限于 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 模型中并无对应表示——一个域类型可以一次性定义,并可在不同字段和模型中被多次使用。

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

  1. 创建一个 schema.sql 文件来定义必要的域类型。同样,您也可以在 Atlas Schema HCL 语言 中配置域类型:
schema.sql
CREATE DOMAIN us_postal_code AS TEXT
CHECK(
VALUE ~ '^\d{5}$'
OR VALUE ~ '^\d{5}-\d{4}$'
);
  1. 在您的 Ent schema 中,针对 PostgreSQL 方言定义一个使用域类型的字段:
ent/schema/user.go
// User 的字段。
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("postal_code").
SchemaType(map[string]string{
dialect.Postgres: "us_postal_code",
}),
}
}
备注

注意:如果使用了带有自定义驱动特定类型的 schema 且该 schema 与其他数据库一起使用,Ent 将回退到驱动使用的默认类型(例如 "varchar")。

  1. 创建一个简单的 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 命令获取其表示形式,为其生成迁移,将其应用到数据库,等等。以下是几个命令,帮助您开始使用 Atlas:

检查 Schema

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

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

上述命令打印以下 SQL。请注意,us_postal_code 域类型在 postal_code 字段中使用之前在 schema 中定义:

-- 创建域类型 "us_postal_code"
CREATE DOMAIN "us_postal_code" AS text CONSTRAINT "us_postal_code_check" CHECK ((VALUE ~ '^\d{5}$'::text) OR (VALUE ~ '^\d{5}-\d{4}$'::text));
-- 创建 "users" 表
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "postal_code" "us_postal_code" NOT NULL, PRIMARY KEY ("id"));

为 Schema 生成迁移

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

atlas migrate diff \
--env local

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

migrations/20240712090543.sql
-- 创建域类型 "us_postal_code"
CREATE DOMAIN "us_postal_code" AS text CONSTRAINT "us_postal_code_check" CHECK ((VALUE ~ '^\d{5}$'::text) OR (VALUE ~ '^\d{5}-\d{4}$'::text));
-- 创建 "users" 表
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "postal_code" "us_postal_code" 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 上找到。