mirror of
https://github.com/ent/ent.git
synced 2026-05-22 09:31:45 +03:00
entc: introduce the entc.Extension api
This commit is contained in:
committed by
Ariel Mashraki
parent
4066255641
commit
52663a4df1
97
entc/entc.go
97
entc/entc.go
@@ -125,8 +125,15 @@ func FeatureNames(names ...string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Annotation is used to attach arbitrary metadata to the schema objects in codegen.
|
||||
// Unlike schema annotations, being serializable to JSON raw value is not mandatory.
|
||||
//
|
||||
// Template extensions can retrieve this metadata and use it inside their execution.
|
||||
// Read more about it in ent website: https://entgo.io/docs/templates/#annotations.
|
||||
type Annotation = schema.Annotation
|
||||
|
||||
// Annotations appends the given annotations to the codegen config.
|
||||
func Annotations(annotations ...schema.Annotation) Option {
|
||||
func Annotations(annotations ...Annotation) Option {
|
||||
return func(cfg *gen.Config) error {
|
||||
if cfg.Annotations == nil {
|
||||
cfg.Annotations = gen.Annotations{}
|
||||
@@ -166,6 +173,94 @@ func TemplateDir(path string) Option {
|
||||
})
|
||||
}
|
||||
|
||||
type (
|
||||
// Extension describes an Ent code generation extension that
|
||||
// allows customizing the code generation and integrate with
|
||||
// other tools and libraries (e.g. GraphQL, gRPC, OpenAPI) by
|
||||
// by registering hooks, templates and global annotations in
|
||||
// one simple call.
|
||||
//
|
||||
// ex, err := entgql.NewExtension(
|
||||
// entgql.WithConfig("../gqlgen.yml"),
|
||||
// entgql.WithSchema("../schema.graphql"),
|
||||
// )
|
||||
// if err != nil {
|
||||
// log.Fatalf("creating graphql extension: %v", err)
|
||||
// }
|
||||
// err = entc.Generate("./schema", &gen.Config{
|
||||
// Templates: entswag.Templates,
|
||||
// }, entc.Extensions(ex))
|
||||
// if err != nil {
|
||||
// log.Fatalf("running ent codegen: %v", err)
|
||||
// }
|
||||
//
|
||||
Extension interface {
|
||||
// Hooks holds an optional list of Hooks to apply
|
||||
// on the graph before/after the code-generation.
|
||||
Hooks() []gen.Hook
|
||||
|
||||
// Annotations injects global annotations to the gen.Config object that
|
||||
// can be accessed globally in all templates. Unlike schema annotations,
|
||||
// being serializable to JSON raw value is not mandatory.
|
||||
//
|
||||
// {{- with $.Config.Annotations.GQL }}
|
||||
// {{/* Annotation usage goes here. */}}
|
||||
// {{- end }}
|
||||
//
|
||||
Annotations() []Annotation
|
||||
|
||||
// Templates specifies a list of alternative templates
|
||||
// to execute or to override the default.
|
||||
Templates() []*gen.Template
|
||||
|
||||
// Options specifies a list of entc.Options to evaluate on
|
||||
// the gen.Config before executing the code generation.
|
||||
Options() []Option
|
||||
}
|
||||
)
|
||||
|
||||
// Extensions evaluates the list of Extensions on the gen.Config.
|
||||
func Extensions(extensions ...Extension) Option {
|
||||
return func(cfg *gen.Config) error {
|
||||
for _, ex := range extensions {
|
||||
cfg.Hooks = append(cfg.Hooks, ex.Hooks()...)
|
||||
cfg.Templates = append(cfg.Templates, ex.Templates()...)
|
||||
for _, opt := range ex.Options() {
|
||||
if err := opt(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := Annotations(ex.Annotations()...)(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultExtension is the default implementation for entc.Extension.
|
||||
//
|
||||
// Embedding this type allow third-party packages to create extensions
|
||||
// without implementing all methods.
|
||||
//
|
||||
// type Extension struct {
|
||||
// entc.DefaultExtension
|
||||
// }
|
||||
//
|
||||
type DefaultExtension struct{}
|
||||
|
||||
// Hooks of the extensions.
|
||||
func (DefaultExtension) Hooks() []gen.Hook { return nil }
|
||||
|
||||
// Annotations of the extensions.
|
||||
func (DefaultExtension) Annotations() gen.Annotations { return nil }
|
||||
|
||||
// Templates of the extensions.
|
||||
func (DefaultExtension) Templates() []*gen.Template { return nil }
|
||||
|
||||
// Options of the extensions.
|
||||
func (DefaultExtension) Options() []Option { return nil }
|
||||
|
||||
// templateOption ensures the template instantiate
|
||||
// once for config and execute the given Option.
|
||||
func templateOption(next func(t *gen.Template) (*gen.Template, error)) Option {
|
||||
|
||||
@@ -18,14 +18,15 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// A usage for custom templates with external functions.
|
||||
// One template is defined in the option below, and the
|
||||
// rest are provided with the `Templates` option.
|
||||
opts := []entc.Option{
|
||||
entc.TemplateFiles("template/stringer.tmpl"),
|
||||
entc.Annotations(Annotation{StructTag: "rql"}),
|
||||
ex, err := NewExtension("json")
|
||||
if err != nil {
|
||||
log.Fatalf("creating extension: %v", err)
|
||||
}
|
||||
err := entc.Generate("./schema", &gen.Config{
|
||||
// A usage for custom options to configure the
|
||||
opts := []entc.Option{
|
||||
entc.Extensions(ex),
|
||||
}
|
||||
err = entc.Generate("./schema", &gen.Config{
|
||||
Header: `
|
||||
// Copyright 2019-present Facebook Inc. All rights reserved.
|
||||
// This source code is licensed under the Apache 2.0 license found
|
||||
@@ -34,20 +35,83 @@ func main() {
|
||||
// Code generated by entc, DO NOT EDIT.
|
||||
`,
|
||||
Templates: []*gen.Template{
|
||||
gen.MustParse(gen.NewTemplate("static").
|
||||
Funcs(template.FuncMap{"title": strings.ToTitle}).
|
||||
ParseFiles("template/static.tmpl")),
|
||||
gen.MustParse(gen.NewTemplate("debug").
|
||||
Funcs(template.FuncMap{"byName": byName}).
|
||||
ParseFiles("template/debug.tmpl")),
|
||||
// Custom templates can be provided by entc.Extension (see below),
|
||||
// or by setting templates on the gen.Config object.
|
||||
//
|
||||
// gen.MustParse(gen.NewTemplate("static").
|
||||
// Funcs(template.FuncMap{"title": strings.ToTitle}).
|
||||
// ParseFiles("template/static.tmpl")),
|
||||
//
|
||||
},
|
||||
Hooks: []gen.Hook{
|
||||
// Hooks can be provided by entc.Extension (see below),
|
||||
// or by setting hooks on the gen.Config object.
|
||||
//
|
||||
// CustomHook1("config 1"),
|
||||
// CustomHook2("config 2"),
|
||||
//
|
||||
},
|
||||
Hooks: []gen.Hook{TagFields("json")},
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
log.Fatalf("running ent codegen: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Extension is an example implementation of entc.Extension.
|
||||
type Extension struct {
|
||||
entc.DefaultExtension
|
||||
tag string
|
||||
templates []*gen.Template
|
||||
}
|
||||
|
||||
// NewExtension creates a new entc.Extension.
|
||||
func NewExtension(tag string) (*Extension, error) {
|
||||
ex := &Extension{tag: tag}
|
||||
t, err := gen.NewTemplate("static").
|
||||
Funcs(template.FuncMap{"title": strings.ToTitle}).
|
||||
ParseFiles("template/static.tmpl")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ex.templates = append(ex.templates, t)
|
||||
t, err = gen.NewTemplate("debug").
|
||||
Funcs(template.FuncMap{"byName": byName}).
|
||||
ParseFiles("template/debug.tmpl")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ex.templates = append(ex.templates, t)
|
||||
return ex, nil
|
||||
}
|
||||
|
||||
// Templates of the extension.
|
||||
func (e *Extension) Templates() []*gen.Template {
|
||||
return e.templates
|
||||
}
|
||||
|
||||
// Hooks of the extension.
|
||||
func (e *Extension) Hooks() []gen.Hook {
|
||||
return []gen.Hook{
|
||||
TagFields(e.tag),
|
||||
}
|
||||
}
|
||||
|
||||
// Annotations of the extension.
|
||||
func (e *Extension) Annotations() []entc.Annotation {
|
||||
return []entc.Annotation{
|
||||
Annotation{StructTag: "rql"},
|
||||
}
|
||||
}
|
||||
|
||||
// Options provides additional options for the extension.
|
||||
func (e *Extension) Options() []entc.Option {
|
||||
return []entc.Option{
|
||||
entc.TemplateFiles("template/stringer.tmpl"),
|
||||
}
|
||||
}
|
||||
|
||||
var _ entc.Extension = (*Extension)(nil)
|
||||
|
||||
// byName returns a node in the graph by its label/name.
|
||||
func byName(g *gen.Graph, name string) (*gen.Type, error) {
|
||||
for _, n := range g.Nodes {
|
||||
|
||||
Reference in New Issue
Block a user