クエリとミューテーション
プロジェクトをセットアップし、Todo リストを作成してクエリする準備が整いました。
Todoを作成する
Testable ExamplesとしてTodoプログラムを作ってみましょう。 以下のコードを example_test.go
に追加して実行します:
func Example_Todo() {
// ...
task1, err := client.Todo.Create().Save(ctx)
if err != nil {
log.Fatalf("failed creating a todo: %v", err)
}
fmt.Println(task1)
// Output:
// Todo(id=1)
}
go test
を実行すると、テストは成功します。
スキーマにフィールドを追加する
見てのとおり、私たちのTodoは ID
フィールドしか持っておらず、退屈すぎます。 より良い例にするために、todo/ent/schema/todo.go
のスキーマへフィールドをいくつか追加してみましょう。
func (Todo) Fields() []ent.Field {
return []ent.Field{
field.Text("text").
NotEmpty(),
field.Time("created_at").
Default(time.Now).
Immutable(),
field.Enum("status").
NamedValues(
"InProgress", "IN_PROGRESS",
"Completed", "COMPLETED",
).
Default("IN_PROGRESS"),
field.Int("priority").
Default(0),
}
}
これらのフィールドを追加した後、またコード生成を実行する必要があります。
go generate ./ent
気づいたかもしれませんが、text
フィールド以外のすべてのフィールドは、作成時にデフォルト値が設定されており、ユーザーが提供する必要があります。 example_test.go
をこれらの変更に合わせて変更しましょう。
func Example_Todo() {
// ...
task1, err := client.Todo.Create().SetText("Add GraphQL Example").Save(ctx)
if err != nil {
log.Fatalf("failed creating a todo: %v", err)
}
fmt.Printf("%d: %q\n", task1.ID, task1.Text)
task2, err := client.Todo.Create().SetText("Add Tracing Example").Save(ctx)
if err != nil {
log.Fatalf("failed creating a todo: %v", err)
}
fmt.Printf("%d: %q\n", task2.ID, task2.Text)
// Output:
// 1: "Add GraphQL Example"
// 2: "Add Tracing Example"
}
すばらしい! データベースに、5つのカラム(id
、text
、created_at
、status
、priority
) を持つスキーマが作成されました。 そして、テーブルに2つのレコードが挿入され、Todoリストに2つのアイテムを作成することに成功しました。
スキーマにエッジを追加する
アイテムが他のアイテムに依存できるように、Todoリストを再設計しましょう。 そこで、依存するアイテムを取得するために、各Todoアイテムにparent
というエッジを追加し、それに依存するすべてのアイテムを取得するためにchildren
という名前の後方参照エッジを追加することにします。
todo/ent/schema/todo.go
でスキーマを再度変更しましょう:
func (Todo) Edges() []ent.Edge {
return []ent.Edge{
edge.To("parent", Todo.Type).
Unique().
From("children"),
}
}
これらのエッジを追加した後、またコード生成を実行する必要があります。
go generate ./ent
2つのTodoをつなげる
先ほど作成した2つのTODOを更新することで、エッジの例を続行します。 Item-2("Add Tracing Example") は、 item-1("Add GraphQL Example") に依存していると定義します。
func Example_Todo() {
// ...
if err := task2.Update().SetParent(task1).Exec(ctx); err != nil {
log.Fatalf("failed connecting todo2 to its parent: %v", err)
}
// Output:
// 1: "Add GraphQL Example"
// 2: "Add Tracing Example"
}
Todoをクエリする
Item-2をItem-1につなげたなら、Todoリストのクエリを開始できます。
すべてのTODOを取得する
func Example_Todo() {
// ...
// すべてのtodoアイテムを取得する
items, err := client.Todo.Query().All(ctx)
if err != nil {
log.Fatalf("failed querying todos: %v", err)
}
for _, t := range items {
fmt.Printf("%d: %q\n", t.ID, t.Text)
}
// Output:
// 1: "Add GraphQL Example"
// 2: "Add Tracing Example"
}
ほかのTODOを親にもつTODOを取得する:
func Example_Todo() {
// ...
// 他のtodoアイテムを親にもつtodoアイテムを全て取得する
items, err := client.Todo.Query().Where(todo.HasParent()).All(ctx)
if err != nil {
log.Fatalf("failed querying todos: %v", err)
}
for _, t := range items {
fmt.Printf("%d: %q\n", t.ID, t.Text)
}
// Output:
// 2: "Add Tracing Example"
}
ほかのTODOを親に持たず、かつ、ほかのTODOを子に持つTODOを取得する
func Example_Todo() {
// ...
// 他のtodoアイテムに依存しておらず、依存しているtodoアイテムを持つすべてのtodoアイテムを取得する
items, err := client.Todo.Query().
Where(
todo.Not(
todo.HasParent(),
),
todo.HasChildren(),
).
All(ctx)
if err != nil {
log.Fatalf("failed querying todos: %v", err)
}
for _, t := range items {
fmt.Printf("%d: %q\n", t.ID, t.Text)
}
// Output:
// 1: "Add GraphQL Example"
}
子TODOを経由して親TODOを取得する
func Example_Todo() {
// ...
// 子TODOを通じて親TODOを取得し、
// クエリが正確に1つのTODOを返すことを期待します。
parent, err := client.Todo.Query(). // すべてのtodoアイテムを取得する
Where(todo.HasParent()). // 親todoアイテムを持つtodoアイテムのみにフィルタリング
QueryParent(). // 親todoアイテムについて走査を続ける
Only(ctx) // 1つのtodoアイテムのみ取得する
if err != nil {
log.Fatalf("failed querying todos: %v", err)
}
fmt.Printf("%d: %q\n", parent.ID, parent.Text)
// Output:
// 1: "Add GraphQL Example"
}