查询和更新

搭建好项目开发环境后,我们准备创建我们的待办事项列表并进行查询。

创建待办事项

我们先在可测试示例中创建一个 Todo。 我们将以下代码添加到 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. }

执行 go test,它应该是能通过测试的。

添加字段到表结构

正如你看到的,我们的 Todo 只有一个 ID 字段,什么事也做不了。 让我们来改进它,在 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. }

添加完这些字段后,我们需要像之前一样执行代码生成:

  1. go generate ./ent

你可能注意到了,除了 text 字段,其他字段在创建时都有一个默认值,唯独它必须由用户提供。 让我们修改 example_test.go 来适配刚刚的变动:

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

很好! 我们在数据库中成功创建了一张表,包含了 5 列 (id, text, created_at, status, priority),并且通过插入了两行数据到表中;即我们创建了两个任务到我们的 Todo list 中。

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