图遍历
Last updated
Last updated
为了举例,我们会生成一个下面这样的图:
第一步,生成 3 个模式: Pet
, User
, Group
.
entc init Pet User Group
然后,为模式添加一些必要的字段和边:
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"),
}
}
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(),
}
}
让我们开始编写用于填充图的顶点和边的代码:
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)
}
// 为群组添加一个 admin.
// 不同于 `Save`, `SaveX` 遇到错误时会引起 panics.
dan := client.User.
Create().
SetAge(29).
SetName("Dan").
AddManage(hub).
SaveX(ctx)
// 创建 "Ariel" 用户和他的宠物
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)
// 创建 "Alex" 用户和他的宠物。
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
}
再看一下我们要遍历的图及其代码:
上面的遍历开始于一个 Group
实体:通过 admin
边、 friends
边、pets
边找到他们的宠物,然后再获取每个宠物的朋友(宠物的 frieds
边)的主人。
func Traverse(ctx context.Context, client *ent.Client) error {
owner, err := client.Group. // GroupClient.
Query(). // Query builder.
Where(group.Name("Github")). // 要求群组名为 Github
QueryAdmin(). // 找到 Dan.
QueryFriends(). // 找到 Dan 的朋友列表: [Ariel].
QueryPets(). // 他们的宠物列表: [Pedro, Xabi].
QueryFriends(). // Pedro 的朋友: [Coco], Xabi 的朋友: [].
QueryOwner(). // Coco 的主人: Alex.
Only(ctx) // 本次遍历中期望只返回一个实体。
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
}
下面这个图又怎么遍历呢?
我们想获取某个群组的 admin
的 friend
的全部宠物。
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
}
完整的实例请参考 GitHub.