Query and Mutation

After setting up our project, we’re ready to create our Todo list and query it.

Create a Todo

Let’s create a Todo in our testable example. We do it by adding the following code to example_test.go:

  1. func Example_Todo() {
  2. // ...
  3. task1, err := client.Todo.Create().Save(ctx)
  4. if err != nil {
  5. log.Fatalf("failed creating a todo: %v", err)
  6. }
  7. fmt.Println(task1)
  8. // Output:
  9. // Todo(id=1)
  10. }

Running go test should pass successfully.

Add Fields To The Schema

As you can see, our Todos are too boring as they contain only the ID field. Let’s improve this example by adding multiple fields to the schema in todo/ent/schema/todo.go:

  1. func (Todo) Fields() []ent.Field {
  2. return []ent.Field{
  3. field.Text("text").
  4. NotEmpty(),
  5. field.Time("created_at").
  6. Default(time.Now).
  7. Immutable(),
  8. field.Enum("status").
  9. NamedValues(
  10. "InProgress", "IN_PROGRESS",
  11. "Completed", "COMPLETED",
  12. ).
  13. Default("IN_PROGRESS"),
  14. field.Int("priority").
  15. Default(0),
  16. }
  17. }

After adding these fields, we need to run the code-generation as before:

  1. go generate ./ent

As you may notice, all fields have a default value on creation except the text field, which must be provided by the user. Let’s change our example_test.go to follow these changes:

  1. func Example_Todo() {
  2. // ...
  3. task1, err := client.Todo.Create().SetText("Add GraphQL Example").Save(ctx)
  4. if err != nil {
  5. log.Fatalf("failed creating a todo: %v", err)
  6. }
  7. fmt.Printf("%d: %q\n", task1.ID, task1.Text)
  8. task2, err := client.Todo.Create().SetText("Add Tracing Example").Save(ctx)
  9. if err != nil {
  10. log.Fatalf("failed creating a todo: %v", err)
  11. }
  12. fmt.Printf("%d: %q\n", task2.ID, task2.Text)
  13. // Output:
  14. // 1: "Add GraphQL Example"
  15. // 2: "Add Tracing Example"
  16. }

Wonderful! We created a schema in the database with 5 columns (id, text, created_at, status, priority) and created 2 items in our todo list, by inserting 2 rows to the table.

tutorial-todo-create

Add Edges To The Schema

Let’s say we want to design our todo list so that an item can depend on another item. Therefore, we’ll add a parent edge to each Todo item, to get the item it depends on, and a back-reference edge named children in order to get all items that depend on it.

Let’s change our schema again in todo/ent/schema/todo.go:

  1. func (Todo) Edges() []ent.Edge {
  2. return []ent.Edge{
  3. edge.To("parent", Todo.Type).
  4. Unique().
  5. From("children"),
  6. }
  7. }

After adding these edges, we need to run the code-generation as before:

  1. go generate ./ent

Connect 2 Todos

We continue our edges example, by updating the 2 todo items we just created. We define that item-2 (“Add Tracing Example”) depends on item-1 (“Add GraphQL Example”).

tutorial-todo-create

  1. func Example_Todo() {
  2. // ...
  3. if err := task2.Update().SetParent(task1).Exec(ctx); err != nil {
  4. log.Fatalf("failed connecting todo2 to its parent: %v", err)
  5. }
  6. // Output:
  7. // 1: "Add GraphQL Example"
  8. // 2: "Add Tracing Example"
  9. }

Query Todos

After connecting item-2 to item-1, we’re ready to start querying our todo list.

Query all todo items:

  1. func Example_Todo() {
  2. // ...
  3. // Query all todo items.
  4. items, err := client.Todo.Query().All(ctx)
  5. if err != nil {
  6. log.Fatalf("failed querying todos: %v", err)
  7. }
  8. for _, t := range items {
  9. fmt.Printf("%d: %q\n", t.ID, t.Text)
  10. }
  11. // Output:
  12. // 1: "Add GraphQL Example"
  13. // 2: "Add Tracing Example"
  14. }

Query all todo items that depend on other items:

  1. func Example_Todo() {
  2. // ...
  3. // Query all todo items that depend on other items.
  4. items, err := client.Todo.Query().Where(todo.HasParent()).All(ctx)
  5. if err != nil {
  6. log.Fatalf("failed querying todos: %v", err)
  7. }
  8. for _, t := range items {
  9. fmt.Printf("%d: %q\n", t.ID, t.Text)
  10. }
  11. // Output:
  12. // 2: "Add Tracing Example"
  13. }

Query all todo items that don’t depend on other items and have items that depend on them:

  1. func Example_Todo() {
  2. // ...
  3. // Query all todo items that don't depend on other items and have items that depend them.
  4. items, err := client.Todo.Query().
  5. Where(
  6. todo.Not(
  7. todo.HasParent(),
  8. ),
  9. todo.HasChildren(),
  10. ).
  11. All(ctx)
  12. if err != nil {
  13. log.Fatalf("failed querying todos: %v", err)
  14. }
  15. for _, t := range items {
  16. fmt.Printf("%d: %q\n", t.ID, t.Text)
  17. }
  18. // Output:
  19. // 1: "Add GraphQL Example"
  20. }

Query parent through its children:

  1. func Example_Todo() {
  2. // ...
  3. // Get a parent item through its children and expect the
  4. // query to return exactly one item.
  5. parent, err := client.Todo.Query(). // Query all todos.
  6. Where(todo.HasParent()). // Filter only those with parents.
  7. QueryParent(). // Continue traversals to the parents.
  8. Only(ctx) // Expect exactly one item.
  9. if err != nil {
  10. log.Fatalf("failed querying todos: %v", err)
  11. }
  12. fmt.Printf("%d: %q\n", parent.ID, parent.Text)
  13. // Output:
  14. // 1: "Add GraphQL Example"
  15. }