跳到主要内容

模板 (Templates)

ent 接受外部的 Go 模板,可通过 --template 标志执行。 若模板名称已被 ent 定义,则会覆盖现有模板;否则会将执行输出写入与模板同名的文件中。例如:

stringer.tmpl - 此模板示例将写入名为 ent/stringer.go 的文件中。

{{/* 以下行告知 Intellij/GoLand 启用基于 *gen.Graph 类型的自动补全功能 */}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}

{{ define "stringer" }}

{{/* 为生成的文件添加基础头部 */}}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}

{{/* 遍历所有节点并实现 "GoStringer" 接口 */}}
{{ range $n := $.Nodes }}
{{ $receiver := $n.Receiver }}
func ({{ $receiver }} *{{ $n.Name }}) GoString() string {
if {{ $receiver }} == nil {
return fmt.Sprintf("{{ $n.Name }}(nil)")
}
return {{ $receiver }}.String()
}
{{ end }}

{{ end }}

debug.tmpl - 此模板示例将写入名为 ent/debug.go 的文件中。

{{ define "debug" }}

{{/* 用于为每个客户端 <T> 添加调试模式运行功能的模板 */}}

{{/* 为生成的文件添加基础头部 */}}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}

{{/* 遍历所有节点并为 "Debug" 方法添加选项 */}}
{{ range $n := $.Nodes }}
{{ $client := print $n.Name "Client" }}
func (c *{{ $client }}) Debug() *{{ $client }} {
if c.debug {
return c
}
cfg := config{driver: dialect.Debug(c.driver, c.log), log: c.log, debug: true, hooks: c.hooks}
return &{{ $client }}{config: cfg}
}
{{ end }}

{{ end }}

若要覆盖现有模板,请使用其名称。例如:

{{/* 用于向特定类型添加额外字段的模板 */}}
{{ define "model/fields/additional" }}
{{- /* 向 "Card" 实体添加静态字段 */}}
{{- if eq $.Name "Card" }}
// 由模板定义的静态字段。
StaticField string `json:"static_field,omitempty"`
{{- end }}
{{ end }}

辅助模板

如上所述,ent 会将每个模板的执行输出写入与模板同名的文件中。 例如,定义为 {{ define "stringer" }} 的模板输出将写入名为 ent/stringer.go 的文件。

默认情况下,ent 会将每个用 {{ define "<name>" }} 声明的模板写入文件。但有时可能需要定义辅助模板——这些模板不会被直接调用,而是由其他模板执行。为支持这种用例,ent 支持两种将模板指定为辅助模板的命名格式: 格式如下:

1. {{ define "helper/.+" }} 用于全局辅助模板。例如:

{{ define "helper/foo" }}
{{/* 此处放置逻辑 */}}
{{ end }}

{{ define "helper/bar/baz" }}
{{/* 此处放置逻辑 */}}
{{ end }}

2. {{ define "<root-template>/helper/.+" }} 用于本地辅助模板。若模板的执行输出被写入文件,则视为“根”模板。例如:

{{/* 在 `gen.Graph` 上执行的根模板,将被写入名为 `ent/http.go` 的文件中 */}}
{{ define "http" }}
{{ range $n := $.Nodes }}
{{ template "http/helper/get" $n }}
{{ template "http/helper/post" $n }}
{{ end }}
{{ end }}

{{/* 在 `gen.Type` 上执行的辅助模板 */}}
{{ define "http/helper/get" }}
{{/* 此处放置逻辑 */}}
{{ end }}

{{/* 在 `gen.Type` 上执行的辅助模板 */}}
{{ define "http/helper/post" }}
{{/* 此处放置逻辑 */}}
{{ end }}

注解

Schema 注解允许将元数据附加到字段和边上,并将其注入到外部模板中。
注解必须是一个可序列化为 JSON 原始值的 Go 类型(例如结构体、映射或切片),并实现 Annotation 接口。

以下是在 schema 和模板中使用注解的示例:

1. 注解定义:

package entgql

// Annotation 用于为模板向字段添加元数据。
type Annotation struct {
// OrderField 是 graphql schema 中定义的排序字段。
OrderField string
}

// Name 实现 ent.Annotation 接口。
func (Annotation) Name() string {
return "EntGQL"
}

2. 在 ent/schema 中使用注解:

// User schema.
type User struct {
ent.Schema
}

// 用户的字段。
func (User) Fields() []ent.Field {
return []ent.Field{
field.Time("creation_date").
Annotations(entgql.Annotation{
OrderField: "CREATED_AT",
}),
}
}

3. 在外部模板中使用注解:

{{ range $node := $.Nodes }}
{{ range $f := $node.Fields }}
{{/* 通过名称获取注解。参见:Annotation.Name */}}
{{ if $annotation := $f.Annotations.EntGQL }}
{{/* 从注解中获取字段 */}}
{{ $orderField := $annotation.OrderField }}
{{ end }}
{{ end }}
{{ end }}

全局注解

全局注解是一种注入到 gen.Config 对象中的注解类型,可以在所有模板中全局访问。例如,一个包含配置文件信息(如 gqlgen.ymlswagger.yml)的注解,可以在所有模板中访问:

1. 注解定义:

package gqlconfig

import (
"entgo.io/ent/schema"
"github.com/99designs/gqlgen/codegen/config"
)

// Annotation 定义了一个自定义注解,
// 用于全局注入到所有模板中。
type Annotation struct {
Config *config.Config
}

func (Annotation) Name() string {
return "GQL"
}

var _ schema.Annotation = (*Annotation)(nil)

2.ent/entc.go 中使用注解:

func main() {
cfg, err := config.LoadConfig("<gqlgen.yml 的路径>")
if err != nil {
log.Fatalf("加载 gqlgen 配置失败: %v", err)
}
opts := []entc.Option{
entc.TemplateDir("./template"),
entc.Annotations(gqlconfig.Annotation{Config: cfg}),
}
err = entc.Generate("./schema", &gen.Config{
Templates: entgql.AllTemplates,
}, opts...)
if err != nil {
log.Fatalf("运行 ent 代码生成失败: %v", err)
}
}

3. 在外部模板中使用注解:

{{- with $.Annotations.GQL.Config.StructTag }}
{{/* 在 *gen.Graph 上访问 GQL 配置 */}}
{{- end }}

{{ range $node := $.Nodes }}
{{- with $node.Config.Annotations.GQL.Config.StructTag }}
{{/* 在 *gen.Type 上访问 GQL 配置 */}}
{{- end }}
{{ end }}

示例

  • 为 GraphQL 实现 Node API 的自定义模板 - Github

  • 使用自定义函数执行外部模板的示例。参见 配置 及其 README 文件。

文档

模板在特定节点类型或整个 schema 图上执行。有关 API 文档,请参阅 GoDoc

自动补全

JetBrains 用户可以添加以下模板注释以在其模板中启用自动补全:

{{/* 以下行告知 Intellij/GoLand 启用基于 *gen.Graph 类型的自动补全功能 */}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}

{{ define "template" }}
{{/* ... */}}
{{ end }}

实际效果如下:

模板自动补全