在 Ent 模式中使用复合类型
在 PostgreSQL 中,复合类型是类似于行或记录的结构,由字段名及其对应的数据类型组成。 在 Ent 中设置一个字段为符合类型可以让你能够在单一列中存储复杂的结构化数据。
本指南说明如何在 Ent 模式中将模式字段类型定义为复合类型,并配置模式迁移,以便使用Atlas将复合类型和Ent模式作为单个迁移单元进行管理。
Atlas 只为专业用户提供 复合类型支持,使用这些功能需运行:
atlas login
安装 Atlas
要安装Atlas的最新版本,只需在终端中运行以下任一命令,或访问Atlas 官方网站:
- macOS + Linux
- Homebrew
- Docker
- Windows
curl -sSf https://atlasgo.sh | sh
brew install ariga/tap/atlas
docker pull arigaio/atlas
docker run --rm arigaio/atlas --help
如果容器需要访问主机网络或本地目录,请使用 --net=host 标志挂载所需目录:
docker run --rm --net=host \
-v $(pwd)/migrations:/migrations \
arigaio/atlas migrate apply
--url "mysql://root:pass@:3306/test"
下载 最新版本 并将 atlas 二进制执行文件所在目录加入到系统路径中。
登录 Atlas
$ atlas login a8m
You are now connected to "a8m" on Atlas Cloud.
复合模式
ent/schema 包主要用来定义 Ent 类型(对象),包括字段、边和逻辑等。
复合类型或其他数据库对象在 Ent 模式中不体现,复合类型定义一次,并在不同的字段和模式中可以使用多次。
为扩展 PostgreSQL 模式以包含自定义复合类型和 Ent 类型,可以配置 Atlas 来读取 复合模式 数据源的模式状态。 跟着以下步骤来配置你的项目:
1. 创建 schema.sql 来定义必要的复合类型。同样你可以用 Atlas 模式 HCL 语言 来配置复合类型:
- Using SQL
- Using HCL
CREATE TYPE address AS (
street text,
city text
);
schema "public" {}
composite "address" {
schema = schema.public
field "street" {
type = text
}
field "city" {
type = text
}
}
2. 在 Ent 模式中,仅在 PostgreSQL 方言中使用复合类型来定义字段:
- Schema
- Address Type
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("address").
GoType(&Address{}).
SchemaType(map[string]string{
dialect.Postgres: "address",
}),
}
}
有时模式使用某些数据库自定义驱动特定类型时,Ent 返回驱动使用的默认类型(例如 "varchar")。
type Address struct {
Street, City string
}
var _ field.ValueScanner = (*Address)(nil)
// Scan implements the database/sql.Scanner interface.
func (a *Address) Scan(v interface{}) (err error) {
switch v := v.(type) {
case nil:
case string:
_, err = fmt.Sscanf(v, "(%q,%q)", &a.Street, &a.City)
case []byte:
_, err = fmt.Sscanf(string(v), "(%q,%q)", &a.Street, &a.City)
}
return
}
// Value implements the driver.Valuer interface.
func (a *Address) Value() (driver.Value, error) {
return fmt.Sprintf("(%q,%q)", a.Street, a.City), nil
}
3. 使用包含在 schema.sql 中自定义类型和 Ent 模式的 composite_schema 来创建 atlas.hcl 配置文件:
data "composite_schema" "app" {
# Load first custom types first.
schema "public" {
url = "file://schema.sql"
}
# Second, load the Ent schema.
schema "public" {
url = "ent://ent/schema"
}
}
env "local" {
src = data.composite_schema.app.url
dev = "docker://postgres/15/dev?search_path=public"
}
使用
设置完模式后,我们可以使用 atlas schema inspect 命令来查看其表示、生成迁移或将它们应用到数据库等。以下是几个帮助你开始使用 Atlas 的几个命令:
检查模式
atlas schema inspect 命令通常用来检查数据库。然而我们也可以用它来检查 composite_schema 并打印其 SQL 表示形式:
atlas schema inspect \
--env local \
--url env://src \
--format '{{ sql . }}'
以上命令打印下述 SQL。需要注意 address 复合类型在 address 字段使用之前需要在模式中定义。
-- Create composite type "address"
CREATE TYPE "address" AS ("street" text, "city" text);
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "address" "address" NOT NULL, PRIMARY KEY ("id"));
为模式生成迁移
运行以下命令为模式生成迁移:
atlas migrate diff \
--env local
注意可生成以下内容的新的迁移文件:
-- Create composite type "address"
CREATE TYPE "address" AS ("street" text, "city" text);
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "address" "address" NOT NULL, PRIMARY KEY ("id"));
应用迁移
运行以下命令将生成的迁移应用到数据库:
atlas migrate apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
有时需要在不生成迁移文件的时候将模式直接应用于数据库。例如,尝试模式变更、创建测试数据库等。这种情况下,可以使用下面的命令将模式直接应用于数据库:
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)
}
// Automatically update the database with the desired schema.
// Another option, is to use 'migrate apply' or 'schema apply' manually.
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。