mirror of
https://github.com/ent/ent.git
synced 2026-05-24 09:31:56 +03:00
ent/doc: traversal docs and example
Reviewed By: alexsn Differential Revision: D17112102 fbshipit-source-id: a4ed3fe82f804631796e4b197dba5f936abdc0fc
This commit is contained in:
committed by
Facebook Github Bot
parent
e85b080178
commit
4ae7526a65
@@ -1,5 +1,214 @@
|
||||
---
|
||||
id: traversals
|
||||
title: Traverse The Graph
|
||||
title: Graph Traversal
|
||||
---
|
||||
Lorem ipsum.
|
||||
|
||||
For the purpose of the example, we'll generate the following graph:
|
||||
|
||||
|
||||

|
||||
|
||||
The first step is to generate the 3 schemas: `Pet`, `User`, `Group`.
|
||||
|
||||
```console
|
||||
entc init Pet User Group
|
||||
```
|
||||
|
||||
Add the necessary fields and edges for the schemas:
|
||||
|
||||
`ent/schema/pet.go`
|
||||
|
||||
```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`
|
||||
|
||||
```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"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`ent/schema/group.go`
|
||||
|
||||
```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:
|
||||
|
||||
```go
|
||||
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: %v", 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 then:
|
||||
|
||||

|
||||
|
||||
The traversal above starts from a `Group` entity, continue to its `admin` (edge),
|
||||
continue to its `friends` (edge), get their `pets` (edge), get each pet's `friends` (edge),
|
||||
and request their owners.
|
||||
|
||||
```go
|
||||
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: %v", 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 it's a `friend`
|
||||
(edge) of some group `admin` (edge).
|
||||
|
||||
```go
|
||||
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: %v", err)
|
||||
}
|
||||
fmt.Println(pets)
|
||||
// Output:
|
||||
// [Pet(id=1, name=Pedro) Pet(id=2, name=Xabi)]
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
The full example exists in [GitHub](https://github.com/facebookincubator/ent/tree/master/examples/traversal).
|
||||
|
||||
Reference in New Issue
Block a user