グラフ トラバーサル
この例では、以下のグラフを生成します。
最初のステップは、3つのスキーマを生成することです。Pet
、User
、Group
です。
go run -mod=mod entgo.io/ent/cmd/ent new Pet User Group
スキーマに必要なフィールドやエッジを追加します。
ent/schema/pet.go
// Pet は、Pet エンティティのスキーマ定義を保持する
type Pet struct {
ent.Schema
}
// Fields of the Pet.
func (Pet) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// 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は、Userエンティティのスキーマ定義を保持する
type User struct {
ent.Schema
}
// Userのフィールド
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int("age"),
field.String("name"),
}
}
// 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は、Groupエンティティのスキーマ定義を保持する
type Group struct {
ent.Schema
}
// Groupのフィールド
func (Group) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// 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: %w", err)
}
// グループの管理者を作成する
// `Save` と異なり、`SaveX` はエラーが発生するとパニックになります。
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
(エッジ) を取得し、各ペットのfriends
(エッジ) を取得し、彼らの飼い主達を要求しています。
func Traverse(ctx context.Context, client *ent.Client) error {
owner, err := client.Group. // GroupClient.
Query(). // Query builder.
Where(group.Name("Github")). // Githubグループに絞り込む (1件のみ該当).
QueryAdmin(). // グループの管理者: Dan.
QueryFriends(). // Danの友人: [Ariel].
QueryPets(). // 彼らのペット達: [Pedro, Xabi].
QueryFriends(). // Pedroの友達: [Coco], Xabiの友達: [].
QueryOwner(). // Cocoの飼い主: Alex.
Only(ctx) // クエリでは1つのエンティティのみが返されることを期待する
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
}
次のようなトラバーサルはどうでしょうか?
あるグループの管理者
(エッジ) の友人
(エッジ) である飼い主
(エッジ
) を持つすべてのペット(エンティティ) を取得したいです。
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
}
完全なサンプルは、GitHubにあります。