跳到主要内容

外部模板

ent 允许使用 --template 标志来执行外部 Go 语言模板。 如果模板名称已在 ent 中定义则会将其覆盖。否则,它会将执行输出写入到与模板同名的文件中。例如:

stringer.tmpl —— 此模板会被写入到名为 ent/stringer.go 的文件中。

{{/* The line below tells Intellij/GoLand to enable the autocompletion based on the *gen.Graph type. */}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}

{{ define "stringer" }}

{{/* Add the base header for the generated file */}}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}

{{/* Loop over all nodes and implement the "GoStringer" interface */}}
{{ 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" }}

{{/* A template that adds the functionality for running each client <T> in debug mode */}}

{{/* Add the base header for the generated file */}}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}

{{/* Loop over all nodes and add option the "Debug" method */}}
{{ 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 }}

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

{{/* A template for adding additional fields to specific types. */}}
{{ define "model/fields/additional" }}
{{- /* Add static fields to the "Card" entity. */}}
{{- if eq $.Name "Card" }}
// StaticField defined by templates.
StaticField string `json:"static_field,omitempty"`
{{- end }}
{{ end }}

辅助模板

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

默认情况下 ent 将每个 {{ define "<name>" }} 声明的模板写入到每个文件。因此有时会期望定义一个辅助模板 —— 不会直接被使用但是会被其他模板执行。 为满足此需求, ent 支持两种命名格式将模板指定为辅助模板,具体格式如下:

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

{{ define "helper/foo" }}
{{/* Logic goes here. */}}
{{ end }}

{{ define "helper/bar/baz" }}
{{/* Logic goes here. */}}
{{ end }}

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

{{/* A root template that is executed on the `gen.Graph` and will be written to a file named: `ent/http.go`.*/}}
{{ define "http" }}
{{ range $n := $.Nodes }}
{{ template "http/helper/get" $n }}
{{ template "http/helper/post" $n }}
{{ end }}
{{ end }}

{{/* A helper template that is executed on `gen.Type` */}}
{{ define "http/helper/get" }}
{{/* Logic goes here. */}}
{{ end }}

{{/* A helper template that is executed on `gen.Type` */}}
{{ define "http/helper/post" }}
{{/* Logic goes here. */}}
{{ end }}

注解

模式注解允许将元数据附加到字段和边上,并将其注入外部模板。
注解必须是可被序列化为 JSON 原始值的 Go 语言类型(如 struct、map 或 slice)并实现 注解 接口。

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

1. 注解定义:

package entgql

// Annotation annotates fields with metadata for templates.
type Annotation struct {
// OrderField is the ordering field as defined in graphql schema.
OrderField string
}

// Name implements ent.Annotation interface.
func (Annotation) Name() string {
return "EntGQL"
}

2. ent/schema 中使用注解:

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

// Fields of the user.
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 }}
{{/* Get the annotation by its name. See: Annotation.Name */}}
{{ if $annotation := $f.Annotations.EntGQL }}
{{/* Get the field from the annotation. */}}
{{ $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 defines a custom annotation
// to be inject globally to all templates.
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("<path to gqlgen.yml>")
if err != nil {
log.Fatalf("loading gqlgen config: %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("running ent codegen: %v", err)
}
}

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

{{- with $.Annotations.GQL.Config.StructTag }}
{{/* Access the GQL configuration on *gen.Graph */}}
{{- end }}

{{ range $node := $.Nodes }}
{{- with $node.Config.Annotations.GQL.Config.StructTag }}
{{/* Access the GQL configuration on *gen.Type */}}
{{- end }}
{{ end }}

示例

  • 实现 GraphQL Node API 的自定义模板 —— Github.

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

文档

模板在特定节点类型或 模板可在特定节点类型上执行,也可在整个模式图上执行。API 文档参见 GoDoc

自动补全

JetBrains 用户可在模板中添加以下注解以启用自动补全功能:

{{/* The line below tells Intellij/GoLand to enable the autocompletion based on the *gen.Graph type. */}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}

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

效果如下:

template-autocomplete