mirror of
https://github.com/ent/ent.git
synced 2026-04-28 13:40:56 +03:00
* WIP - migrating entgo.io to docosaurus v2 * organizing pages a bit to be better suited for v2 site structure * doc/website: finish migration to docusaurus v2 Co-authored-by: Rotem Tamir <rotemtamir@gmail.com>
215 lines
5.1 KiB
Markdown
Executable File
215 lines
5.1 KiB
Markdown
Executable File
---
|
||
id: tutorial-todo-crud
|
||
title: Query and Mutation
|
||
sidebar_label: 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`:
|
||
|
||
```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)
|
||
}
|
||
```
|
||
|
||
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`:
|
||
|
||
```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),
|
||
}
|
||
}
|
||
```
|
||
|
||
After adding these fields, we need to run the code-generation as before:
|
||
|
||
```console
|
||
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:
|
||
|
||
```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"
|
||
}
|
||
```
|
||
|
||
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.
|
||
|
||

|
||
|
||
## 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`:
|
||
|
||
```go
|
||
func (Todo) Edges() []ent.Edge {
|
||
return []ent.Edge{
|
||
edge.To("parent", Todo.Type).
|
||
Unique().
|
||
From("children"),
|
||
}
|
||
}
|
||
```
|
||
|
||
After adding these edges, we need to run the code-generation as before:
|
||
|
||
```console
|
||
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"*).
|
||
|
||

|
||
|
||
```go
|
||
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"
|
||
}
|
||
```
|
||
|
||
## Query Todos
|
||
|
||
After connecting item-2 to item-1, we're ready to start querying our todo list.
|
||
|
||
#### Query all todo items:
|
||
|
||
```go
|
||
func Example_Todo() {
|
||
// ...
|
||
|
||
// Query all todo items.
|
||
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"
|
||
}
|
||
```
|
||
|
||
#### Query all todo items that depend on other items:
|
||
|
||
```go
|
||
func Example_Todo() {
|
||
// ...
|
||
|
||
// Query all todo items that depend on other items.
|
||
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"
|
||
}
|
||
```
|
||
|
||
#### Query all todo items that don't depend on other items and have items that depend on them:
|
||
|
||
```go
|
||
func Example_Todo() {
|
||
// ...
|
||
|
||
// Query all todo items that don't depend on other items and have items that depend them.
|
||
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"
|
||
}
|
||
```
|
||
|
||
#### Query parent through its children:
|
||
|
||
```go
|
||
func Example_Todo() {
|
||
// ...
|
||
|
||
// Get a parent item through its children and expect the
|
||
// query to return exactly one item.
|
||
parent, err := client.Todo.Query(). // Query all todos.
|
||
Where(todo.HasParent()). // Filter only those with parents.
|
||
QueryParent(). // Continue traversals to the parents.
|
||
Only(ctx) // Expect exactly one item.
|
||
if err != nil {
|
||
log.Fatalf("failed querying todos: %v", err)
|
||
}
|
||
fmt.Printf("%d: %q\n", parent.ID, parent.Text)
|
||
// Output:
|
||
// 1: "Add GraphQL Example"
|
||
}
|
||
```
|