メインコンテンツへスキップする

クエリとミューテーション

プロジェクトをセットアップし、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").
Values("in_progress", "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つのカラム(idtextcreated_atstatuspriority) を持つスキーマが作成されました。 そして、テーブルに2つのレコードが挿入され、Todoリストに2つのアイテムを作成することに成功しました。

tutorial-todo-create

スキーマにエッジを追加する

アイテムが他のアイテムに依存できるように、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") に依存していると定義します。

tutorial-todo-create

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"
}