mirror of
https://github.com/ent/ent.git
synced 2026-03-05 19:35:23 +03:00
https://go.dev/ref/mod#build-commands is the documentation for the -mod flag. It seems that basically -mod=mod is never harmful in ent's case, all it does is tell the go command that it can add ent to the go.mod file if it's not already present
4.7 KiB
Executable File
4.7 KiB
Executable File
id, title
| id | title |
|---|---|
| traversals | Graph Traversal |
For the purpose of the example, we'll generate the following graph:
The first step is to generate the 3 schemas: Pet, User, Group.
go run -mod=mod entgo.io/ent/cmd/ent init Pet User Group
Add the necessary fields and edges for the schemas:
ent/schema/pet.go
// Pet holds the schema definition for the Pet entity.
type Pet struct {
ent.Schema
}
// Fields of the Pet.
func (Pet) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// Edges of the Pet.
func (Pet) Edges() []ent.Edge {
return []ent.Edge{
edge.To("friends", Pet.Type),
edge.From("owner", User.Type).
Ref("pets").
Unique(),
}
}
ent/schema/user.go
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int("age"),
field.String("name"),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("pets", Pet.Type),
edge.To("friends", User.Type),
edge.From("groups", Group.Type).
Ref("users"),
edge.From("manage", Group.Type).
Ref("admin"),
}
}
ent/schema/group.go
// Group holds the schema definition for the Group entity.
type Group struct {
ent.Schema
}
// Fields of the Group.
func (Group) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// Edges of the Group.
func (Group) Edges() []ent.Edge {
return []ent.Edge{
edge.To("users", User.Type),
edge.To("admin", User.Type).
Unique(),
}
}
Let's write the code for populating the vertices and the edges to the graph:
func Gen(ctx context.Context, client *ent.Client) error {
hub, err := client.Group.
Create().
SetName("Github").
Save(ctx)
if err != nil {
return fmt.Errorf("failed creating the group: %w", err)
}
// Create the admin of the group.
// Unlike `Save`, `SaveX` panics if an error occurs.
dan := client.User.
Create().
SetAge(29).
SetName("Dan").
AddManage(hub).
SaveX(ctx)
// Create "Ariel" and its pets.
a8m := client.User.
Create().
SetAge(30).
SetName("Ariel").
AddGroups(hub).
AddFriends(dan).
SaveX(ctx)
pedro := client.Pet.
Create().
SetName("Pedro").
SetOwner(a8m).
SaveX(ctx)
xabi := client.Pet.
Create().
SetName("Xabi").
SetOwner(a8m).
SaveX(ctx)
// Create "Alex" and its pets.
alex := client.User.
Create().
SetAge(37).
SetName("Alex").
SaveX(ctx)
coco := client.Pet.
Create().
SetName("Coco").
SetOwner(alex).
AddFriends(pedro).
SaveX(ctx)
fmt.Println("Pets created:", pedro, xabi, coco)
// Output:
// Pets created: Pet(id=1, name=Pedro) Pet(id=2, name=Xabi) Pet(id=3, name=Coco)
return nil
}
Let's go over a few traversals, and show the code for them:
The traversal above starts from a Group entity, continues to its admin (edge),
continues to its friends (edge), gets their pets (edge), gets each pet's friends (edge),
and requests their owners.
func Traverse(ctx context.Context, client *ent.Client) error {
owner, err := client.Group. // GroupClient.
Query(). // Query builder.
Where(group.Name("Github")). // Filter only Github group (only 1).
QueryAdmin(). // Getting Dan.
QueryFriends(). // Getting Dan's friends: [Ariel].
QueryPets(). // Their pets: [Pedro, Xabi].
QueryFriends(). // Pedro's friends: [Coco], Xabi's friends: [].
QueryOwner(). // Coco's owner: Alex.
Only(ctx) // Expect only one entity to return in the query.
if err != nil {
return fmt.Errorf("failed querying the owner: %w", err)
}
fmt.Println(owner)
// Output:
// User(id=3, age=37, name=Alex)
return nil
}
What about the following traversal?
We want to get all pets (entities) that have an owner (edge) that is a friend
(edge) of some group admin (edge).
func Traverse(ctx context.Context, client *ent.Client) error {
pets, err := client.Pet.
Query().
Where(
pet.HasOwnerWith(
user.HasFriendsWith(
user.HasManage(),
),
),
).
All(ctx)
if err != nil {
return fmt.Errorf("failed querying the pets: %w", err)
}
fmt.Println(pets)
// Output:
// [Pet(id=1, name=Pedro) Pet(id=2, name=Xabi)]
return nil
}
The full example exists in GitHub.


