Introduction

Installation

The project comes with a codegen tool called ent. In order to install ent run the following command:

  1. go get -d entgo.io/ent/cmd/ent

Initialize A New Schema

In order to generate one or more schema templates, run ent init as follows:

  1. go run entgo.io/ent/cmd/ent init User Pet

init will create the 2 schemas (user.go and pet.go) under the ent/schema directory. If the ent directory does not exist, it will create it as well. The convention is to have an ent directory under the root directory of the project.

Generate Assets

After adding a few fields and edges, you want to generate the assets for working with your entities. Run ent generate from the root directory of the project, or use go generate:

  1. go generate ./ent

The generate command generates the following assets for the schemas:

  • Client and Tx objects used for interacting with the graph.
  • CRUD builders for each schema type. See CRUD for more info.
  • Entity object (Go struct) for each of the schema types.
  • Package containing constants and predicates used for interacting with the builders.
  • A migrate package for SQL dialects. See Migration for more info.
  • A hook package for adding mutation middlewares. See Hooks for more info.

Version Compatibility Between entc And ent

When working with ent CLI in a project, you want to make sure the version being used by the CLI 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 ent. If your project does not use Go modules, setup one as follows:

  1. go mod init <project>

And then, re-run the following command in order to add ent to your go.mod file:

  1. go get -d entgo.io/ent/cmd/ent

Add a generate.go file to your project under <project>/ent:

  1. package ent
  2. //go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema

Finally, you can run go generate ./ent from the root directory of your project in order to run ent code generation on your project schemas.

Code Generation Options

For more info about codegen options, run ent generate -h:

  1. generate go code for the schema directory
  2. Usage:
  3. ent generate [flags] path
  4. Examples:
  5. ent generate ./ent/schema
  6. ent generate github.com/a8m/x
  7. Flags:
  8. --feature strings extend codegen with additional features
  9. --header string override codegen header
  10. -h, --help help for generate
  11. --idtype [int string] type of the id field (default int)
  12. --storage string storage driver to support in codegen (default "sql")
  13. --target string target directory for codegen
  14. --template strings external templates to execute

Storage Options

ent can generate assets for both SQL and Gremlin dialect. The default dialect is SQL.

External Templates

ent accepts external Go templates to execute. If the template name already defined by ent, it will override the existing one. Otherwise, it will write the execution output to a file with the same name as the template. The flag format supports file, dir and glob as follows:

  1. go run entgo.io/ent/cmd/ent generate --template <dir-path> --template glob="path/to/*.tmpl" ./ent/schema

More information and examples can be found in the external templates doc.

Use entc as a Package

Another option for running ent code generation is to create a file named ent/entc.go with the following content, and then the ent/generate.go file to execute it:

ent/entc.go

  1. // +build ignore
  2. package main
  3. import (
  4. "log"
  5. "entgo.io/ent/entc"
  6. "entgo.io/ent/entc/gen"
  7. "entgo.io/ent/schema/field"
  8. )
  9. func main() {
  10. if err := entc.Generate("./schema", &gen.Config{}); err != nil {
  11. log.Fatal("running ent codegen:", err)
  12. }
  13. }

ent/generate.go

  1. package ent
  2. //go:generate go run -mod=mod entc.go

The full example exists in GitHub.

Schema Description

In order to get a description of your graph schema, run:

  1. go run entgo.io/ent/cmd/ent describe ./ent/schema

