diff --git a/README.md b/README.md index 26a76d2fb..bfc90fd30 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ Simple, yet powerful ORM for modeling and querying data. ## Installation ```console -go get github.com/facebookincubator/ent/entc/cmd/entc +go get github.com/facebookincubator/ent/cmd/entc ``` ## Docs -The documentation for developing and using ent is avaliable at: https://entgo.io +The documentation for developing and using ent is available at: https://entgo.io ## Join the ent Community See the [CONTRIBUTING](CONTRIBUTING.md) file for how to help out. diff --git a/entc/cmd/entc/entc.go b/cmd/entc/entc.go similarity index 72% rename from entc/cmd/entc/entc.go rename to cmd/entc/entc.go index eaa20e2a5..0d65572c9 100644 --- a/entc/cmd/entc/entc.go +++ b/cmd/entc/entc.go @@ -15,8 +15,8 @@ import ( "text/template" "unicode" + "github.com/facebookincubator/ent/entc" "github.com/facebookincubator/ent/entc/gen" - "github.com/facebookincubator/ent/entc/load" "github.com/facebookincubator/ent/schema/field" "github.com/spf13/cobra" @@ -70,7 +70,7 @@ func main() { ), Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, path []string) { - graph, err := loadGraph(path[0], gen.Config{}) + graph, err := entc.LoadGraph(path[0], &gen.Config{}) failOnErr(err) graph.Describe(os.Stdout) }, @@ -90,23 +90,13 @@ func main() { ), Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, path []string) { - if cfg.Target == "" { - abs, err := filepath.Abs(path[0]) - failOnErr(err) - cfg.Target = filepath.Dir(abs) - } - for _, s := range storage { - sr, err := gen.NewStorage(s) - failOnErr(err) - cfg.Storage = append(cfg.Storage, sr) - } - if len(template) > 0 { - cfg.Template = loadTemplate(template) + opts := []entc.Option{entc.Storage(storage...)} + for _, tmpl := range template { + opts = append(opts, entc.TemplateDir(tmpl)) } cfg.IDType = &field.TypeInfo{Type: field.Type(idtype)} - graph, err := loadGraph(path[0], cfg) + err := entc.Generate(path[0], &cfg, opts...) failOnErr(err) - failOnErr(graph.Gen()) }, } ) @@ -121,49 +111,6 @@ func main() { cmd.Execute() } -// loadGraph loads the given schema package from the given path -// and construct a *gen.Graph. The path can be either a package -// path (e.g github.com/a8m/x) or a filepath. -// -// The second argument is an optional config for the graph creation. -func loadGraph(path string, cfg gen.Config) (*gen.Graph, error) { - spec, err := (&load.Config{Path: path}).Load() - if err != nil { - return nil, err - } - cfg.Schema = spec.PkgPath - cfg.Package = filepath.Dir(spec.PkgPath) - return gen.NewGraph(cfg, spec.Schemas...) -} - -// loadTemplate loads templates from files or directory. -func loadTemplate(paths []string) *template.Template { - t := template.New("external"). - Funcs(gen.Funcs) - for _, path := range paths { - info, err := os.Stat(path) - failOnErr(err) - if !info.IsDir() { - buf, err := ioutil.ReadFile(path) - failOnErr(err) - t, err = t.Parse(string(buf)) - failOnErr(err) - continue - } - infos, err := ioutil.ReadDir(path) - failOnErr(err) - paths := make([]string, len(infos)) - for i := range infos { - paths[i] = filepath.Join(path, infos[0].Name()) - } - for _, tt := range loadTemplate(paths).Templates() { - t, err = t.AddParseTree(tt.Name(), tt.Tree) - failOnErr(err) - } - } - return t -} - // schema template for the "init" command. var tmpl = template.Must(template.New("schema"). Parse(`package schema diff --git a/doc/md/code-gen.md b/doc/md/code-gen.md index 3c7ead3ef..29bc38a69 100755 --- a/doc/md/code-gen.md +++ b/doc/md/code-gen.md @@ -9,7 +9,7 @@ title: Introduction `entc` run the following command: ```bash -go get github.com/facebookincubator/ent/entc/cmd/entc +go get github.com/facebookincubator/ent/cmd/entc ``` ## Initialize A New Schema @@ -33,12 +33,6 @@ the assets for working with your entities. Run the following command: entc generate ./ent/schema ``` -You should note that `goimports` is required for the codegen, and it can be installed using: - -```bash -go get -u golang.org/x/tools/cmd/goimports -``` - The `generate` command generates the following assets for the schemas: - `Client` and `Tx` objects used for interacting with the graph. @@ -47,6 +41,24 @@ The `generate` command generates the following assets for the schemas: - Package containing constants and predicates used for interacting with the builders. - A `migrate` package for SQL dialects. See [Migration](migrate.md) for more info. +## Version Compatibility Between `entc` And `ent` + +When working with `entc` in a project, you want to make sure that the version being +used by `entc` is **identical** to the `ent` version used by your project. + +One of the options for achieving this is asking `go generate` to use the version +mentioned in the `go.mod` file when running `entc`. + +Add a `generate.go` file to your project under `/ent`: + +```go +package ent + +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate ./schema +``` + +And run `go generate ./ent` from your project root directory in order to run `entc` for your project. + ## Code Generation Options For more info about codegen options, run `entc generate -h`: @@ -83,6 +95,35 @@ a file with the same name as the template. Example of a custom template provides a `Node` API for GraphQL - [Github](https://github.com/facebookincubator/ent/blob/master/entc/integration/template/ent/template/node.tmpl). +## Use `entc` As A Package + +Another option for running `entc` is to use it as a package as follows: + +```go +package main + +import ( + "log" + + "github.com/facebookincubator/ent/entc" + "github.com/facebookincubator/ent/entc/gen" + "github.com/facebookincubator/ent/schema/field" +) + +func main() { + err := entc.Generate("./schema", &gen.Config{ + Header: "// Your Custom Header", + IDType: &field.TypeInfo{Type: field.TypeInt}, + }) + if err != nil { + log.Fatal("running ent codegen:", err) + } +} +``` + +The full example exists in [GitHub](https://github.com/facebookincubator/ent/tree/master/examples/entcpkg). + + ## Schema Description In order to get a description of your graph schema, run: diff --git a/doc/md/getting-started.md b/doc/md/getting-started.md index 99ef33576..b8d3eb50f 100755 --- a/doc/md/getting-started.md +++ b/doc/md/getting-started.md @@ -17,7 +17,7 @@ sidebar_label: Quick Introduction ## Installation ```console -go get github.com/facebookincubator/ent/entc/cmd/entc +go get github.com/facebookincubator/ent/cmd/entc ``` After installing `entc` (the code generator for `ent`), you should have it in your `PATH`. diff --git a/entc/entc.go b/entc/entc.go new file mode 100644 index 000000000..aa01a4de9 --- /dev/null +++ b/entc/entc.go @@ -0,0 +1,135 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Package entc provides an interface for interacting with +// entc (ent codegen) as a package rather than an executable. + +package entc + +import ( + "os" + "path" + "path/filepath" + "text/template" + + "github.com/facebookincubator/ent/entc/gen" + "github.com/facebookincubator/ent/entc/load" +) + +// LoadGraph loads the schema package from the given schema path, +// and construct a *gen.Graph. +func LoadGraph(schemaPath string, cfg *gen.Config) (*gen.Graph, error) { + spec, err := (&load.Config{Path: schemaPath}).Load() + if err != nil { + return nil, err + } + cfg.Schema = spec.PkgPath + if cfg.Package == "" { + // default package-path for codegen is one package + // above the schema package (`/ent/schema`). + cfg.Package = path.Dir(spec.PkgPath) + } + return gen.NewGraph(cfg, spec.Schemas...) +} + +// Generate runs the codegen on the schema path. The default target +// directory for the assets, is one directory above the schema path. +// Hence, if the schema package resides in "/ent/schema", +// the base directory for codegen will be "/ent". +// +// If no storage driver provided by option, SQL driver will be used. +// +// entc.Generate("./ent/path", &gen.Config{ +// Header: "// Custom header", +// IDType: &field.TypeInfo{Type: field.TypeInt}, +// }) +// +func Generate(schemaPath string, cfg *gen.Config, options ...Option) error { + if cfg.Target == "" { + abs, err := filepath.Abs(schemaPath) + if err != nil { + return err + } + // default target-path for codegen is one dir above + // the schema. + cfg.Target = filepath.Dir(abs) + } + for _, opt := range options { + if err := opt(cfg); err != nil { + return err + } + } + if len(cfg.Storage) == 0 { + driver, err := gen.NewStorage("sql") + if err != nil { + return err + } + cfg.Storage = append(cfg.Storage, driver) + } + graph, err := LoadGraph(schemaPath, cfg) + if err != nil { + return err + } + return graph.Gen() +} + +// Option allows for managing codegen configuration using functional options. +type Option func(*gen.Config) error + +// Storage sets the list of storage-driver types to support by the codegen. +func Storage(types ...string) Option { + return func(cfg *gen.Config) error { + for _, t := range types { + storage, err := gen.NewStorage(t) + if err != nil { + return err + } + cfg.Storage = append(cfg.Storage, storage) + } + return nil + } +} + +// TemplateFiles parses the named files and associates the resulting templates +// with codegen templates. +func TemplateFiles(filenames ...string) Option { + return templateOption(func(cfg *gen.Config) (err error) { + cfg.Template, err = cfg.Template.ParseFiles(filenames...) + return + }) +} + +// TemplateGlob parses the template definitions from the files identified +// by the pattern and associates the resulting templates with codegen templates. +func TemplateGlob(pattern string) Option { + return templateOption(func(cfg *gen.Config) (err error) { + cfg.Template, err = cfg.Template.ParseGlob(pattern) + return + }) +} + +// TemplateDir parses the template definitions from the files in the directory +// and associates the resulting templates with codegen templates. +func TemplateDir(path string) Option { + return templateOption(func(cfg *gen.Config) (err error) { + return filepath.Walk(path, func(path string, info os.FileInfo, err error) error { + if info.IsDir() { + return nil + } + cfg.Template, err = cfg.Template.ParseFiles(path) + return err + }) + }) +} + +// templateOption ensures the template instantiate +// once for config and execute the given Option. +func templateOption(next Option) Option { + return func(cfg *gen.Config) (err error) { + if cfg.Template == nil { + cfg.Template = template.New("external").Funcs(gen.Funcs) + } + return next(cfg) + } +} diff --git a/entc/gen/graph.go b/entc/gen/graph.go index 85c96f006..e7f203da6 100644 --- a/entc/gen/graph.go +++ b/entc/gen/graph.go @@ -48,7 +48,7 @@ type ( // Graph holds the nodes/entities of the loaded graph schema. Note that, it doesn't // hold the edges of the graph. Instead, each Type holds the edges for other Types. Graph struct { - Config + *Config // Nodes are list of Go types that mapped to the types in the loaded schema. Nodes []*Type // Schemas holds the raw interfaces for the loaded schemas. @@ -58,7 +58,7 @@ type ( // NewGraph creates a new Graph for the code generation from the given schema definitions. // It fails if one of the schemas is invalid. -func NewGraph(c Config, schemas ...*load.Schema) (g *Graph, err error) { +func NewGraph(c *Config, schemas ...*load.Schema) (g *Graph, err error) { defer catch(&err) g = &Graph{c, make([]*Type, 0, len(schemas)), schemas} for _, schema := range schemas { diff --git a/entc/gen/graph_test.go b/entc/gen/graph_test.go index 86df0cf2b..82011fd03 100644 --- a/entc/gen/graph_test.go +++ b/entc/gen/graph_test.go @@ -63,10 +63,10 @@ var ( func TestNewGraph(t *testing.T) { require := require.New(t) - _, err := NewGraph(Config{Package: "entc/gen", Storage: drivers}, T1) + _, err := NewGraph(&Config{Package: "entc/gen", Storage: drivers}, T1) require.Error(err, "should fail due to missing types") - graph, err := NewGraph(Config{Package: "entc/gen", Storage: drivers}, T1, T2) + graph, err := NewGraph(&Config{Package: "entc/gen", Storage: drivers}, T1, T2) require.NoError(err) require.NotNil(graph) require.Len(graph.Nodes, 2) @@ -121,7 +121,7 @@ func TestNewGraph(t *testing.T) { } func TestNewGraphRequiredLoop(t *testing.T) { - _, err := NewGraph(Config{Package: "entc/gen", Storage: drivers}, &load.Schema{ + _, err := NewGraph(&Config{Package: "entc/gen", Storage: drivers}, &load.Schema{ Name: "T1", Edges: []*load.Edge{ {Name: "parent", Type: "T1", Unique: true, Required: true}, @@ -130,7 +130,7 @@ func TestNewGraphRequiredLoop(t *testing.T) { }) require.Error(t, err, "require loop") - _, err = NewGraph(Config{Package: "entc/gen", Storage: drivers}, + _, err = NewGraph(&Config{Package: "entc/gen", Storage: drivers}, &load.Schema{ Name: "User", Edges: []*load.Edge{ @@ -147,7 +147,7 @@ func TestNewGraphRequiredLoop(t *testing.T) { } func TestNewGraphBadInverse(t *testing.T) { - _, err := NewGraph(Config{Package: "entc/gen", Storage: drivers}, + _, err := NewGraph(&Config{Package: "entc/gen", Storage: drivers}, &load.Schema{ Name: "User", Edges: []*load.Edge{ @@ -172,10 +172,10 @@ func TestNewGraphBadInverse(t *testing.T) { func TestRelation(t *testing.T) { require := require.New(t) - _, err := NewGraph(Config{Package: "entc/gen", Storage: drivers}, T1) + _, err := NewGraph(&Config{Package: "entc/gen", Storage: drivers}, T1) require.Error(err, "should fail due to missing types") - graph, err := NewGraph(Config{Package: "entc/gen"}, T1, T2) + graph, err := NewGraph(&Config{Package: "entc/gen"}, T1, T2) require.NoError(err) require.NotNil(graph) require.Len(graph.Nodes, 2) @@ -209,7 +209,7 @@ func TestGraph_Gen(t *testing.T) { require.NoError(os.MkdirAll(target, os.ModePerm), "creating tmpdir") defer os.Remove(target) external := template.Must(template.New("external").Parse("package external")) - graph, err := NewGraph(Config{ + graph, err := NewGraph(&Config{ Package: "entc/gen", Target: target, Storage: drivers, diff --git a/entc/gen/internal/bindata.go b/entc/gen/internal/bindata.go index 0d28ef777..c9b22e572 100644 --- a/entc/gen/internal/bindata.go +++ b/entc/gen/internal/bindata.go @@ -134,7 +134,7 @@ func templateBaseTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/base.tmpl", size: 5214, mode: os.FileMode(420), modTime: time.Unix(1570437111, 0)} + info := bindataFileInfo{name: "template/base.tmpl", size: 5214, mode: os.FileMode(420), modTime: time.Unix(1570451137, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -154,7 +154,7 @@ func templateBuilderCreateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/builder/create.tmpl", size: 3054, mode: os.FileMode(420), modTime: time.Unix(1570048192, 0)} + info := bindataFileInfo{name: "template/builder/create.tmpl", size: 3054, mode: os.FileMode(420), modTime: time.Unix(1570030748, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -174,7 +174,7 @@ func templateBuilderDeleteTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/builder/delete.tmpl", size: 2446, mode: os.FileMode(420), modTime: time.Unix(1568649864, 0)} + info := bindataFileInfo{name: "template/builder/delete.tmpl", size: 2446, mode: os.FileMode(420), modTime: time.Unix(1568645716, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -194,7 +194,7 @@ func templateBuilderQueryTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/builder/query.tmpl", size: 16113, mode: os.FileMode(420), modTime: time.Unix(1568649864, 0)} + info := bindataFileInfo{name: "template/builder/query.tmpl", size: 16113, mode: os.FileMode(420), modTime: time.Unix(1568645715, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -214,7 +214,7 @@ func templateBuilderSetterTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/builder/setter.tmpl", size: 4397, mode: os.FileMode(420), modTime: time.Unix(1568979858, 0)} + info := bindataFileInfo{name: "template/builder/setter.tmpl", size: 4397, mode: os.FileMode(420), modTime: time.Unix(1568906061, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -234,7 +234,7 @@ func templateBuilderUpdateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/builder/update.tmpl", size: 8088, mode: os.FileMode(420), modTime: time.Unix(1570048192, 0)} + info := bindataFileInfo{name: "template/builder/update.tmpl", size: 8088, mode: os.FileMode(420), modTime: time.Unix(1570030781, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -254,7 +254,7 @@ func templateClientTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/client.tmpl", size: 6205, mode: os.FileMode(420), modTime: time.Unix(1570008618, 0)} + info := bindataFileInfo{name: "template/client.tmpl", size: 6205, mode: os.FileMode(420), modTime: time.Unix(1570008718, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -274,7 +274,7 @@ func templateConfigTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/config.tmpl", size: 1254, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/config.tmpl", size: 1254, mode: os.FileMode(420), modTime: time.Unix(1567330565, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -294,7 +294,7 @@ func templateContextTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/context.tmpl", size: 719, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/context.tmpl", size: 719, mode: os.FileMode(420), modTime: time.Unix(1567330561, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -314,7 +314,7 @@ func templateDialectGremlinByTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/by.tmpl", size: 1875, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/by.tmpl", size: 1875, mode: os.FileMode(420), modTime: time.Unix(1567330626, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -334,7 +334,7 @@ func templateDialectGremlinCreateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/create.tmpl", size: 2763, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/create.tmpl", size: 2763, mode: os.FileMode(420), modTime: time.Unix(1567330629, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -354,7 +354,7 @@ func templateDialectGremlinDecodeTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/decode.tmpl", size: 2132, mode: os.FileMode(420), modTime: time.Unix(1570299906, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/decode.tmpl", size: 2132, mode: os.FileMode(420), modTime: time.Unix(1570281258, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -374,7 +374,7 @@ func templateDialectGremlinDeleteTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/delete.tmpl", size: 825, mode: os.FileMode(420), modTime: time.Unix(1568649864, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/delete.tmpl", size: 825, mode: os.FileMode(420), modTime: time.Unix(1568645716, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -394,7 +394,7 @@ func templateDialectGremlinErrorsTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/errors.tmpl", size: 1804, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/errors.tmpl", size: 1804, mode: os.FileMode(420), modTime: time.Unix(1567330638, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -414,7 +414,7 @@ func templateDialectGremlinGroupTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/group.tmpl", size: 1347, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/group.tmpl", size: 1347, mode: os.FileMode(420), modTime: time.Unix(1567526275, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -434,7 +434,7 @@ func templateDialectGremlinMetaTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/meta.tmpl", size: 704, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/meta.tmpl", size: 704, mode: os.FileMode(420), modTime: time.Unix(1567330643, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -454,7 +454,7 @@ func templateDialectGremlinOpenTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/open.tmpl", size: 542, mode: os.FileMode(420), modTime: time.Unix(1570437111, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/open.tmpl", size: 542, mode: os.FileMode(420), modTime: time.Unix(1570451137, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -474,7 +474,7 @@ func templateDialectGremlinPredicateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/predicate.tmpl", size: 3313, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/predicate.tmpl", size: 3313, mode: os.FileMode(420), modTime: time.Unix(1567330647, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -494,7 +494,7 @@ func templateDialectGremlinQueryTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/query.tmpl", size: 3929, mode: os.FileMode(420), modTime: time.Unix(1570099221, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/query.tmpl", size: 3929, mode: os.FileMode(420), modTime: time.Unix(1570094435, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -514,7 +514,7 @@ func templateDialectGremlinSelectTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/select.tmpl", size: 1078, mode: os.FileMode(420), modTime: time.Unix(1567611994, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/select.tmpl", size: 1078, mode: os.FileMode(420), modTime: time.Unix(1567600027, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -534,7 +534,7 @@ func templateDialectGremlinUpdateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/gremlin/update.tmpl", size: 6095, mode: os.FileMode(420), modTime: time.Unix(1568557285, 0)} + info := bindataFileInfo{name: "template/dialect/gremlin/update.tmpl", size: 6095, mode: os.FileMode(420), modTime: time.Unix(1568542264, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -554,7 +554,7 @@ func templateDialectSqlByTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/by.tmpl", size: 949, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/sql/by.tmpl", size: 949, mode: os.FileMode(420), modTime: time.Unix(1567330589, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -574,7 +574,7 @@ func templateDialectSqlCreateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/create.tmpl", size: 6421, mode: os.FileMode(420), modTime: time.Unix(1569269741, 0)} + info := bindataFileInfo{name: "template/dialect/sql/create.tmpl", size: 6421, mode: os.FileMode(420), modTime: time.Unix(1569251090, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -594,7 +594,7 @@ func templateDialectSqlDecodeTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/decode.tmpl", size: 2142, mode: os.FileMode(420), modTime: time.Unix(1570187197, 0)} + info := bindataFileInfo{name: "template/dialect/sql/decode.tmpl", size: 2142, mode: os.FileMode(420), modTime: time.Unix(1570187959, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -614,7 +614,7 @@ func templateDialectSqlDeleteTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/delete.tmpl", size: 828, mode: os.FileMode(420), modTime: time.Unix(1568649864, 0)} + info := bindataFileInfo{name: "template/dialect/sql/delete.tmpl", size: 828, mode: os.FileMode(420), modTime: time.Unix(1568645716, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -634,7 +634,7 @@ func templateDialectSqlErrorsTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/errors.tmpl", size: 967, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/sql/errors.tmpl", size: 967, mode: os.FileMode(420), modTime: time.Unix(1567330602, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -654,7 +654,7 @@ func templateDialectSqlGroupTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/group.tmpl", size: 1031, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/sql/group.tmpl", size: 1031, mode: os.FileMode(420), modTime: time.Unix(1567330605, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -674,7 +674,7 @@ func templateDialectSqlMetaTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/meta.tmpl", size: 1782, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/sql/meta.tmpl", size: 1782, mode: os.FileMode(420), modTime: time.Unix(1567330610, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -694,7 +694,7 @@ func templateDialectSqlOpenTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/open.tmpl", size: 389, mode: os.FileMode(420), modTime: time.Unix(1570420017, 0)} + info := bindataFileInfo{name: "template/dialect/sql/open.tmpl", size: 389, mode: os.FileMode(420), modTime: time.Unix(1570008718, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -714,7 +714,7 @@ func templateDialectSqlPredicateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/predicate.tmpl", size: 4526, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/dialect/sql/predicate.tmpl", size: 4526, mode: os.FileMode(420), modTime: time.Unix(1567330614, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -734,7 +734,7 @@ func templateDialectSqlQueryTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/query.tmpl", size: 6382, mode: os.FileMode(420), modTime: time.Unix(1570099221, 0)} + info := bindataFileInfo{name: "template/dialect/sql/query.tmpl", size: 6382, mode: os.FileMode(420), modTime: time.Unix(1570094421, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -754,7 +754,7 @@ func templateDialectSqlSelectTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/select.tmpl", size: 809, mode: os.FileMode(420), modTime: time.Unix(1567611994, 0)} + info := bindataFileInfo{name: "template/dialect/sql/select.tmpl", size: 809, mode: os.FileMode(420), modTime: time.Unix(1567539807, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -774,7 +774,7 @@ func templateDialectSqlUpdateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/dialect/sql/update.tmpl", size: 12705, mode: os.FileMode(420), modTime: time.Unix(1570115310, 0)} + info := bindataFileInfo{name: "template/dialect/sql/update.tmpl", size: 12705, mode: os.FileMode(420), modTime: time.Unix(1570107181, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -794,7 +794,7 @@ func templateEntTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/ent.tmpl", size: 3926, mode: os.FileMode(420), modTime: time.Unix(1570187197, 0)} + info := bindataFileInfo{name: "template/ent.tmpl", size: 3926, mode: os.FileMode(420), modTime: time.Unix(1570170532, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -814,12 +814,12 @@ func templateExampleTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/example.tmpl", size: 2425, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/example.tmpl", size: 2425, mode: os.FileMode(420), modTime: time.Unix(1567330554, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _templateHeaderTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x5c\x8e\xd1\x6a\xc2\x30\x18\x85\xaf\x97\xa7\x38\x48\xaf\x64\x4b\x9d\x77\x1b\x78\x21\x55\x99\x30\x74\xa0\x2f\x10\x93\xbf\x4d\xb0\x24\x25\x89\x1b\x12\xf2\xee\xa3\x5d\x0b\xb2\xab\xc0\xf9\xbe\xfc\xe7\xa4\x54\xce\x59\xe5\xba\xbb\x37\x8d\x8e\x58\x2e\x5e\xdf\x5e\x3a\x4f\x81\x6c\xc4\x4e\x48\xba\x38\x77\xc5\xde\x4a\x8e\x75\xdb\x62\x90\x02\x7a\xee\xbf\x49\x71\x76\xd6\x26\x20\xb8\x9b\x97\x04\xe9\x14\xc1\x04\xb4\x46\x92\x0d\xa4\x70\xb3\x8a\x3c\xa2\x26\xac\x3b\x21\x35\x61\xc9\x17\x13\x45\xed\x6e\x56\x31\x63\x07\xfe\xb9\xaf\xb6\x87\xd3\x16\xb5\x69\x09\x63\xe6\x9d\x8b\x50\xc6\x93\x8c\xce\xdf\xe1\x6a\xc4\x87\xb2\xe8\x89\x38\x9b\x97\x39\x33\x96\x12\x14\xd5\xc6\x12\x66\x9a\x84\x22\x3f\x43\xce\xac\x2c\x91\x12\x7e\x4c\xd4\x28\xf8\xc7\x90\x23\xe7\x94\xc0\xff\x1e\x6a\x03\x21\xe7\xaa\x5f\xdd\x90\x25\x2f\x22\x29\x5c\xee\x20\x1b\xe5\x33\x36\x47\x1c\x8e\x67\x6c\x37\xfb\x33\xef\x6d\xab\x30\x76\x15\xdd\xb5\xc1\xfb\x0a\x17\x11\x08\x05\xaf\x9c\xad\x4d\xc3\xbf\x84\xbc\x8a\xa6\xbf\xd8\x3b\xa6\x86\x16\x61\x67\xa8\x55\x28\x30\x3b\x49\xd7\xd1\xb0\xea\x69\x3a\xb0\x42\xc1\x87\xf8\xdf\xcf\xb1\xa8\x1b\xc3\x49\x7f\x84\xbf\x01\x00\x00\xff\xff\x93\x25\x51\x7e\xb4\x01\x00\x00") +var _templateHeaderTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x5c\x8e\xc1\x8a\xea\x30\x14\x86\xd7\xb7\x4f\xf1\x23\x5d\xc9\xbd\xa9\xd7\xdd\x0c\xb8\x90\xaa\x8c\x30\xe8\x80\xbe\x40\x4c\xfe\xb6\xc1\x92\x94\x24\xce\x20\x25\xef\x3e\xb4\x53\x41\x66\x15\xf8\xbe\x73\xf2\x9d\xbe\x2f\xe6\x59\xe9\xba\xbb\x37\x75\x13\xb1\x5c\xfc\x7f\xf9\xd7\x79\x06\xda\x88\x9d\x54\xbc\x38\x77\xc5\xde\x2a\x81\x75\xdb\x62\x1c\x0a\x18\xbc\xff\xa4\x16\xd9\xb9\x31\x01\xc1\xdd\xbc\x22\x94\xd3\x84\x09\x68\x8d\xa2\x0d\xd4\xb8\x59\x4d\x8f\xd8\x10\xeb\x4e\xaa\x86\x58\x8a\xc5\xc3\xa2\x72\x37\xab\x33\x63\x47\xff\xbe\x2f\xb7\x87\xd3\x16\x95\x69\x89\x89\x79\xe7\x22\xb4\xf1\x54\xd1\xf9\x3b\x5c\x85\xf8\x14\x8b\x9e\x14\xd9\xbc\x48\x29\xcb\xfa\x1e\x9a\x95\xb1\xc4\xac\xa1\xd4\xf4\x33\xa4\x34\xd0\x2f\x13\x1b\xe4\xe2\x6d\x84\x48\xa9\xef\x21\x7e\x1e\xb6\x81\x48\xa9\x28\x50\x0e\x57\xd7\xb4\xf4\x32\x52\xe3\x72\x07\x6d\x54\x7f\xb1\x39\xe2\x70\x3c\x63\xbb\xd9\x9f\xc5\xb0\x60\x35\xa6\x56\xde\x5d\x6b\xbc\xae\x70\x91\x81\xc8\x45\xe9\x6c\x65\x6a\xf1\x21\xd5\x55\xd6\x9c\xca\xa6\x42\x23\xc3\xce\xb0\xd5\xc8\x31\x3b\x29\xd7\x71\xbc\xea\xcf\xe3\x83\x15\x72\x31\xe2\x5f\x9b\x53\xa8\x9b\xe0\x63\xfc\x59\x7e\x07\x00\x00\xff\xff\x26\x39\x8f\x5b\xb4\x01\x00\x00") func templateHeaderTmplBytes() ([]byte, error) { return bindataRead( @@ -834,7 +834,7 @@ func templateHeaderTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/header.tmpl", size: 436, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/header.tmpl", size: 436, mode: os.FileMode(420), modTime: time.Unix(1570451141, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -854,7 +854,7 @@ func templateImportTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/import.tmpl", size: 984, mode: os.FileMode(420), modTime: time.Unix(1568897694, 0)} + info := bindataFileInfo{name: "template/import.tmpl", size: 984, mode: os.FileMode(420), modTime: time.Unix(1568822311, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -874,7 +874,7 @@ func templateMetaTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/meta.tmpl", size: 4291, mode: os.FileMode(420), modTime: time.Unix(1570048192, 0)} + info := bindataFileInfo{name: "template/meta.tmpl", size: 4291, mode: os.FileMode(420), modTime: time.Unix(1570033406, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -894,7 +894,7 @@ func templateMigrateMigrateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/migrate/migrate.tmpl", size: 2450, mode: os.FileMode(420), modTime: time.Unix(1567955626, 0)} + info := bindataFileInfo{name: "template/migrate/migrate.tmpl", size: 2450, mode: os.FileMode(420), modTime: time.Unix(1567952288, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -914,7 +914,7 @@ func templateMigrateSchemaTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/migrate/schema.tmpl", size: 3755, mode: os.FileMode(420), modTime: time.Unix(1570048192, 0)} + info := bindataFileInfo{name: "template/migrate/schema.tmpl", size: 3755, mode: os.FileMode(420), modTime: time.Unix(1570019529, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -934,7 +934,7 @@ func templatePredicateTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/predicate.tmpl", size: 1213, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/predicate.tmpl", size: 1213, mode: os.FileMode(420), modTime: time.Unix(1567330539, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -954,7 +954,7 @@ func templateTxTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/tx.tmpl", size: 3382, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/tx.tmpl", size: 3382, mode: os.FileMode(420), modTime: time.Unix(1567330536, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -974,7 +974,7 @@ func templateWhereTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/where.tmpl", size: 5353, mode: os.FileMode(420), modTime: time.Unix(1570048192, 0)} + info := bindataFileInfo{name: "template/where.tmpl", size: 5353, mode: os.FileMode(420), modTime: time.Unix(1570012859, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/entc/gen/template.go b/entc/gen/template.go index 438c728ad..01126b43b 100644 --- a/entc/gen/template.go +++ b/entc/gen/template.go @@ -123,7 +123,7 @@ func init() { templates = template.Must(templates.Parse(string(internal.MustAsset(asset)))) } b := bytes.NewBuffer([]byte("package main\n")) - check(templates.ExecuteTemplate(b, "import", Type{}), "load imports") + check(templates.ExecuteTemplate(b, "import", Type{Config: &Config{}}), "load imports") f, err := parser.ParseFile(token.NewFileSet(), "", b, parser.ImportsOnly) check(err, "parse imports") for _, spec := range f.Imports { diff --git a/entc/gen/template/header.tmpl b/entc/gen/template/header.tmpl index d7fbad433..d136807bf 100644 --- a/entc/gen/template/header.tmpl +++ b/entc/gen/template/header.tmpl @@ -5,7 +5,7 @@ in the LICENSE file in the root directory of this source tree. */}} {{ define "header" }} -// {{ with $.Header }}{{ . }}{{ else }}Code generated by entc, DO NOT EDIT.{{ end }} +{{ with $.Header }}{{ . }}{{ else }}// Code generated by entc, DO NOT EDIT.{{ end }} {{ $pkg := base $.Config.Package }} {{ if hasField $ "Scope" }} diff --git a/entc/gen/type.go b/entc/gen/type.go index 6bbe81cda..47d1ce558 100644 --- a/entc/gen/type.go +++ b/entc/gen/type.go @@ -25,7 +25,7 @@ type ( // Type represents one node-type in the graph, its relations and // the information it holds. Type struct { - Config + *Config // schema definition. schema *load.Schema // Name holds the type/ent name. @@ -130,7 +130,7 @@ type ( ) // NewType creates a new type and its fields from the given schema. -func NewType(c Config, schema *load.Schema) (*Type, error) { +func NewType(c *Config, schema *load.Schema) (*Type, error) { typ := &Type{ Config: c, ID: &Field{ diff --git a/entc/gen/type_test.go b/entc/gen/type_test.go index 596574cf7..f8e6d1daa 100644 --- a/entc/gen/type_test.go +++ b/entc/gen/type_test.go @@ -17,7 +17,7 @@ import ( func TestType(t *testing.T) { require := require.New(t) - typ, err := NewType(Config{Package: "entc/gen"}, T1) + typ, err := NewType(&Config{Package: "entc/gen"}, T1) require.NoError(err) require.NotNil(typ) require.Equal("T1", typ.Name) @@ -25,7 +25,7 @@ func TestType(t *testing.T) { require.Equal("t1", typ.Package()) require.Equal("t", typ.Receiver()) - typ, err = NewType(Config{Package: "entc/gen"}, &load.Schema{ + typ, err = NewType(&Config{Package: "entc/gen"}, &load.Schema{ Fields: []*load.Field{ {Unique: true, Default: true, Info: &field.TypeInfo{Type: field.TypeInt}}, }, @@ -33,7 +33,7 @@ func TestType(t *testing.T) { require.Error(err, "unique field can not have default") require.Nil(typ) - typ, err = NewType(Config{Package: "entc/gen"}, &load.Schema{ + typ, err = NewType(&Config{Package: "entc/gen"}, &load.Schema{ Name: "T", Fields: []*load.Field{ {Name: "foo", Unique: true, Info: &field.TypeInfo{Type: field.TypeInt}}, @@ -43,7 +43,7 @@ func TestType(t *testing.T) { require.Error(err, "field foo redeclared") require.Nil(typ) - typ, err = NewType(Config{Package: "entc/gen"}, &load.Schema{ + typ, err = NewType(&Config{Package: "entc/gen"}, &load.Schema{ Name: "T", Fields: []*load.Field{ {Name: "enums", Info: &field.TypeInfo{Type: field.TypeEnum}, Enums: []string{"A", "A"}}, @@ -52,7 +52,7 @@ func TestType(t *testing.T) { require.Error(err, "duplicate enums") require.Nil(typ) - typ, err = NewType(Config{Package: "entc/gen"}, &load.Schema{ + typ, err = NewType(&Config{Package: "entc/gen"}, &load.Schema{ Name: "T", Fields: []*load.Field{ {Name: "enums", Info: &field.TypeInfo{Type: field.TypeEnum}, Enums: []string{""}}, @@ -112,7 +112,7 @@ func TestType_Receiver(t *testing.T) { {"[]byte", "b"}, } for _, tt := range tests { - typ := &Type{Name: tt.name, Config: Config{Package: "entc/gen"}} + typ := &Type{Name: tt.name, Config: &Config{Package: "entc/gen"}} require.Equal(t, tt.receiver, typ.Receiver()) } } @@ -152,7 +152,7 @@ func TestType_Package(t *testing.T) { func TestType_AddIndex(t *testing.T) { size := int64(1024) - typ, err := NewType(Config{}, &load.Schema{ + typ, err := NewType(&Config{}, &load.Schema{ Name: "User", Fields: []*load.Field{ {Name: "name", Info: &field.TypeInfo{Type: field.TypeString}}, diff --git a/entc/integration/generate.go b/entc/integration/generate.go index fe56ed829..c4ab587ad 100644 --- a/entc/integration/generate.go +++ b/entc/integration/generate.go @@ -4,10 +4,10 @@ package integration -//go:generate go run ../cmd/entc/entc.go generate --storage=sql,gremlin --idtype string --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./ent/schema -//go:generate go run ../cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./migrate/entv1/schema -//go:generate go run ../cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./migrate/entv2/schema -//go:generate go run ../cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./template/ent/schema --template=template/ent/template -//go:generate go run ../cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./json/ent/schema -//go:generate go run ../cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./config/ent/schema -//go:generate go run ../cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." --idtype uint64 ./idtype/ent/schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --storage=sql,gremlin --idtype string --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./ent/schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./migrate/entv1/schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./migrate/entv2/schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./template/ent/schema --template=template/ent/template +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./json/ent/schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./config/ent/schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." --idtype uint64 ./idtype/ent/schema diff --git a/entc/load/internal/bindata.go b/entc/load/internal/bindata.go index 86b6d2a3d..7964ac293 100644 --- a/entc/load/internal/bindata.go +++ b/entc/load/internal/bindata.go @@ -93,7 +93,7 @@ func templateMainTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/main.tmpl", size: 843, mode: os.FileMode(420), modTime: time.Unix(1567360769, 0)} + info := bindataFileInfo{name: "template/main.tmpl", size: 843, mode: os.FileMode(420), modTime: time.Unix(1567330508, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -113,7 +113,7 @@ func schemaGo() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "schema.go", size: 7249, mode: os.FileMode(420), modTime: time.Unix(1570299906, 0)} + info := bindataFileInfo{name: "schema.go", size: 7249, mode: os.FileMode(420), modTime: time.Unix(1570201210, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/examples/edgeindex/ent/generate.go b/examples/edgeindex/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/edgeindex/ent/generate.go +++ b/examples/edgeindex/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/entcpkg/README.md b/examples/entcpkg/README.md new file mode 100644 index 000000000..949480da4 --- /dev/null +++ b/examples/entcpkg/README.md @@ -0,0 +1,48 @@ +# entcpkg example + +An example of using `entc` (ent codegen) as package rather than an executable. + +In this example, we have a file named `entc.go` under the `./ent` directory, that holds the +configuration for the codegen: + +```go +// +build ignore + +package main + +import ( + "log" + + "github.com/facebookincubator/ent/entc" + "github.com/facebookincubator/ent/entc/gen" + "github.com/facebookincubator/ent/schema/field" +) + +func main() { + err := entc.Generate("./schema", &gen.Config{ + Header: ` + // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + // This source code is licensed under the Apache 2.0 license found + // in the LICENSE file in the root directory of this source tree. + + // Code generated (@generated) by entc, DO NOT EDIT. + `, + IDType: &field.TypeInfo{Type: field.TypeInt}, + }) + if err != nil { + log.Fatal("running ent codegen:", err) + } +} +``` + +As you can see, the file is tagged with `// +build ignore` in order to not include it +in the `ent` package. In order to run the codegen, run the file itself (using `go run`) +or run `go generate ./ent`. The `generate.go` file holds the `go run command`: + +```go +package ent + +//go:generate go run entc.go +``` + +The `generate.go` file is preferred if you have many `generate` pragmas in your project. \ No newline at end of file diff --git a/examples/entcpkg/ent/client.go b/examples/entcpkg/ent/client.go new file mode 100644 index 000000000..aace2c7f6 --- /dev/null +++ b/examples/entcpkg/ent/client.go @@ -0,0 +1,161 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "log" + + "github.com/facebookincubator/ent/examples/entcpkg/ent/migrate" + + "github.com/facebookincubator/ent/examples/entcpkg/ent/user" + + "github.com/facebookincubator/ent/dialect" + "github.com/facebookincubator/ent/dialect/sql" +) + +// Client is the client that holds all ent builders. +type Client struct { + config + // Schema is the client for creating, migrating and dropping schema. + Schema *migrate.Schema + // User is the client for interacting with the User builders. + User *UserClient +} + +// NewClient creates a new client configured with the given options. +func NewClient(opts ...Option) *Client { + c := config{log: log.Println} + c.options(opts...) + return &Client{ + config: c, + Schema: migrate.NewSchema(c.driver), + User: NewUserClient(c), + } +} + +// Open opens a connection to the database specified by the driver name and a +// driver-specific data source name, and returns a new client attached to it. +// Optional parameters can be added for configuring the client. +func Open(driverName, dataSourceName string, options ...Option) (*Client, error) { + switch driverName { + case dialect.MySQL, dialect.SQLite: + drv, err := sql.Open(driverName, dataSourceName) + if err != nil { + return nil, err + } + return NewClient(append(options, Driver(drv))...), nil + + default: + return nil, fmt.Errorf("unsupported driver: %q", driverName) + } +} + +// Tx returns a new transactional client. +func (c *Client) Tx(ctx context.Context) (*Tx, error) { + if _, ok := c.driver.(*txDriver); ok { + return nil, fmt.Errorf("ent: cannot start a transaction within a transaction") + } + tx, err := newTx(ctx, c.driver) + if err != nil { + return nil, fmt.Errorf("ent: starting a transaction: %v", err) + } + cfg := config{driver: tx, log: c.log, debug: c.debug} + return &Tx{ + config: cfg, + User: NewUserClient(cfg), + }, nil +} + +// Debug returns a new debug-client. It's used to get verbose logging on specific operations. +// +// client.Debug(). +// User. +// Query(). +// Count(ctx) +// +func (c *Client) Debug() *Client { + if c.debug { + return c + } + cfg := config{driver: dialect.Debug(c.driver, c.log), log: c.log, debug: true} + return &Client{ + config: cfg, + Schema: migrate.NewSchema(cfg.driver), + User: NewUserClient(cfg), + } +} + +// Close closes the database connection and prevents new queries from starting. +func (c *Client) Close() error { + return c.driver.Close() +} + +// UserClient is a client for the User schema. +type UserClient struct { + config +} + +// NewUserClient returns a client for the User from the given config. +func NewUserClient(c config) *UserClient { + return &UserClient{config: c} +} + +// Create returns a create builder for User. +func (c *UserClient) Create() *UserCreate { + return &UserCreate{config: c.config} +} + +// Update returns an update builder for User. +func (c *UserClient) Update() *UserUpdate { + return &UserUpdate{config: c.config} +} + +// UpdateOne returns an update builder for the given entity. +func (c *UserClient) UpdateOne(u *User) *UserUpdateOne { + return c.UpdateOneID(u.ID) +} + +// UpdateOneID returns an update builder for the given id. +func (c *UserClient) UpdateOneID(id int) *UserUpdateOne { + return &UserUpdateOne{config: c.config, id: id} +} + +// Delete returns a delete builder for User. +func (c *UserClient) Delete() *UserDelete { + return &UserDelete{config: c.config} +} + +// DeleteOne returns a delete builder for the given entity. +func (c *UserClient) DeleteOne(u *User) *UserDeleteOne { + return c.DeleteOneID(u.ID) +} + +// DeleteOneID returns a delete builder for the given id. +func (c *UserClient) DeleteOneID(id int) *UserDeleteOne { + return &UserDeleteOne{c.Delete().Where(user.ID(id))} +} + +// Create returns a query builder for User. +func (c *UserClient) Query() *UserQuery { + return &UserQuery{config: c.config} +} + +// Get returns a User entity by its id. +func (c *UserClient) Get(ctx context.Context, id int) (*User, error) { + return c.Query().Where(user.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *UserClient) GetX(ctx context.Context, id int) *User { + u, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return u +} diff --git a/examples/entcpkg/ent/config.go b/examples/entcpkg/ent/config.go new file mode 100644 index 000000000..1a5d585d1 --- /dev/null +++ b/examples/entcpkg/ent/config.go @@ -0,0 +1,55 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "github.com/facebookincubator/ent/dialect" +) + +// Option function to configure the client. +type Option func(*config) + +// Config is the configuration for the client and its builder. +type config struct { + // driver used for executing database requests. + driver dialect.Driver + // debug enable a debug logging. + debug bool + // log used for logging on debug mode. + log func(...interface{}) +} + +// Options applies the options on the config object. +func (c *config) options(opts ...Option) { + for _, opt := range opts { + opt(c) + } + if c.debug { + c.driver = dialect.Debug(c.driver, c.log) + } +} + +// Debug enables debug logging on the ent.Driver. +func Debug() Option { + return func(c *config) { + c.debug = true + } +} + +// Log sets the logging function for debug mode. +func Log(fn func(...interface{})) Option { + return func(c *config) { + c.log = fn + } +} + +// Driver configures the client driver. +func Driver(driver dialect.Driver) Option { + return func(c *config) { + c.driver = driver + } +} diff --git a/examples/entcpkg/ent/context.go b/examples/entcpkg/ent/context.go new file mode 100644 index 000000000..c6a16805e --- /dev/null +++ b/examples/entcpkg/ent/context.go @@ -0,0 +1,24 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "context" +) + +type contextKey struct{} + +// FromContext returns the Client stored in a context, or nil if there isn't one. +func FromContext(ctx context.Context) *Client { + c, _ := ctx.Value(contextKey{}).(*Client) + return c +} + +// NewContext returns a new context with the given Client attached. +func NewContext(parent context.Context, c *Client) context.Context { + return context.WithValue(parent, contextKey{}, c) +} diff --git a/examples/entcpkg/ent/ent.go b/examples/entcpkg/ent/ent.go new file mode 100644 index 000000000..87e6c5af5 --- /dev/null +++ b/examples/entcpkg/ent/ent.go @@ -0,0 +1,196 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + + "github.com/facebookincubator/ent/dialect" + "github.com/facebookincubator/ent/dialect/sql" +) + +// Order applies an ordering on either graph traversal or sql selector. +type Order func(*sql.Selector) + +// Asc applies the given fields in ASC order. +func Asc(fields ...string) Order { + return Order( + func(s *sql.Selector) { + for _, f := range fields { + s.OrderBy(sql.Asc(f)) + } + }, + ) +} + +// Desc applies the given fields in DESC order. +func Desc(fields ...string) Order { + return Order( + func(s *sql.Selector) { + for _, f := range fields { + s.OrderBy(sql.Desc(f)) + } + }, + ) +} + +// Aggregate applies an aggregation step on the group-by traversal/selector. +type Aggregate struct { + // SQL the column wrapped with the aggregation function. + SQL func(*sql.Selector) string +} + +// As is a pseudo aggregation function for renaming another other functions with custom names. For example: +// +// GroupBy(field1, field2). +// Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")). +// Scan(ctx, &v) +// +func As(fn Aggregate, end string) Aggregate { + return Aggregate{ + SQL: func(s *sql.Selector) string { + return sql.As(fn.SQL(s), end) + }, + } +} + +// Count applies the "count" aggregation function on each group. +func Count() Aggregate { + return Aggregate{ + SQL: func(s *sql.Selector) string { + return sql.Count("*") + }, + } +} + +// Max applies the "max" aggregation function on the given field of each group. +func Max(field string) Aggregate { + return Aggregate{ + SQL: func(s *sql.Selector) string { + return sql.Max(s.C(field)) + }, + } +} + +// Mean applies the "mean" aggregation function on the given field of each group. +func Mean(field string) Aggregate { + return Aggregate{ + SQL: func(s *sql.Selector) string { + return sql.Avg(s.C(field)) + }, + } +} + +// Min applies the "min" aggregation function on the given field of each group. +func Min(field string) Aggregate { + return Aggregate{ + SQL: func(s *sql.Selector) string { + return sql.Min(s.C(field)) + }, + } +} + +// Sum applies the "sum" aggregation function on the given field of each group. +func Sum(field string) Aggregate { + return Aggregate{ + SQL: func(s *sql.Selector) string { + return sql.Sum(s.C(field)) + }, + } +} + +// ErrNotFound returns when trying to fetch a specific entity and it was not found in the database. +type ErrNotFound struct { + label string +} + +// Error implements the error interface. +func (e *ErrNotFound) Error() string { + return fmt.Sprintf("ent: %s not found", e.label) +} + +// IsNotFound returns a boolean indicating whether the error is a not found error. +func IsNotFound(err error) bool { + _, ok := err.(*ErrNotFound) + return ok +} + +// MaskNotFound masks nor found error. +func MaskNotFound(err error) error { + if IsNotFound(err) { + return nil + } + return err +} + +// ErrNotSingular returns when trying to fetch a singular entity and more then one was found in the database. +type ErrNotSingular struct { + label string +} + +// Error implements the error interface. +func (e *ErrNotSingular) Error() string { + return fmt.Sprintf("ent: %s not singular", e.label) +} + +// IsNotSingular returns a boolean indicating whether the error is a not singular error. +func IsNotSingular(err error) bool { + _, ok := err.(*ErrNotSingular) + return ok +} + +// ErrConstraintFailed returns when trying to create/update one or more entities and +// one or more of their constraints failed. For example, violation of edge or field uniqueness. +type ErrConstraintFailed struct { + msg string + wrap error +} + +// Error implements the error interface. +func (e ErrConstraintFailed) Error() string { + return fmt.Sprintf("ent: unique constraint failed: %s", e.msg) +} + +// Unwrap implements the errors.Wrapper interface. +func (e *ErrConstraintFailed) Unwrap() error { + return e.wrap +} + +// IsConstraintFailure returns a boolean indicating whether the error is a constraint failure. +func IsConstraintFailure(err error) bool { + _, ok := err.(*ErrConstraintFailed) + return ok +} + +func isSQLConstraintError(err error) (*ErrConstraintFailed, bool) { + // Error number 1062 is ER_DUP_ENTRY in mysql, and "UNIQUE constraint failed" is SQLite prefix. + if msg := err.Error(); strings.HasPrefix(msg, "Error 1062") || strings.HasPrefix(msg, "UNIQUE constraint failed") { + return &ErrConstraintFailed{msg, err}, true + } + return nil, false +} + +// rollback calls to tx.Rollback and wraps the given error with the rollback error if occurred. +func rollback(tx dialect.Tx, err error) error { + if rerr := tx.Rollback(); rerr != nil { + err = fmt.Errorf("%s: %v", err.Error(), rerr) + } + if err, ok := isSQLConstraintError(err); ok { + return err + } + return err +} + +// keys returns the keys/ids from the edge map. +func keys(m map[int]struct{}) []int { + s := make([]int, 0, len(m)) + for id := range m { + s = append(s, id) + } + return s +} diff --git a/examples/entcpkg/ent/entc.go b/examples/entcpkg/ent/entc.go new file mode 100644 index 000000000..5e792dac4 --- /dev/null +++ b/examples/entcpkg/ent/entc.go @@ -0,0 +1,31 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// +build ignore + +package main + +import ( + "log" + + "github.com/facebookincubator/ent/entc" + "github.com/facebookincubator/ent/entc/gen" + "github.com/facebookincubator/ent/schema/field" +) + +func main() { + err := entc.Generate("./schema", &gen.Config{ + Header: ` + // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + // This source code is licensed under the Apache 2.0 license found + // in the LICENSE file in the root directory of this source tree. + + // Code generated (@generated) by entc, DO NOT EDIT. + `, + IDType: &field.TypeInfo{Type: field.TypeInt}, + }) + if err != nil { + log.Fatal("running ent codegen:", err) + } +} diff --git a/examples/entcpkg/ent/example_test.go b/examples/entcpkg/ent/example_test.go new file mode 100644 index 000000000..17a23dddc --- /dev/null +++ b/examples/entcpkg/ent/example_test.go @@ -0,0 +1,44 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "log" + + "github.com/facebookincubator/ent/dialect/sql" +) + +// dsn for the database. In order to run the tests locally, run the following command: +// +// ENT_INTEGRATION_ENDPOINT="root:pass@tcp(localhost:3306)/test?parseTime=True" go test -v +// +var dsn string + +func ExampleUser() { + if dsn == "" { + return + } + ctx := context.Background() + drv, err := sql.Open("mysql", dsn) + if err != nil { + log.Fatalf("failed creating database client: %v", err) + } + defer drv.Close() + client := NewClient(Driver(drv)) + // creating vertices for the user's edges. + + // create user vertex with its edges. + u := client.User. + Create(). + SaveX(ctx) + log.Println("user created:", u) + + // query edges. + + // Output: +} diff --git a/examples/entcpkg/ent/generate.go b/examples/entcpkg/ent/generate.go new file mode 100644 index 000000000..14d86db5b --- /dev/null +++ b/examples/entcpkg/ent/generate.go @@ -0,0 +1,7 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +package ent + +//go:generate go run entc.go diff --git a/examples/entcpkg/ent/migrate/migrate.go b/examples/entcpkg/ent/migrate/migrate.go new file mode 100644 index 000000000..7991000b1 --- /dev/null +++ b/examples/entcpkg/ent/migrate/migrate.go @@ -0,0 +1,71 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package migrate + +import ( + "context" + "fmt" + "io" + + "github.com/facebookincubator/ent/dialect" + "github.com/facebookincubator/ent/dialect/sql/schema" +) + +var ( + // WithGlobalUniqueID sets the universal ids options to the migration. + // If this option is enabled, ent migration will allocate a 1<<32 range + // for the ids of each entity (table). + // Note that this option cannot be applied on tables that already exist. + WithGlobalUniqueID = schema.WithGlobalUniqueID + // WithDropColumn sets the drop column option to the migration. + // If this option is enabled, ent migration will drop old columns + // that were used for both fields and edges. This defaults to false. + WithDropColumn = schema.WithDropColumn + // WithDropIndex sets the drop index option to the migration. + // If this option is enabled, ent migration will drop old indexes + // that were defined in the schema. This defaults to false. + // Note that unique constraints are defined using `UNIQUE INDEX`, + // and therefore, it's recommended to enable this option to get more + // flexibility in the schema changes. + WithDropIndex = schema.WithDropIndex +) + +// Schema is the API for creating, migrating and dropping a schema. +type Schema struct { + drv dialect.Driver + universalID bool +} + +// NewSchema creates a new schema client. +func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } + +// Create creates all schema resources. +func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { + migrate, err := schema.NewMigrate(s.drv, opts...) + if err != nil { + return fmt.Errorf("ent/migrate: %v", err) + } + return migrate.Create(ctx, Tables...) +} + +// WriteTo writes the schema changes to w instead of running them against the database. +// +// if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { +// log.Fatal(err) +// } +// +func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { + drv := &schema.WriteDriver{ + Writer: w, + Driver: s.drv, + } + migrate, err := schema.NewMigrate(drv, opts...) + if err != nil { + return fmt.Errorf("ent/migrate: %v", err) + } + return migrate.Create(ctx, Tables...) +} diff --git a/examples/entcpkg/ent/migrate/schema.go b/examples/entcpkg/ent/migrate/schema.go new file mode 100644 index 000000000..a775deda1 --- /dev/null +++ b/examples/entcpkg/ent/migrate/schema.go @@ -0,0 +1,33 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package migrate + +import ( + "github.com/facebookincubator/ent/dialect/sql/schema" + "github.com/facebookincubator/ent/schema/field" +) + +var ( + // UsersColumns holds the columns for the "users" table. + UsersColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt, Increment: true}, + } + // UsersTable holds the schema information for the "users" table. + UsersTable = &schema.Table{ + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, + ForeignKeys: []*schema.ForeignKey{}, + } + // Tables holds all the tables in the schema. + Tables = []*schema.Table{ + UsersTable, + } +) + +func init() { +} diff --git a/examples/entcpkg/ent/predicate/predicate.go b/examples/entcpkg/ent/predicate/predicate.go new file mode 100644 index 000000000..1226d0823 --- /dev/null +++ b/examples/entcpkg/ent/predicate/predicate.go @@ -0,0 +1,14 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package predicate + +import ( + "github.com/facebookincubator/ent/dialect/sql" +) + +// User is the predicate function for user builders. +type User func(*sql.Selector) diff --git a/examples/entcpkg/ent/schema/user.go b/examples/entcpkg/ent/schema/user.go new file mode 100644 index 000000000..4c79d453c --- /dev/null +++ b/examples/entcpkg/ent/schema/user.go @@ -0,0 +1,22 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +package schema + +import "github.com/facebookincubator/ent" + +// User holds the schema definition for the User entity. +type User struct { + ent.Schema +} + +// Fields of the User. +func (User) Fields() []ent.Field { + return nil +} + +// Edges of the User. +func (User) Edges() []ent.Edge { + return nil +} diff --git a/examples/entcpkg/ent/tx.go b/examples/entcpkg/ent/tx.go new file mode 100644 index 000000000..42bfff020 --- /dev/null +++ b/examples/entcpkg/ent/tx.go @@ -0,0 +1,97 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "context" + + "github.com/facebookincubator/ent/dialect" + "github.com/facebookincubator/ent/examples/entcpkg/ent/migrate" +) + +// Tx is a transactional client that is created by calling Client.Tx(). +type Tx struct { + config + // User is the client for interacting with the User builders. + User *UserClient +} + +// Commit commits the transaction. +func (tx *Tx) Commit() error { + return tx.config.driver.(*txDriver).tx.Commit() +} + +// Rollback rollbacks the transaction. +func (tx *Tx) Rollback() error { + return tx.config.driver.(*txDriver).tx.Rollback() +} + +// Client returns a Client that binds to current transaction. +func (tx *Tx) Client() *Client { + return &Client{ + config: tx.config, + Schema: migrate.NewSchema(tx.driver), + User: NewUserClient(tx.config), + } +} + +// txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation. +// The idea is to support transactions without adding any extra code to the builders. +// When a builder calls to driver.Tx(), it gets the same dialect.Tx instance. +// Commit and Rollback are nop for the internal builders and the user must call one +// of them in order to commit or rollback the transaction. +// +// If a closed transaction is embedded in one of the generated entities, and the entity +// applies a query, for example: User.QueryXXX(), the query will be executed +// through the driver which created this transaction. +// +// Note that txDriver is not goroutine safe. +type txDriver struct { + // the driver we started the transaction from. + drv dialect.Driver + // tx is the underlying transaction. + tx dialect.Tx +} + +// newTx creates a new transactional driver. +func newTx(ctx context.Context, drv dialect.Driver) (*txDriver, error) { + tx, err := drv.Tx(ctx) + if err != nil { + return nil, err + } + return &txDriver{tx: tx, drv: drv}, nil +} + +// Tx returns the transaction wrapper (txDriver) to avoid Commit or Rollback calls +// from the internal builders. Should be called only by the internal builders. +func (tx *txDriver) Tx(context.Context) (dialect.Tx, error) { return tx, nil } + +// Dialect returns the dialect of the driver we started the transaction from. +func (tx *txDriver) Dialect() string { return tx.drv.Dialect() } + +// Close is a nop close. +func (*txDriver) Close() error { return nil } + +// Commit is a nop commit for the internal builders. +// User must call `Tx.Commit` in order to commit the transaction. +func (*txDriver) Commit() error { return nil } + +// Rollback is a nop rollback for the internal builders. +// User must call `Tx.Rollback` in order to rollback the transaction. +func (*txDriver) Rollback() error { return nil } + +// Exec calls tx.Exec. +func (tx *txDriver) Exec(ctx context.Context, query string, args, v interface{}) error { + return tx.tx.Exec(ctx, query, args, v) +} + +// Query calls tx.Query. +func (tx *txDriver) Query(ctx context.Context, query string, args, v interface{}) error { + return tx.tx.Query(ctx, query, args, v) +} + +var _ dialect.Driver = (*txDriver)(nil) diff --git a/examples/entcpkg/ent/user.go b/examples/entcpkg/ent/user.go new file mode 100644 index 000000000..5bd124326 --- /dev/null +++ b/examples/entcpkg/ent/user.go @@ -0,0 +1,84 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "bytes" + "fmt" + + "github.com/facebookincubator/ent/dialect/sql" +) + +// User is the model entity for the User schema. +type User struct { + config + // ID of the ent. + ID int `json:"id,omitempty"` +} + +// FromRows scans the sql response data into User. +func (u *User) FromRows(rows *sql.Rows) error { + var vu struct { + ID int + } + // the order here should be the same as in the `user.Columns`. + if err := rows.Scan( + &vu.ID, + ); err != nil { + return err + } + u.ID = vu.ID + return nil +} + +// Update returns a builder for updating this User. +// Note that, you need to call User.Unwrap() before calling this method, if this User +// was returned from a transaction, and the transaction was committed or rolled back. +func (u *User) Update() *UserUpdateOne { + return (&UserClient{u.config}).UpdateOne(u) +} + +// Unwrap unwraps the entity that was returned from a transaction after it was closed, +// so that all next queries will be executed through the driver which created the transaction. +func (u *User) Unwrap() *User { + tx, ok := u.config.driver.(*txDriver) + if !ok { + panic("ent: User is not a transactional entity") + } + u.config.driver = tx.drv + return u +} + +// String implements the fmt.Stringer. +func (u *User) String() string { + buf := bytes.NewBuffer(nil) + buf.WriteString("User(") + buf.WriteString(fmt.Sprintf("id=%v", u.ID)) + buf.WriteString(")") + return buf.String() +} + +// Users is a parsable slice of User. +type Users []*User + +// FromRows scans the sql response data into Users. +func (u *Users) FromRows(rows *sql.Rows) error { + for rows.Next() { + vu := &User{} + if err := vu.FromRows(rows); err != nil { + return err + } + *u = append(*u, vu) + } + return nil +} + +func (u Users) config(cfg config) { + for _i := range u { + u[_i].config = cfg + } +} diff --git a/examples/entcpkg/ent/user/user.go b/examples/entcpkg/ent/user/user.go new file mode 100644 index 000000000..667bdbb3f --- /dev/null +++ b/examples/entcpkg/ent/user/user.go @@ -0,0 +1,22 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package user + +const ( + // Label holds the string label denoting the user type in the database. + Label = "user" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + + // Table holds the table name of the user in the database. + Table = "users" +) + +// Columns holds all SQL columns are user fields. +var Columns = []string{ + FieldID, +} diff --git a/examples/entcpkg/ent/user/where.go b/examples/entcpkg/ent/user/where.go new file mode 100644 index 000000000..6d8189666 --- /dev/null +++ b/examples/entcpkg/ent/user/where.go @@ -0,0 +1,147 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package user + +import ( + "github.com/facebookincubator/ent/dialect/sql" + "github.com/facebookincubator/ent/examples/entcpkg/ent/predicate" +) + +// ID filters vertices based on their identifier. +func ID(id int) predicate.User { + return predicate.User( + func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldID), id)) + }, + ) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int) predicate.User { + return predicate.User( + func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldID), id)) + }, + ) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int) predicate.User { + return predicate.User( + func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldID), id)) + }, + ) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int) predicate.User { + return predicate.User( + func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(ids) == 0 { + s.Where(sql.False()) + return + } + v := make([]interface{}, len(ids)) + for i := range v { + v[i] = ids[i] + } + s.Where(sql.In(s.C(FieldID), v...)) + }, + ) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int) predicate.User { + return predicate.User( + func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(ids) == 0 { + s.Where(sql.False()) + return + } + v := make([]interface{}, len(ids)) + for i := range v { + v[i] = ids[i] + } + s.Where(sql.NotIn(s.C(FieldID), v...)) + }, + ) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int) predicate.User { + return predicate.User( + func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldID), id)) + }, + ) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int) predicate.User { + return predicate.User( + func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldID), id)) + }, + ) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int) predicate.User { + return predicate.User( + func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldID), id)) + }, + ) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int) predicate.User { + return predicate.User( + func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldID), id)) + }, + ) +} + +// And groups list of predicates with the AND operator between them. +func And(predicates ...predicate.User) predicate.User { + return predicate.User( + func(s *sql.Selector) { + for _, p := range predicates { + p(s) + } + }, + ) +} + +// Or groups list of predicates with the OR operator between them. +func Or(predicates ...predicate.User) predicate.User { + return predicate.User( + func(s *sql.Selector) { + for i, p := range predicates { + if i > 0 { + s.Or() + } + p(s) + } + }, + ) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.User) predicate.User { + return predicate.User( + func(s *sql.Selector) { + p(s.Not()) + }, + ) +} diff --git a/examples/entcpkg/ent/user_create.go b/examples/entcpkg/ent/user_create.go new file mode 100644 index 000000000..942c16807 --- /dev/null +++ b/examples/entcpkg/ent/user_create.go @@ -0,0 +1,58 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "context" + + "github.com/facebookincubator/ent/dialect/sql" + "github.com/facebookincubator/ent/examples/entcpkg/ent/user" +) + +// UserCreate is the builder for creating a User entity. +type UserCreate struct { + config +} + +// Save creates the User in the database. +func (uc *UserCreate) Save(ctx context.Context) (*User, error) { + return uc.sqlSave(ctx) +} + +// SaveX calls Save and panics if Save returns an error. +func (uc *UserCreate) SaveX(ctx context.Context) *User { + v, err := uc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +func (uc *UserCreate) sqlSave(ctx context.Context) (*User, error) { + var ( + res sql.Result + u = &User{config: uc.config} + ) + tx, err := uc.driver.Tx(ctx) + if err != nil { + return nil, err + } + builder := sql.Insert(user.Table).Default(uc.driver.Dialect()) + query, args := builder.Query() + if err := tx.Exec(ctx, query, args, &res); err != nil { + return nil, rollback(tx, err) + } + id, err := res.LastInsertId() + if err != nil { + return nil, rollback(tx, err) + } + u.ID = int(id) + if err := tx.Commit(); err != nil { + return nil, err + } + return u, nil +} diff --git a/examples/entcpkg/ent/user_delete.go b/examples/entcpkg/ent/user_delete.go new file mode 100644 index 000000000..382b437a5 --- /dev/null +++ b/examples/entcpkg/ent/user_delete.go @@ -0,0 +1,81 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "context" + + "github.com/facebookincubator/ent/dialect/sql" + "github.com/facebookincubator/ent/examples/entcpkg/ent/predicate" + "github.com/facebookincubator/ent/examples/entcpkg/ent/user" +) + +// UserDelete is the builder for deleting a User entity. +type UserDelete struct { + config + predicates []predicate.User +} + +// Where adds a new predicate to the delete builder. +func (ud *UserDelete) Where(ps ...predicate.User) *UserDelete { + ud.predicates = append(ud.predicates, ps...) + return ud +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (ud *UserDelete) Exec(ctx context.Context) (int, error) { + return ud.sqlExec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (ud *UserDelete) ExecX(ctx context.Context) int { + n, err := ud.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (ud *UserDelete) sqlExec(ctx context.Context) (int, error) { + var res sql.Result + selector := sql.Select().From(sql.Table(user.Table)) + for _, p := range ud.predicates { + p(selector) + } + query, args := sql.Delete(user.Table).FromSelect(selector).Query() + if err := ud.driver.Exec(ctx, query, args, &res); err != nil { + return 0, err + } + affected, err := res.RowsAffected() + if err != nil { + return 0, err + } + return int(affected), nil +} + +// UserDeleteOne is the builder for deleting a single User entity. +type UserDeleteOne struct { + ud *UserDelete +} + +// Exec executes the deletion query. +func (udo *UserDeleteOne) Exec(ctx context.Context) error { + n, err := udo.ud.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &ErrNotFound{user.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (udo *UserDeleteOne) ExecX(ctx context.Context) { + udo.ud.ExecX(ctx) +} diff --git a/examples/entcpkg/ent/user_query.go b/examples/entcpkg/ent/user_query.go new file mode 100644 index 000000000..d32827748 --- /dev/null +++ b/examples/entcpkg/ent/user_query.go @@ -0,0 +1,572 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "math" + + "github.com/facebookincubator/ent/dialect/sql" + "github.com/facebookincubator/ent/examples/entcpkg/ent/predicate" + "github.com/facebookincubator/ent/examples/entcpkg/ent/user" +) + +// UserQuery is the builder for querying User entities. +type UserQuery struct { + config + limit *int + offset *int + order []Order + unique []string + predicates []predicate.User + // intermediate queries. + sql *sql.Selector +} + +// Where adds a new predicate for the builder. +func (uq *UserQuery) Where(ps ...predicate.User) *UserQuery { + uq.predicates = append(uq.predicates, ps...) + return uq +} + +// Limit adds a limit step to the query. +func (uq *UserQuery) Limit(limit int) *UserQuery { + uq.limit = &limit + return uq +} + +// Offset adds an offset step to the query. +func (uq *UserQuery) Offset(offset int) *UserQuery { + uq.offset = &offset + return uq +} + +// Order adds an order step to the query. +func (uq *UserQuery) Order(o ...Order) *UserQuery { + uq.order = append(uq.order, o...) + return uq +} + +// First returns the first User entity in the query. Returns *ErrNotFound when no user was found. +func (uq *UserQuery) First(ctx context.Context) (*User, error) { + us, err := uq.Limit(1).All(ctx) + if err != nil { + return nil, err + } + if len(us) == 0 { + return nil, &ErrNotFound{user.Label} + } + return us[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (uq *UserQuery) FirstX(ctx context.Context) *User { + u, err := uq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return u +} + +// FirstID returns the first User id in the query. Returns *ErrNotFound when no id was found. +func (uq *UserQuery) FirstID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = uq.Limit(1).IDs(ctx); err != nil { + return + } + if len(ids) == 0 { + err = &ErrNotFound{user.Label} + return + } + return ids[0], nil +} + +// FirstXID is like FirstID, but panics if an error occurs. +func (uq *UserQuery) FirstXID(ctx context.Context) int { + id, err := uq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns the only User entity in the query, returns an error if not exactly one entity was returned. +func (uq *UserQuery) Only(ctx context.Context) (*User, error) { + us, err := uq.Limit(2).All(ctx) + if err != nil { + return nil, err + } + switch len(us) { + case 1: + return us[0], nil + case 0: + return nil, &ErrNotFound{user.Label} + default: + return nil, &ErrNotSingular{user.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (uq *UserQuery) OnlyX(ctx context.Context) *User { + u, err := uq.Only(ctx) + if err != nil { + panic(err) + } + return u +} + +// OnlyID returns the only User id in the query, returns an error if not exactly one id was returned. +func (uq *UserQuery) OnlyID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = uq.Limit(2).IDs(ctx); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &ErrNotFound{user.Label} + default: + err = &ErrNotSingular{user.Label} + } + return +} + +// OnlyXID is like OnlyID, but panics if an error occurs. +func (uq *UserQuery) OnlyXID(ctx context.Context) int { + id, err := uq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of Users. +func (uq *UserQuery) All(ctx context.Context) ([]*User, error) { + return uq.sqlAll(ctx) +} + +// AllX is like All, but panics if an error occurs. +func (uq *UserQuery) AllX(ctx context.Context) []*User { + us, err := uq.All(ctx) + if err != nil { + panic(err) + } + return us +} + +// IDs executes the query and returns a list of User ids. +func (uq *UserQuery) IDs(ctx context.Context) ([]int, error) { + return uq.sqlIDs(ctx) +} + +// IDsX is like IDs, but panics if an error occurs. +func (uq *UserQuery) IDsX(ctx context.Context) []int { + ids, err := uq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (uq *UserQuery) Count(ctx context.Context) (int, error) { + return uq.sqlCount(ctx) +} + +// CountX is like Count, but panics if an error occurs. +func (uq *UserQuery) CountX(ctx context.Context) int { + count, err := uq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (uq *UserQuery) Exist(ctx context.Context) (bool, error) { + return uq.sqlExist(ctx) +} + +// ExistX is like Exist, but panics if an error occurs. +func (uq *UserQuery) ExistX(ctx context.Context) bool { + exist, err := uq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the query builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (uq *UserQuery) Clone() *UserQuery { + return &UserQuery{ + config: uq.config, + limit: uq.limit, + offset: uq.offset, + order: append([]Order{}, uq.order...), + unique: append([]string{}, uq.unique...), + predicates: append([]predicate.User{}, uq.predicates...), + // clone intermediate queries. + sql: uq.sql.Clone(), + } +} + +// GroupBy used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +func (uq *UserQuery) GroupBy(field string, fields ...string) *UserGroupBy { + group := &UserGroupBy{config: uq.config} + group.fields = append([]string{field}, fields...) + group.sql = uq.sqlQuery() + return group +} + +// Select one or more fields from the given query. +func (uq *UserQuery) Select(field string, fields ...string) *UserSelect { + selector := &UserSelect{config: uq.config} + selector.fields = append([]string{field}, fields...) + selector.sql = uq.sqlQuery() + return selector +} + +func (uq *UserQuery) sqlAll(ctx context.Context) ([]*User, error) { + rows := &sql.Rows{} + selector := uq.sqlQuery() + if unique := uq.unique; len(unique) == 0 { + selector.Distinct() + } + query, args := selector.Query() + if err := uq.driver.Query(ctx, query, args, rows); err != nil { + return nil, err + } + defer rows.Close() + var us Users + if err := us.FromRows(rows); err != nil { + return nil, err + } + us.config(uq.config) + return us, nil +} + +func (uq *UserQuery) sqlCount(ctx context.Context) (int, error) { + rows := &sql.Rows{} + selector := uq.sqlQuery() + unique := []string{user.FieldID} + if len(uq.unique) > 0 { + unique = uq.unique + } + selector.Count(sql.Distinct(selector.Columns(unique...)...)) + query, args := selector.Query() + if err := uq.driver.Query(ctx, query, args, rows); err != nil { + return 0, err + } + defer rows.Close() + if !rows.Next() { + return 0, errors.New("ent: no rows found") + } + var n int + if err := rows.Scan(&n); err != nil { + return 0, fmt.Errorf("ent: failed reading count: %v", err) + } + return n, nil +} + +func (uq *UserQuery) sqlExist(ctx context.Context) (bool, error) { + n, err := uq.sqlCount(ctx) + if err != nil { + return false, fmt.Errorf("ent: check existence: %v", err) + } + return n > 0, nil +} + +func (uq *UserQuery) sqlIDs(ctx context.Context) ([]int, error) { + vs, err := uq.sqlAll(ctx) + if err != nil { + return nil, err + } + var ids []int + for _, v := range vs { + ids = append(ids, v.ID) + } + return ids, nil +} + +func (uq *UserQuery) sqlQuery() *sql.Selector { + t1 := sql.Table(user.Table) + selector := sql.Select(t1.Columns(user.Columns...)...).From(t1) + if uq.sql != nil { + selector = uq.sql + selector.Select(selector.Columns(user.Columns...)...) + } + for _, p := range uq.predicates { + p(selector) + } + for _, p := range uq.order { + p(selector) + } + if offset := uq.offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := uq.limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// UserGroupBy is the builder for group-by User entities. +type UserGroupBy struct { + config + fields []string + fns []Aggregate + // intermediate queries. + sql *sql.Selector +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (ugb *UserGroupBy) Aggregate(fns ...Aggregate) *UserGroupBy { + ugb.fns = append(ugb.fns, fns...) + return ugb +} + +// Scan applies the group-by query and scan the result into the given value. +func (ugb *UserGroupBy) Scan(ctx context.Context, v interface{}) error { + return ugb.sqlScan(ctx, v) +} + +// ScanX is like Scan, but panics if an error occurs. +func (ugb *UserGroupBy) ScanX(ctx context.Context, v interface{}) { + if err := ugb.Scan(ctx, v); err != nil { + panic(err) + } +} + +// Strings returns list of strings from group-by. It is only allowed when querying group-by with one field. +func (ugb *UserGroupBy) Strings(ctx context.Context) ([]string, error) { + if len(ugb.fields) > 1 { + return nil, errors.New("ent: UserGroupBy.Strings is not achievable when grouping more than 1 field") + } + var v []string + if err := ugb.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// StringsX is like Strings, but panics if an error occurs. +func (ugb *UserGroupBy) StringsX(ctx context.Context) []string { + v, err := ugb.Strings(ctx) + if err != nil { + panic(err) + } + return v +} + +// Ints returns list of ints from group-by. It is only allowed when querying group-by with one field. +func (ugb *UserGroupBy) Ints(ctx context.Context) ([]int, error) { + if len(ugb.fields) > 1 { + return nil, errors.New("ent: UserGroupBy.Ints is not achievable when grouping more than 1 field") + } + var v []int + if err := ugb.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// IntsX is like Ints, but panics if an error occurs. +func (ugb *UserGroupBy) IntsX(ctx context.Context) []int { + v, err := ugb.Ints(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64s returns list of float64s from group-by. It is only allowed when querying group-by with one field. +func (ugb *UserGroupBy) Float64s(ctx context.Context) ([]float64, error) { + if len(ugb.fields) > 1 { + return nil, errors.New("ent: UserGroupBy.Float64s is not achievable when grouping more than 1 field") + } + var v []float64 + if err := ugb.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// Float64sX is like Float64s, but panics if an error occurs. +func (ugb *UserGroupBy) Float64sX(ctx context.Context) []float64 { + v, err := ugb.Float64s(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bools returns list of bools from group-by. It is only allowed when querying group-by with one field. +func (ugb *UserGroupBy) Bools(ctx context.Context) ([]bool, error) { + if len(ugb.fields) > 1 { + return nil, errors.New("ent: UserGroupBy.Bools is not achievable when grouping more than 1 field") + } + var v []bool + if err := ugb.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// BoolsX is like Bools, but panics if an error occurs. +func (ugb *UserGroupBy) BoolsX(ctx context.Context) []bool { + v, err := ugb.Bools(ctx) + if err != nil { + panic(err) + } + return v +} + +func (ugb *UserGroupBy) sqlScan(ctx context.Context, v interface{}) error { + rows := &sql.Rows{} + query, args := ugb.sqlQuery().Query() + if err := ugb.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +func (ugb *UserGroupBy) sqlQuery() *sql.Selector { + selector := ugb.sql + columns := make([]string, 0, len(ugb.fields)+len(ugb.fns)) + columns = append(columns, ugb.fields...) + for _, fn := range ugb.fns { + columns = append(columns, fn.SQL(selector)) + } + return selector.Select(columns...).GroupBy(ugb.fields...) +} + +// UserSelect is the builder for select fields of User entities. +type UserSelect struct { + config + fields []string + // intermediate queries. + sql *sql.Selector +} + +// Scan applies the selector query and scan the result into the given value. +func (us *UserSelect) Scan(ctx context.Context, v interface{}) error { + return us.sqlScan(ctx, v) +} + +// ScanX is like Scan, but panics if an error occurs. +func (us *UserSelect) ScanX(ctx context.Context, v interface{}) { + if err := us.Scan(ctx, v); err != nil { + panic(err) + } +} + +// Strings returns list of strings from selector. It is only allowed when selecting one field. +func (us *UserSelect) Strings(ctx context.Context) ([]string, error) { + if len(us.fields) > 1 { + return nil, errors.New("ent: UserSelect.Strings is not achievable when selecting more than 1 field") + } + var v []string + if err := us.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// StringsX is like Strings, but panics if an error occurs. +func (us *UserSelect) StringsX(ctx context.Context) []string { + v, err := us.Strings(ctx) + if err != nil { + panic(err) + } + return v +} + +// Ints returns list of ints from selector. It is only allowed when selecting one field. +func (us *UserSelect) Ints(ctx context.Context) ([]int, error) { + if len(us.fields) > 1 { + return nil, errors.New("ent: UserSelect.Ints is not achievable when selecting more than 1 field") + } + var v []int + if err := us.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// IntsX is like Ints, but panics if an error occurs. +func (us *UserSelect) IntsX(ctx context.Context) []int { + v, err := us.Ints(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64s returns list of float64s from selector. It is only allowed when selecting one field. +func (us *UserSelect) Float64s(ctx context.Context) ([]float64, error) { + if len(us.fields) > 1 { + return nil, errors.New("ent: UserSelect.Float64s is not achievable when selecting more than 1 field") + } + var v []float64 + if err := us.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// Float64sX is like Float64s, but panics if an error occurs. +func (us *UserSelect) Float64sX(ctx context.Context) []float64 { + v, err := us.Float64s(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bools returns list of bools from selector. It is only allowed when selecting one field. +func (us *UserSelect) Bools(ctx context.Context) ([]bool, error) { + if len(us.fields) > 1 { + return nil, errors.New("ent: UserSelect.Bools is not achievable when selecting more than 1 field") + } + var v []bool + if err := us.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// BoolsX is like Bools, but panics if an error occurs. +func (us *UserSelect) BoolsX(ctx context.Context) []bool { + v, err := us.Bools(ctx) + if err != nil { + panic(err) + } + return v +} + +func (us *UserSelect) sqlScan(ctx context.Context, v interface{}) error { + rows := &sql.Rows{} + query, args := us.sqlQuery().Query() + if err := us.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +func (us *UserSelect) sqlQuery() sql.Querier { + view := "user_view" + return sql.Select(us.fields...).From(us.sql.As(view)) +} diff --git a/examples/entcpkg/ent/user_update.go b/examples/entcpkg/ent/user_update.go new file mode 100644 index 000000000..53fe56af5 --- /dev/null +++ b/examples/entcpkg/ent/user_update.go @@ -0,0 +1,157 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +// Code generated (@generated) by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + + "github.com/facebookincubator/ent/dialect/sql" + "github.com/facebookincubator/ent/examples/entcpkg/ent/predicate" + "github.com/facebookincubator/ent/examples/entcpkg/ent/user" +) + +// UserUpdate is the builder for updating User entities. +type UserUpdate struct { + config + predicates []predicate.User +} + +// Where adds a new predicate for the builder. +func (uu *UserUpdate) Where(ps ...predicate.User) *UserUpdate { + uu.predicates = append(uu.predicates, ps...) + return uu +} + +// Save executes the query and returns the number of rows/vertices matched by this operation. +func (uu *UserUpdate) Save(ctx context.Context) (int, error) { + return uu.sqlSave(ctx) +} + +// SaveX is like Save, but panics if an error occurs. +func (uu *UserUpdate) SaveX(ctx context.Context) int { + affected, err := uu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (uu *UserUpdate) Exec(ctx context.Context) error { + _, err := uu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (uu *UserUpdate) ExecX(ctx context.Context) { + if err := uu.Exec(ctx); err != nil { + panic(err) + } +} + +func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { + selector := sql.Select(user.FieldID).From(sql.Table(user.Table)) + for _, p := range uu.predicates { + p(selector) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err = uu.driver.Query(ctx, query, args, rows); err != nil { + return 0, err + } + defer rows.Close() + var ids []int + for rows.Next() { + var id int + if err := rows.Scan(&id); err != nil { + return 0, fmt.Errorf("ent: failed reading id: %v", err) + } + ids = append(ids, id) + } + if len(ids) == 0 { + return 0, nil + } + + tx, err := uu.driver.Tx(ctx) + if err != nil { + return 0, err + } + if err = tx.Commit(); err != nil { + return 0, err + } + return len(ids), nil +} + +// UserUpdateOne is the builder for updating a single User entity. +type UserUpdateOne struct { + config + id int +} + +// Save executes the query and returns the updated entity. +func (uuo *UserUpdateOne) Save(ctx context.Context) (*User, error) { + return uuo.sqlSave(ctx) +} + +// SaveX is like Save, but panics if an error occurs. +func (uuo *UserUpdateOne) SaveX(ctx context.Context) *User { + u, err := uuo.Save(ctx) + if err != nil { + panic(err) + } + return u +} + +// Exec executes the query on the entity. +func (uuo *UserUpdateOne) Exec(ctx context.Context) error { + _, err := uuo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (uuo *UserUpdateOne) ExecX(ctx context.Context) { + if err := uuo.Exec(ctx); err != nil { + panic(err) + } +} + +func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (u *User, err error) { + selector := sql.Select(user.Columns...).From(sql.Table(user.Table)) + user.ID(uuo.id)(selector) + rows := &sql.Rows{} + query, args := selector.Query() + if err = uuo.driver.Query(ctx, query, args, rows); err != nil { + return nil, err + } + defer rows.Close() + var ids []int + for rows.Next() { + var id int + u = &User{config: uuo.config} + if err := u.FromRows(rows); err != nil { + return nil, fmt.Errorf("ent: failed scanning row into User: %v", err) + } + id = u.ID + ids = append(ids, id) + } + switch n := len(ids); { + case n == 0: + return nil, &ErrNotFound{fmt.Sprintf("User with id: %v", uuo.id)} + case n > 1: + return nil, fmt.Errorf("ent: more than one User with the same id: %v", uuo.id) + } + + tx, err := uuo.driver.Tx(ctx) + if err != nil { + return nil, err + } + if err = tx.Commit(); err != nil { + return nil, err + } + return u, nil +} diff --git a/examples/entcpkg/entcpkg.go b/examples/entcpkg/entcpkg.go new file mode 100644 index 000000000..c4723156d --- /dev/null +++ b/examples/entcpkg/entcpkg.go @@ -0,0 +1,30 @@ +// Copyright 2019-present Facebook Inc. All rights reserved. +// This source code is licensed under the Apache 2.0 license found +// in the LICENSE file in the root directory of this source tree. + +package main + +import ( + "context" + "fmt" + "log" + + "github.com/facebookincubator/ent/examples/entcpkg/ent" + + _ "github.com/mattn/go-sqlite3" +) + +func main() { + client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + if err != nil { + log.Fatalf("failed opening connection to sqlite: %v", err) + } + defer client.Close() + ctx := context.Background() + // run the auto migration tool. + if err := client.Schema.Create(ctx); err != nil { + log.Fatalf("failed creating schema resources: %v", err) + } + usr := client.User.Create().SaveX(ctx) + fmt.Println("boring user:", usr) +} diff --git a/examples/m2m2types/ent/generate.go b/examples/m2m2types/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/m2m2types/ent/generate.go +++ b/examples/m2m2types/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/m2mbidi/ent/generate.go b/examples/m2mbidi/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/m2mbidi/ent/generate.go +++ b/examples/m2mbidi/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/m2mrecur/ent/generate.go b/examples/m2mrecur/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/m2mrecur/ent/generate.go +++ b/examples/m2mrecur/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/o2m2types/ent/generate.go b/examples/o2m2types/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/o2m2types/ent/generate.go +++ b/examples/o2m2types/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/o2mrecur/ent/generate.go b/examples/o2mrecur/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/o2mrecur/ent/generate.go +++ b/examples/o2mrecur/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/o2o2types/ent/generate.go b/examples/o2o2types/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/o2o2types/ent/generate.go +++ b/examples/o2o2types/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/o2obidi/ent/generate.go b/examples/o2obidi/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/o2obidi/ent/generate.go +++ b/examples/o2obidi/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/o2orecur/ent/generate.go b/examples/o2orecur/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/o2orecur/ent/generate.go +++ b/examples/o2orecur/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/start/ent/generate.go b/examples/start/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/start/ent/generate.go +++ b/examples/start/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema diff --git a/examples/traversal/ent/generate.go b/examples/traversal/ent/generate.go index 7b45d2695..076564b64 100644 --- a/examples/traversal/ent/generate.go +++ b/examples/traversal/ent/generate.go @@ -4,4 +4,4 @@ package ent -//go:generate go run ../../../entc/cmd/entc/entc.go generate --header "Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema +//go:generate go run github.com/facebookincubator/ent/cmd/entc generate --header "// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated (@generated) by entc, DO NOT EDIT." ./schema