Paul O'Shannessy f72afcceea Adopt Contributor Covenant
Summary:
In order to foster healthy open source communities, we're adopting the
[Contributor Covenant](https://www.contributor-covenant.org/). It has been
built by open source community members and represents a shared understanding of
what is expected from a healthy community.

Reviewed By: josephsavona, danobi, rdzhabarov

Differential Revision: D17104640

fbshipit-source-id: d210000de686c5f0d97d602b50472d5869bc6a49
2019-08-29 23:22:44 -07:00
2019-08-29 23:22:44 -07:00
2019-06-17 08:23:39 -07:00
2019-08-27 04:48:28 -07:00
2019-08-19 09:32:14 -07:00
2019-08-26 08:02:12 -07:00
2019-08-19 09:32:14 -07:00

Ent

Note: if you edit this file, don't forget to update the Wiki as well.

First Installation

If it is the first time you work with entc, you need to compile it manually, since we don't have any official binary distribution.

cd fbsource/fbcode/github.com/facebookincubator/ent/entc/cmd/entc
go build
sudo mv entc /usr/local/bin

Creating Schema

If you came here to see how to create your first schema, it's preferred to give entc to do it for you in order to keep the same standard for all projects that use it. Run the following (replace User/Group with your entities):

entc init User Group

The schema that was created has 2 methods: User.Fields and User.Edges. The first defines the fields/properties of the entity in the graph, and the second defines the edges for other entities (or to itself) in the graph.

Here are a few examples that will help you to understand what field/edge to declare in your schema

type User struct{
	ent.Schema
}

func (User) Fields() []ent.Field {
	return []ent.Field{
		// "age" defines a field of type int, with a positive validator.
		// The validator is called on create or update on this field.
		field.Int("age").
			Positive(),

		// "name" defines a field of type string, and overrides the standard
		// tag for the generated entity.
		field.String("name").
			StructTag(`json:"first_name" graphql:"first_name"`),

		// "last" defines a field of type string, with default (on creation) to "unknown",
		// and 2 validators.
		field.String("last").
			Default("unknown").
			Match(regexp.MustCompile("[a-zA-Z_]+$")).
			Validate(func(s string) error {
				if strings.ToLower(s) == s {
					return errors.New("last name must begin with uppercase")
				}
				return nil
			}),
	}
}

func (User) Edges() []ent.Edge {
	return []ent.Edge{
		// "groups" defines an edge to the Group entity (also a schema in this package).
		// The relation type for this edge is many-2-many. 
		edge.To("groups", Group.Type),
		
		// "workplace" defines an edge from the Company entity (also a schema in this package).
		// The relation type for this edge is many-2-one, and the owner of this edge, is the
		// Company entity. 
		edge.From("workplace", Company.Type).Unique().Ref("employees"),
		
		// "parent" defines an edge from a User to itself.
		edge.To("parent", User.Type).Unique().From("children"),
	}
}

Code Generation

After running init, run the codegen on the directory the was created (ent/schema).

entc generate ./ent/schema

In addition to the "production" code, entc generates for you also an example_test.go file with example for each ent in the graph.

Working with the generated code

First, you need to create the ent.Client in order to interact with the different builders, then, use this client to create, update, delete, or query entities.

package main

import (
	"log"
	
	"<project>/ent"
	"<project>/ent/user"
	"github.com/facebookincubator/ent/dialect/sql"
)

func main() {
	ctx := context.Backgorund()
	drv, err := sql.Open("mysql", "root:pass@tcp(localhost:3306)/test?charset=utf8&parseTime=True")
	if err != nil {
    	log.Fatal(err)
    }
	defer drv.Close()
	client := ent.NewClient(drv)
	
	// Create:
	
	// `client.User` holds the `UserClient`, and `client.User.Create()` returns a new User creator.
	a8m, err := client.User.
		Create().
		SetAge(30)
		SetName("a8m").
		Save(ctx)	
	if err != nil {
		log.Fatal(err)
	}	
	// If you want to ignore the error checks in the code, replace `Save` with `SaveX`.
	
	// Delete:
	
	// delete one.
	client.User.DeleteOne(a8m).ExecX(ctx)
	// delete all.
	client.User.Delete().ExecX(ctx)
	// delete with condition.
	client.User.Delete().Where(user.Name("a8m")).ExecX(ctx)
	
	// Update:
	
	// add a user to a group.
    a8m = client.User.UpdateOne(a8m).AddGroups(grp).SaveX(ctx)
    // delete a user from a group.
    a8m = client.User.UpdateOne(a8m).RemoveGroups(grp).SaveX(ctx)
    // add user to all groups.
    client.Group.Update().AddUsers(a8m).ExecX(ctx)
	
	// Query:
	
	// get all groups.
	groups := client.Group.Query().AllX(ctx) 
	// get all groups of a specific user.
	groups = a8m.QueryGroups().AllX(ctx)
	// query by path.
	users := client.Group.
		Query().
		Where(group.HasUsers(), group.NameHasPrefix("fb")).
		QueryUsers().
		AllX(ctx)
		
	// Aggregation:
	
	var v []struct{
		Name  string `json:"name"`
		Count int    `json:"count"`
	}
	client.User.
		Query().
		GroupBy(user.FieldName).
		Aggregate(ent.Count()).
		ScanX(&v)
}
Description
An entity framework for Go
Readme Apache-2.0 51 MiB
Languages
Go 100%