メインコンテンツへスキップする

外部テンプレート

entは、--templateフラグを使って実行される場合、外部のGoテンプレートを受け入れます。 テンプレート名がすでにentで定義されている場合は、既存のものを上書きします。 それ以外の場合は、実行出力をテンプレートと同じ名前のファイルに書き込みます。 以下の例をご覧ください。

stringer.tmpl - このテンプレート例は、ent/stringer.goというファイルに書き込まれます。

{{/* 次の行は、Intellij/GoLandに、*gen.Graphタイプに基づいてオートコンプリートを有効にするよう指示する */}}
{{/* 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" }}

{{/* 各クライアント<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
StaticField string `json:"static_field,omitempty"`
{{- end }}
{{ end }}

ヘルパーテンプレート

前述の通り、entは各テンプレートの実行出力を、テンプレートと同じ名前のファイルに書き込みます。 たとえば、{{ define "stringer" }} で定義されたテンプレートの出力は、ent/stringer.goという名前のファイルに書き込まれます。

デフォルトでは、ent{{ define "<name>" }}で宣言された各テンプレートをファイルに書き込みます。 しかし、- 直接呼び出されるのではなく、他のテンプレートによって実行されるテンプレート- ヘルパーテンプレートを定義することが望ましい場合があります。 このために、entはテンプレートをヘルパーとして指定する2つの命名形式をサポートしています。 フォーマットは以下の通りです:

1. グローバルヘルパーテンプレート {{ define "helper/.+" }} 例:

{{ define "helper/foo" }}
{{/* ここにロジックを書く */}}
{{ end }}

{{ define "helper/bar/baz" }}
{{/* ここにロジックを書く */}}
{{ end }}

2. ローカルヘルパーテンプレート {{ define "<root-template>/helper/.+" }} このテンプレートは、その実行出力がファイルに書き込まれる場合、"root"とみなされます。 例:

{{/* このルートテンプレートは、`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 }}

アノテーション

スキーマアノテーションを使用すると、フィールドやエッジにメタデータを付与し、外部テンプレートに注入したりすることができます。
アノテーションは、JSON raw dataにシリアライズ可能なGoの型(struct、map、sliceなど) かつ、Annotationインターフェイスを実装する必要があります。

ここでは、アノテーションの例と、スキーマやテンプレートでの使い方を紹介します:

1. アノテーションの定義

package entgql

// Annotationは、フィールドにテンプレート用のメタデータを付与します
type Annotation struct {
// OrderFieldは、GraphQLスキーマで定義されている順序フィールドです
OrderField string
}

// Name は、ent.Annotation インターフェースを実装しています
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 }}
{{/* アノアテーションを名前で取得する。 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"
)

// アノテーションは、カスタムアノテーションを定義します。
// すべてのテンプレートにグローバルに注入されます。
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.

  • 外部テンプレートをカスタム関数で実行する例。 configurationとその 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