An example for the output is as follows:

  1. Pet:
  2. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  3. | Field | Type | Unique | Optional | Nillable | Default | UpdateDefault | Immutable | StructTag | Validators |
  4. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  5. | id | int | false | false | false | false | false | false | json:"id,omitempty" | 0 |
  6. | name | string | false | false | false | false | false | false | json:"name,omitempty" | 0 |
  7. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  8. +-------+------+---------+---------+----------+--------+----------+
  9. | Edge | Type | Inverse | BackRef | Relation | Unique | Optional |
  10. +-------+------+---------+---------+----------+--------+----------+
  11. | owner | User | true | pets | M2O | true | true |
  12. +-------+------+---------+---------+----------+--------+----------+
  13. User:
  14. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  15. | Field | Type | Unique | Optional | Nillable | Default | UpdateDefault | Immutable | StructTag | Validators |
  16. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  17. | id | int | false | false | false | false | false | false | json:"id,omitempty" | 0 |
  18. | age | int | false | false | false | false | false | false | json:"age,omitempty" | 0 |
  19. | name | string | false | false | false | false | false | false | json:"name,omitempty" | 0 |
  20. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  21. +------+------+---------+---------+----------+--------+----------+
  22. | Edge | Type | Inverse | BackRef | Relation | Unique | Optional |
  23. +------+------+---------+---------+----------+--------+----------+
  24. | pets | Pet | false | | O2M | false | true |
  25. +------+------+---------+---------+----------+--------+----------+

Code Generation Hooks

The entc package provides an option to add a list of hooks (middlewares) to the code-generation phase. This option is ideal for adding custom validators for the schema, or for generating additional assets using the graph schema.

  1. // +build ignore
  2. package main
  3. import (
  4. "fmt"
  5. "log"
  6. "reflect"
  7. "entgo.io/ent/entc"
  8. "entgo.io/ent/entc/gen"
  9. )
  10. func main() {
  11. err := entc.Generate("./schema", &gen.Config{
  12. Hooks: []gen.Hook{
  13. EnsureStructTag("json"),
  14. },
  15. })
  16. if err != nil {
  17. log.Fatalf("running ent codegen: %v", err)
  18. }
  19. }
  20. // EnsureStructTag ensures all fields in the graph have a specific tag name.
  21. func EnsureStructTag(name string) gen.Hook {
  22. return func(next gen.Generator) gen.Generator {
  23. return gen.GenerateFunc(func(g *gen.Graph) error {
  24. for _, node := range g.Nodes {
  25. for _, field := range node.Fields {
  26. tag := reflect.StructTag(field.StructTag)
  27. if _, ok := tag.Lookup(name); !ok {
  28. return fmt.Errorf("struct tag %q is missing for field %s.%s", name, node.Name, field.Name)
  29. }
  30. }
  31. }
  32. return next.Generate(g)
  33. })
  34. }
  35. }

External Dependencies

In order to extend the generated client and builders under the ent package, and inject them external dependencies as struct fields, use the entc.Dependency option in your ent/entc.go file:

ent/entc.go

  1. func main() {
  2. opts := []entc.Option{
  3. entc.Dependency(
  4. entc.DependencyType(&http.Client{}),
  5. ),
  6. entc.Dependency(
  7. entc.DependencyName("Writer"),
  8. entc.DependencyTypeInfo(&field.TypeInfo{
  9. Ident: "io.Writer",
  10. PkgPath: "io",
  11. }),
  12. ),
  13. }
  14. if err := entc.Generate("./schema", &gen.Config{}, opts...); err != nil {
  15. log.Fatalf("running ent codegen: %v", err)
  16. }
  17. }

Then, use it in your application:

example_test.go

  1. func Example_Deps() {
  2. client, err := ent.Open(
  3. "sqlite3",
  4. "file:ent?mode=memory&cache=shared&_fk=1",
  5. ent.Writer(os.Stdout),
  6. ent.HTTPClient(http.DefaultClient),
  7. )
  8. if err != nil {
  9. log.Fatalf("failed opening connection to sqlite: %v", err)
  10. }
  11. defer client.Close()
  12. // An example for using the injected dependencies in the generated builders.
  13. client.User.Use(func(next ent.Mutator) ent.Mutator {
  14. return hook.UserFunc(func(ctx context.Context, m *ent.UserMutation) (ent.Value, error) {
  15. _ = m.HTTPClient
  16. _ = m.Writer
  17. return next.Mutate(ctx, m)
  18. })
  19. })
  20. // ...
  21. }

The full example exists in GitHub.

Feature Flags

The entc package provides a collection of code-generation features that be added or removed using flags.

For more information, please see the features-flags page.