mirror of
https://github.com/ent/ent.git
synced 2026-04-28 05:30:56 +03:00
entc/gen: introduce the entc.Dependency option
This commit is contained in:
committed by
Ariel Mashraki
parent
5bbd973ffa
commit
82eeeb5a1c
179
entc/entc.go
179
entc/entc.go
@@ -12,12 +12,14 @@ import (
|
||||
"go/token"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"entgo.io/ent/entc/gen"
|
||||
"entgo.io/ent/entc/internal"
|
||||
"entgo.io/ent/entc/load"
|
||||
"entgo.io/ent/schema"
|
||||
"entgo.io/ent/schema/field"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
@@ -173,51 +175,49 @@ 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.
|
||||
// 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
|
||||
// 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)
|
||||
// }
|
||||
//
|
||||
type 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.
|
||||
//
|
||||
// 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)
|
||||
// }
|
||||
// {{- with $.Config.Annotations.GQL }}
|
||||
// {{/* Annotation usage goes here. */}}
|
||||
// {{- end }}
|
||||
//
|
||||
Extension interface {
|
||||
// Hooks holds an optional list of Hooks to apply
|
||||
// on the graph before/after the code-generation.
|
||||
Hooks() []gen.Hook
|
||||
Annotations() []Annotation
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
}
|
||||
)
|
||||
// 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 {
|
||||
@@ -263,6 +263,95 @@ func (DefaultExtension) Options() []Option { return nil }
|
||||
|
||||
var _ Extension = (*DefaultExtension)(nil)
|
||||
|
||||
// DependencyOption allows configuring optional dependencies using functional options.
|
||||
type DependencyOption func(*gen.DependencyAnnotation) error
|
||||
|
||||
// DependencyType sets the type of the struct field in
|
||||
// the generated builders for the configured dependency.
|
||||
func DependencyType(v interface{}) DependencyOption {
|
||||
return func(d *gen.DependencyAnnotation) error {
|
||||
if v == nil {
|
||||
return errors.New("nil dependency type")
|
||||
}
|
||||
t := reflect.TypeOf(v)
|
||||
tv := indirect(t)
|
||||
d.Type = &field.TypeInfo{
|
||||
Ident: t.String(),
|
||||
PkgPath: tv.PkgPath(),
|
||||
RType: &field.RType{
|
||||
Kind: t.Kind(),
|
||||
Name: tv.Name(),
|
||||
Ident: tv.String(),
|
||||
PkgPath: tv.PkgPath(),
|
||||
},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DependencyTypeInfo is similar to DependencyType, but
|
||||
// allows setting the field.TypeInfo explicitly.
|
||||
func DependencyTypeInfo(t *field.TypeInfo) DependencyOption {
|
||||
return func(d *gen.DependencyAnnotation) error {
|
||||
if t == nil {
|
||||
return errors.New("nil dependency type info")
|
||||
}
|
||||
d.Type = t
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DependencyField sets the struct field and the option name
|
||||
// of the dependency in the generated builders.
|
||||
func DependencyName(name string) DependencyOption {
|
||||
return func(d *gen.DependencyAnnotation) error {
|
||||
d.Field = name
|
||||
d.Option = name
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Dependency allows configuring optional dependencies as struct fields on the
|
||||
// generated builders. For example:
|
||||
//
|
||||
// opts := []entc.Option{
|
||||
// entc.Dependency(
|
||||
// entc.DependencyType(&http.Client{}),
|
||||
// ),
|
||||
// entc.Dependency(
|
||||
// entc.DependencyName("DB"),
|
||||
// entc.DependencyType(&sql.DB{}),
|
||||
// )
|
||||
// }
|
||||
// if err := entc.Generate("./ent/path", &gen.Config{}, opts...); err != nil {
|
||||
// log.Fatalf("running ent codegen: %v", err)
|
||||
// }
|
||||
//
|
||||
func Dependency(opts ...DependencyOption) Option {
|
||||
return func(cfg *gen.Config) error {
|
||||
d := &gen.DependencyAnnotation{}
|
||||
for _, opt := range opts {
|
||||
if err := opt(d); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := d.Build(); err != nil {
|
||||
return err
|
||||
}
|
||||
if cfg.Annotations == nil {
|
||||
cfg.Annotations = gen.Annotations{}
|
||||
}
|
||||
v, ok := cfg.Annotations[d.Name()]
|
||||
if !ok {
|
||||
v = []*gen.DependencyAnnotation{d}
|
||||
} else {
|
||||
v = append(v.([]*gen.DependencyAnnotation), d)
|
||||
}
|
||||
cfg.Annotations[d.Name()] = v
|
||||
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 {
|
||||
@@ -307,3 +396,11 @@ func mayRecover(err error, schemaPath string, cfg *gen.Config) error {
|
||||
target := filepath.Join(cfg.Target, "internal/schema.go")
|
||||
return (&internal.Snapshot{Path: target, Config: cfg}).Restore()
|
||||
}
|
||||
|
||||
// indirect returns the type at the end of indirection.
|
||||
func indirect(t reflect.Type) reflect.Type {
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -8,11 +8,13 @@ package gen
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"text/template/parse"
|
||||
@@ -754,6 +756,76 @@ func (a assets) format() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DependencyAnnotation allows configuring optional dependencies as struct fields on the
|
||||
// generated builders. For example:
|
||||
//
|
||||
// DependencyAnnotation{
|
||||
// Field: "HTTPClient",
|
||||
// Type: "*http.Client",
|
||||
// Option: "WithClient",
|
||||
// }
|
||||
//
|
||||
// Although the DependencyAnnotation is exported, used should use the entc.OptionalDependency
|
||||
// option in order to build this annotation.
|
||||
type DependencyAnnotation struct {
|
||||
// Field defines the struct field name on the builders.
|
||||
// It defaults to the full type name. For example:
|
||||
//
|
||||
// http.Client => HTTPClient
|
||||
// net.Conn => NetConn
|
||||
// url.URL => URL
|
||||
//
|
||||
Field string
|
||||
// Type defines the type identifier. For example, `*http.Client`.
|
||||
Type *field.TypeInfo
|
||||
// Option defines the name of the config option.
|
||||
// It defaults to the field name.
|
||||
Option string
|
||||
}
|
||||
|
||||
// Name describes the annotation name.
|
||||
func (DependencyAnnotation) Name() string {
|
||||
return "Dependencies"
|
||||
}
|
||||
|
||||
// Build builds the annotation and fails if it is invalid.
|
||||
func (d *DependencyAnnotation) Build() error {
|
||||
if d.Type == nil {
|
||||
return errors.New("entc/gen: missing dependency type")
|
||||
}
|
||||
if d.Field == "" {
|
||||
name, err := d.defaultName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Field = name
|
||||
}
|
||||
if d.Option == "" {
|
||||
d.Option = d.Field
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DependencyAnnotation) defaultName() (string, error) {
|
||||
var pkg, name string
|
||||
switch parts := strings.Split(strings.TrimLeft(d.Type.Ident, "[]*"), "."); len(parts) {
|
||||
case 1:
|
||||
name = parts[0]
|
||||
case 2:
|
||||
name = parts[1]
|
||||
// Avoid stuttering.
|
||||
if !strings.EqualFold(parts[0], name) {
|
||||
pkg = parts[0]
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("entc/gen: unexpected number of parts: %q", parts)
|
||||
}
|
||||
if r := d.Type.RType; r != nil && (r.Kind == reflect.Array || r.Kind == reflect.Slice) {
|
||||
name = plural(name)
|
||||
}
|
||||
return pascal(pkg) + pascal(name), nil
|
||||
}
|
||||
|
||||
// expect panics if the condition is false.
|
||||
func expect(cond bool, msg string, args ...interface{}) {
|
||||
if !cond {
|
||||
|
||||
@@ -396,3 +396,46 @@ func TestGraph_Hooks(t *testing.T) {
|
||||
require.NotNil(graph)
|
||||
require.EqualError(graph.Gen(), `struct tag "yaml" is missing for field T1.age`)
|
||||
}
|
||||
|
||||
func TestDependencyAnnotation_Build(t *testing.T) {
|
||||
tests := []struct {
|
||||
typ *field.TypeInfo
|
||||
field string
|
||||
}{
|
||||
{
|
||||
typ: &field.TypeInfo{
|
||||
Ident: "*http.Client",
|
||||
},
|
||||
field: "HTTPClient",
|
||||
},
|
||||
{
|
||||
typ: &field.TypeInfo{
|
||||
Ident: "[]*http.Client",
|
||||
RType: &field.RType{
|
||||
Kind: reflect.Slice,
|
||||
},
|
||||
},
|
||||
field: "HTTPClients",
|
||||
},
|
||||
{
|
||||
typ: &field.TypeInfo{
|
||||
Ident: "[]*url.URL",
|
||||
RType: &field.RType{
|
||||
Kind: reflect.Slice,
|
||||
},
|
||||
},
|
||||
field: "URLs",
|
||||
},
|
||||
{
|
||||
typ: &field.TypeInfo{
|
||||
Ident: "*net.Conn",
|
||||
},
|
||||
field: "NetConn",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
d := &DependencyAnnotation{Type: tt.typ}
|
||||
require.NoError(t, d.Build())
|
||||
require.Equal(t, tt.field, d.Field)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,21 @@ in the LICENSE file in the root directory of this source tree.
|
||||
{{ define "config" }}
|
||||
|
||||
{{ $pkg := base $.Config.Package }}
|
||||
{{/* Additional dependencies. */}}
|
||||
{{ $deps := list }}{{ with $.Config.Annotations }}{{ $deps = $.Config.Annotations.Dependencies }}{{ end }}
|
||||
|
||||
{{ template "header" $ }}
|
||||
|
||||
{{ template "import" $ }}
|
||||
|
||||
{{ with $deps }}
|
||||
import (
|
||||
{{- range $dep := $deps }}
|
||||
{{ $dep.Type.PkgName }} "{{ $dep.Type.PkgPath }}"
|
||||
{{- end }}
|
||||
)
|
||||
{{ end }}
|
||||
|
||||
// Option function to configure the client.
|
||||
type Option func(*config)
|
||||
|
||||
@@ -26,6 +37,10 @@ type config struct {
|
||||
log func(...interface{})
|
||||
// hooks to execute on mutations.
|
||||
hooks *hooks
|
||||
{{- /* Additional dependency fields. */}}
|
||||
{{- range $dep := $deps }}
|
||||
{{ $dep.Field }} {{ $dep.Type }}
|
||||
{{- end }}
|
||||
{{- /* Support adding config fields from both global or dialect-specific templates. */}}
|
||||
{{- range $prefix := list "" (printf "dialect/%s/" $.Storage) }}
|
||||
{{- with $tmpls := matchTemplate (print $prefix "config/fields/*") }}
|
||||
@@ -74,6 +89,16 @@ func Driver(driver dialect.Driver) Option {
|
||||
}
|
||||
}
|
||||
|
||||
{{- /* Additional dependency options. */}}
|
||||
{{- range $dep := $deps }}
|
||||
// {{ $dep.Option }} configures the {{ $dep.Field }}.
|
||||
func {{ $dep.Option }}(v {{ $dep.Type }}) Option {
|
||||
return func(c *config) {
|
||||
c.{{ $dep.Field }} = v
|
||||
}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{- /* Support adding config options from both global or dialect-specific templates. */}}
|
||||
{{- range $prefix := list "" (printf "dialect/%s/" $.Storage) }}
|
||||
{{- with $tmpls := matchTemplate (print $prefix "config/options/*") }}
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
// Package internal holds a loadable version of the latest schema.
|
||||
package internal
|
||||
|
||||
const Schema = `{"Schema":"entgo.io/ent/entc/integration/hooks/ent/schema","Package":"entgo.io/ent/entc/integration/hooks/ent","Schemas":[{"name":"Card","config":{"Table":""},"edges":[{"name":"owner","type":"User","ref_name":"cards","unique":true,"inverse":true}],"fields":[{"name":"number","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"default":true,"default_value":"unknown","default_kind":24,"immutable":true,"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0},"comment":"Exact name written on card"},{"name":"created_at","type":{"Type":2,"Ident":"","PkgPath":"time","Nillable":false,"RType":null},"default":true,"default_kind":19,"position":{"Index":2,"MixedIn":false,"MixinIndex":0}},{"name":"in_hook","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"position":{"Index":3,"MixedIn":false,"MixinIndex":0},"comment":"A mandatory field that is set by the hook"}],"hooks":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":false,"MixinIndex":0},{"Index":1,"MixedIn":false,"MixinIndex":0}]},{"name":"User","config":{"Table":""},"edges":[{"name":"cards","type":"Card"},{"name":"friends","type":"User"},{"name":"best_friend","type":"User","unique":true}],"fields":[{"name":"version","type":{"Type":12,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"default":true,"default_value":0,"default_kind":2,"position":{"Index":0,"MixedIn":true,"MixinIndex":0}},{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"worth","type":{"Type":17,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0}}],"hooks":[{"Index":0,"MixedIn":true,"MixinIndex":0}]}],"Features":["schema/snapshot"]}`
|
||||
const Schema = `{"Schema":"entgo.io/ent/entc/integration/hooks/ent/schema","Package":"entgo.io/ent/entc/integration/hooks/ent","Schemas":[{"name":"Card","config":{"Table":""},"edges":[{"name":"owner","type":"User","ref_name":"cards","unique":true,"inverse":true}],"fields":[{"name":"number","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"default":true,"default_value":"unknown","default_kind":24,"immutable":true,"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0},"comment":"Exact name written on card"},{"name":"created_at","type":{"Type":2,"Ident":"","PkgPath":"time","PkgName":"","Nillable":false,"RType":null},"default":true,"default_kind":19,"position":{"Index":2,"MixedIn":false,"MixinIndex":0}},{"name":"in_hook","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"position":{"Index":3,"MixedIn":false,"MixinIndex":0},"comment":"A mandatory field that is set by the hook"}],"hooks":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":false,"MixinIndex":0},{"Index":1,"MixedIn":false,"MixinIndex":0}]},{"name":"User","config":{"Table":""},"edges":[{"name":"cards","type":"Card"},{"name":"friends","type":"User"},{"name":"best_friend","type":"User","unique":true}],"fields":[{"name":"version","type":{"Type":12,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"default":true,"default_value":0,"default_kind":2,"position":{"Index":0,"MixedIn":true,"MixinIndex":0}},{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"worth","type":{"Type":17,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0}}],"hooks":[{"Index":0,"MixedIn":true,"MixinIndex":0}]}],"Features":["schema/snapshot"]}`
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
// Package internal holds a loadable version of the latest schema.
|
||||
package internal
|
||||
|
||||
const Schema = `{"Schema":"entgo.io/ent/entc/integration/privacy/ent/schema","Package":"entgo.io/ent/entc/integration/privacy/ent","Schemas":[{"name":"Task","config":{"Table":""},"edges":[{"name":"teams","type":"Team"},{"name":"owner","type":"User","ref_name":"tasks","unique":true,"inverse":true}],"fields":[{"name":"title","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"description","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0}},{"name":"status","type":{"Type":6,"Ident":"task.Status","PkgPath":"","Nillable":false,"RType":null},"enums":[{"N":"planned","V":"planned"},{"N":"in_progress","V":"in_progress"},{"N":"closed","V":"closed"}],"default":true,"default_value":"planned","default_kind":24,"position":{"Index":2,"MixedIn":false,"MixinIndex":0}},{"name":"uuid","type":{"Type":4,"Ident":"uuid.UUID","PkgPath":"github.com/google/uuid","Nillable":true,"RType":{"Name":"UUID","Ident":"uuid.UUID","Kind":17,"PkgPath":"github.com/google/uuid","Methods":{"ClockSequence":{"In":[],"Out":[{"Name":"int","Ident":"int","Kind":2,"PkgPath":"","Methods":null}]},"Domain":{"In":[],"Out":[{"Name":"Domain","Ident":"uuid.Domain","Kind":8,"PkgPath":"github.com/google/uuid","Methods":null}]},"ID":{"In":[],"Out":[{"Name":"uint32","Ident":"uint32","Kind":10,"PkgPath":"","Methods":null}]},"MarshalBinary":{"In":[],"Out":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null},{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"MarshalText":{"In":[],"Out":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null},{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"NodeID":{"In":[],"Out":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null}]},"Scan":{"In":[{"Name":"","Ident":"interface {}","Kind":20,"PkgPath":"","Methods":null}],"Out":[{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"String":{"In":[],"Out":[{"Name":"string","Ident":"string","Kind":24,"PkgPath":"","Methods":null}]},"Time":{"In":[],"Out":[{"Name":"Time","Ident":"uuid.Time","Kind":6,"PkgPath":"github.com/google/uuid","Methods":null}]},"URN":{"In":[],"Out":[{"Name":"string","Ident":"string","Kind":24,"PkgPath":"","Methods":null}]},"UnmarshalBinary":{"In":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null}],"Out":[{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"UnmarshalText":{"In":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null}],"Out":[{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"Value":{"In":[],"Out":[{"Name":"Value","Ident":"driver.Value","Kind":20,"PkgPath":"database/sql/driver","Methods":null},{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"Variant":{"In":[],"Out":[{"Name":"Variant","Ident":"uuid.Variant","Kind":8,"PkgPath":"github.com/google/uuid","Methods":null}]},"Version":{"In":[],"Out":[{"Name":"Version","Ident":"uuid.Version","Kind":8,"PkgPath":"github.com/google/uuid","Methods":null}]}}}},"optional":true,"position":{"Index":3,"MixedIn":false,"MixinIndex":0}}],"hooks":[{"Index":0,"MixedIn":false,"MixinIndex":0}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":true,"MixinIndex":1},{"Index":0,"MixedIn":false,"MixinIndex":0}]},{"name":"Team","config":{"Table":""},"edges":[{"name":"tasks","type":"Task","ref_name":"teams","inverse":true},{"name":"users","type":"User","ref_name":"teams","inverse":true}],"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":false,"MixinIndex":0}]},{"name":"User","config":{"Table":""},"edges":[{"name":"teams","type":"Team"},{"name":"tasks","type":"Task"}],"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"unique":true,"immutable":true,"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"age","type":{"Type":17,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":true,"MixinIndex":1},{"Index":0,"MixedIn":false,"MixinIndex":0}]}],"Features":["privacy","entql","schema/snapshot"]}`
|
||||
const Schema = `{"Schema":"entgo.io/ent/entc/integration/privacy/ent/schema","Package":"entgo.io/ent/entc/integration/privacy/ent","Schemas":[{"name":"Task","config":{"Table":""},"edges":[{"name":"teams","type":"Team"},{"name":"owner","type":"User","ref_name":"tasks","unique":true,"inverse":true}],"fields":[{"name":"title","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"description","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0}},{"name":"status","type":{"Type":6,"Ident":"task.Status","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"enums":[{"N":"planned","V":"planned"},{"N":"in_progress","V":"in_progress"},{"N":"closed","V":"closed"}],"default":true,"default_value":"planned","default_kind":24,"position":{"Index":2,"MixedIn":false,"MixinIndex":0}},{"name":"uuid","type":{"Type":4,"Ident":"uuid.UUID","PkgPath":"github.com/google/uuid","PkgName":"","Nillable":true,"RType":{"Name":"UUID","Ident":"uuid.UUID","Kind":17,"PkgPath":"github.com/google/uuid","Methods":{"ClockSequence":{"In":[],"Out":[{"Name":"int","Ident":"int","Kind":2,"PkgPath":"","Methods":null}]},"Domain":{"In":[],"Out":[{"Name":"Domain","Ident":"uuid.Domain","Kind":8,"PkgPath":"github.com/google/uuid","Methods":null}]},"ID":{"In":[],"Out":[{"Name":"uint32","Ident":"uint32","Kind":10,"PkgPath":"","Methods":null}]},"MarshalBinary":{"In":[],"Out":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null},{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"MarshalText":{"In":[],"Out":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null},{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"NodeID":{"In":[],"Out":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null}]},"Scan":{"In":[{"Name":"","Ident":"interface {}","Kind":20,"PkgPath":"","Methods":null}],"Out":[{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"String":{"In":[],"Out":[{"Name":"string","Ident":"string","Kind":24,"PkgPath":"","Methods":null}]},"Time":{"In":[],"Out":[{"Name":"Time","Ident":"uuid.Time","Kind":6,"PkgPath":"github.com/google/uuid","Methods":null}]},"URN":{"In":[],"Out":[{"Name":"string","Ident":"string","Kind":24,"PkgPath":"","Methods":null}]},"UnmarshalBinary":{"In":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null}],"Out":[{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"UnmarshalText":{"In":[{"Name":"","Ident":"[]uint8","Kind":23,"PkgPath":"","Methods":null}],"Out":[{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"Value":{"In":[],"Out":[{"Name":"Value","Ident":"driver.Value","Kind":20,"PkgPath":"database/sql/driver","Methods":null},{"Name":"error","Ident":"error","Kind":20,"PkgPath":"","Methods":null}]},"Variant":{"In":[],"Out":[{"Name":"Variant","Ident":"uuid.Variant","Kind":8,"PkgPath":"github.com/google/uuid","Methods":null}]},"Version":{"In":[],"Out":[{"Name":"Version","Ident":"uuid.Version","Kind":8,"PkgPath":"github.com/google/uuid","Methods":null}]}}}},"optional":true,"position":{"Index":3,"MixedIn":false,"MixinIndex":0}}],"hooks":[{"Index":0,"MixedIn":false,"MixinIndex":0}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":true,"MixinIndex":1},{"Index":0,"MixedIn":false,"MixinIndex":0}]},{"name":"Team","config":{"Table":""},"edges":[{"name":"tasks","type":"Task","ref_name":"teams","inverse":true},{"name":"users","type":"User","ref_name":"teams","inverse":true}],"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":false,"MixinIndex":0}]},{"name":"User","config":{"Table":""},"edges":[{"name":"teams","type":"Team"},{"name":"tasks","type":"Task"}],"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"unique":true,"immutable":true,"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"age","type":{"Type":17,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":true,"MixinIndex":1},{"Index":0,"MixedIn":false,"MixinIndex":0}]}],"Features":["privacy","entql","schema/snapshot"]}`
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
package ent
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
)
|
||||
@@ -23,7 +26,9 @@ type config struct {
|
||||
// log used for logging on debug mode.
|
||||
log func(...interface{})
|
||||
// hooks to execute on mutations.
|
||||
hooks *hooks
|
||||
hooks *hooks
|
||||
HTTPClient *http.Client
|
||||
Writer io.Writer
|
||||
}
|
||||
|
||||
// hooks per client, for fast access.
|
||||
@@ -61,3 +66,17 @@ func Driver(driver dialect.Driver) Option {
|
||||
c.driver = driver
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPClient configures the HTTPClient.
|
||||
func HTTPClient(v *http.Client) Option {
|
||||
return func(c *config) {
|
||||
c.HTTPClient = v
|
||||
}
|
||||
}
|
||||
|
||||
// Writer configures the Writer.
|
||||
func Writer(v io.Writer) Option {
|
||||
return func(c *config) {
|
||||
c.Writer = v
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,14 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"entgo.io/ent/entc"
|
||||
"entgo.io/ent/entc/gen"
|
||||
"entgo.io/ent/schema"
|
||||
"entgo.io/ent/schema/field"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -23,9 +25,20 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalf("creating extension: %v", err)
|
||||
}
|
||||
// A usage for custom options to configure the
|
||||
// A usage for custom options to configure the code generator to use
|
||||
// an extension and inject external dependencies in the generated API.
|
||||
opts := []entc.Option{
|
||||
entc.Extensions(ex),
|
||||
entc.Dependency(
|
||||
entc.DependencyType(&http.Client{}),
|
||||
),
|
||||
entc.Dependency(
|
||||
entc.DependencyName("Writer"),
|
||||
entc.DependencyTypeInfo(&field.TypeInfo{
|
||||
Ident: "io.Writer",
|
||||
PkgPath: "io",
|
||||
}),
|
||||
),
|
||||
}
|
||||
err = entc.Generate("./schema", &gen.Config{
|
||||
Header: `
|
||||
|
||||
@@ -8,20 +8,36 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"entgo.io/ent/examples/entcpkg/ent"
|
||||
"entgo.io/ent/examples/entcpkg/ent/hook"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func Example_EntcPkg() {
|
||||
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
|
||||
client, err := ent.Open(
|
||||
"sqlite3",
|
||||
"file:ent?mode=memory&cache=shared&_fk=1",
|
||||
ent.Writer(os.Stdout),
|
||||
ent.HTTPClient(http.DefaultClient),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("failed opening connection to sqlite: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
// An example for using the injected dependencies in the generated builders.
|
||||
client.User.Use(func(next ent.Mutator) ent.Mutator {
|
||||
return hook.UserFunc(func(ctx context.Context, m *ent.UserMutation) (ent.Value, error) {
|
||||
_ = m.HTTPClient
|
||||
_ = m.Writer
|
||||
return next.Mutate(ctx, m)
|
||||
})
|
||||
})
|
||||
ctx := context.Background()
|
||||
// run the auto migration tool.
|
||||
// Run the auto migration tool.
|
||||
if err := client.Schema.Create(ctx); err != nil {
|
||||
log.Fatalf("failed creating schema resources: %v", err)
|
||||
}
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
// Package internal holds a loadable version of the latest schema.
|
||||
package internal
|
||||
|
||||
const Schema = `{"Schema":"entgo.io/ent/examples/privacyadmin/ent/schema","Package":"entgo.io/ent/examples/privacyadmin/ent","Schemas":[{"name":"User","config":{"Table":""},"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"default":true,"default_value":"Unknown","default_kind":24,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":false,"MixinIndex":0}]}],"Features":["schema/snapshot","privacy"]}`
|
||||
const Schema = `{"Schema":"entgo.io/ent/examples/privacyadmin/ent/schema","Package":"entgo.io/ent/examples/privacyadmin/ent","Schemas":[{"name":"User","config":{"Table":""},"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"default":true,"default_value":"Unknown","default_kind":24,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":false,"MixinIndex":0}]}],"Features":["schema/snapshot","privacy"]}`
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
// Package internal holds a loadable version of the latest schema.
|
||||
package internal
|
||||
|
||||
const Schema = `{"Schema":"entgo.io/ent/examples/privacytenant/ent/schema","Package":"entgo.io/ent/examples/privacytenant/ent","Schemas":[{"name":"Group","config":{"Table":""},"edges":[{"name":"tenant","type":"Tenant","unique":true,"required":true},{"name":"users","type":"User","ref_name":"groups","inverse":true}],"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"default":true,"default_value":"Unknown","default_kind":24,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":true,"MixinIndex":1},{"Index":0,"MixedIn":false,"MixinIndex":0}]},{"name":"Tenant","config":{"Table":""},"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":false,"MixinIndex":0}]},{"name":"User","config":{"Table":""},"edges":[{"name":"tenant","type":"Tenant","unique":true,"required":true},{"name":"groups","type":"Group"}],"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"default":true,"default_value":"Unknown","default_kind":24,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"foods","type":{"Type":3,"Ident":"[]string","PkgPath":"","Nillable":true,"RType":{"Name":"","Ident":"[]string","Kind":23,"PkgPath":"","Methods":{}}},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":true,"MixinIndex":1}]}],"Features":["privacy","entql","schema/snapshot"]}`
|
||||
const Schema = `{"Schema":"entgo.io/ent/examples/privacytenant/ent/schema","Package":"entgo.io/ent/examples/privacytenant/ent","Schemas":[{"name":"Group","config":{"Table":""},"edges":[{"name":"tenant","type":"Tenant","unique":true,"required":true},{"name":"users","type":"User","ref_name":"groups","inverse":true}],"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"default":true,"default_value":"Unknown","default_kind":24,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":true,"MixinIndex":1},{"Index":0,"MixedIn":false,"MixinIndex":0}]},{"name":"Tenant","config":{"Table":""},"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"validators":1,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":false,"MixinIndex":0}]},{"name":"User","config":{"Table":""},"edges":[{"name":"tenant","type":"Tenant","unique":true,"required":true},{"name":"groups","type":"Group"}],"fields":[{"name":"name","type":{"Type":7,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"default":true,"default_value":"Unknown","default_kind":24,"position":{"Index":0,"MixedIn":false,"MixinIndex":0}},{"name":"foods","type":{"Type":3,"Ident":"[]string","PkgPath":"","PkgName":"","Nillable":true,"RType":{"Name":"","Ident":"[]string","Kind":23,"PkgPath":"","Methods":{}}},"optional":true,"position":{"Index":1,"MixedIn":false,"MixinIndex":0}}],"policy":[{"Index":0,"MixedIn":true,"MixinIndex":0},{"Index":0,"MixedIn":true,"MixinIndex":1}]}],"Features":["privacy","entql","schema/snapshot"]}`
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
// Package internal holds a loadable version of the latest schema.
|
||||
package internal
|
||||
|
||||
const Schema = `{"Schema":"entgo.io/ent/examples/version/ent/schema","Package":"entgo.io/ent/examples/version/ent","Schemas":[{"name":"User","config":{"Table":""},"fields":[{"name":"version","type":{"Type":13,"Ident":"","PkgPath":"","Nillable":false,"RType":null},"default":true,"default_kind":19,"position":{"Index":0,"MixedIn":true,"MixinIndex":0},"comment":"Unix time of when the latest update occurred"},{"name":"status","type":{"Type":6,"Ident":"user.Status","PkgPath":"","Nillable":false,"RType":null},"enums":[{"N":"online","V":"online"},{"N":"offline","V":"offline"}],"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}]}],"Features":["schema/snapshot"]}`
|
||||
const Schema = `{"Schema":"entgo.io/ent/examples/version/ent/schema","Package":"entgo.io/ent/examples/version/ent","Schemas":[{"name":"User","config":{"Table":""},"fields":[{"name":"version","type":{"Type":13,"Ident":"","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"default":true,"default_kind":19,"position":{"Index":0,"MixedIn":true,"MixinIndex":0},"comment":"Unix time of when the latest update occurred"},{"name":"status","type":{"Type":6,"Ident":"user.Status","PkgPath":"","PkgName":"","Nillable":false,"RType":null},"enums":[{"N":"online","V":"online"},{"N":"offline","V":"offline"}],"position":{"Index":0,"MixedIn":false,"MixinIndex":0}}]}],"Features":["schema/snapshot"]}`
|
||||
|
||||
@@ -85,8 +85,9 @@ func (t Type) ConstName() string {
|
||||
type TypeInfo struct {
|
||||
Type Type
|
||||
Ident string
|
||||
PkgPath string
|
||||
Nillable bool // slices or pointers.
|
||||
PkgPath string // import path.
|
||||
PkgName string // local package name.
|
||||
Nillable bool // slices or pointers.
|
||||
RType *RType
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user