mirror of
https://github.com/ent/ent.git
synced 2026-04-28 05:30:56 +03:00
docs: various fixes to the graphql tutorial (#2965)
* doc/md: fix resolver diff and isolation example * doc/md: fix updateTodo input field * doc/md: add missing extension and fix paths Without entgql.WithSchemaGenerator entc.go fails to run. * doc/md: add file titles Note that the where:TodoWhereInput parameter is pre-filled in the generated ent.graphql file. * doc/md: add context to conjunction/negation example Only add for the first example to provide a lead to readers.
This commit is contained in:
@@ -47,14 +47,15 @@ go run ./cmd/todo/
|
||||
|
||||
### Configure Ent
|
||||
|
||||
Go to your `ent/entc.go` file, and add the 3 highlighted lines (extension options):
|
||||
Go to your `ent/entc.go` file, and add the 4 highlighted lines (extension options):
|
||||
|
||||
```go {3-5} title="ent/entc.go"
|
||||
```go {3-6} title="ent/entc.go"
|
||||
func main() {
|
||||
ex, err := entgql.NewExtension(
|
||||
entgql.WithSchemaGenerator(),
|
||||
entgql.WithWhereInputs(true),
|
||||
entgql.WithConfigPath("../gqlgen.yml"),
|
||||
entgql.WithSchemaPath("../ent.graphql"),
|
||||
entgql.WithConfigPath("gqlgen.yml"),
|
||||
entgql.WithSchemaPath("ent.graphql"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("creating entgql extension: %v", err)
|
||||
@@ -76,14 +77,14 @@ configures a path to a new, or an existing GraphQL schema to write the generated
|
||||
After changing the `entc.go` configuration, we're ready to execute the code generation as follows:
|
||||
|
||||
```console
|
||||
go generate ./ent/...
|
||||
go generate .
|
||||
```
|
||||
|
||||
Observe that Ent has generated `<T>WhereInput` for each type in your schema in a file named `ent/gql_where_input.go`. Ent
|
||||
also generates a GraphQL schema as well (`ent.graphql`), so you don't need to `autobind` them to `gqlgen` manually.
|
||||
For example:
|
||||
|
||||
```go title="ent/where_input.go"
|
||||
```go title="ent/gql_where_input.go"
|
||||
// TodoWhereInput represents a where input for filtering Todo queries.
|
||||
type TodoWhereInput struct {
|
||||
Not *TodoWhereInput `json:"not,omitempty"`
|
||||
@@ -157,7 +158,7 @@ schema:
|
||||
After running the code generation, we're ready to complete the integration and expose the filtering capabilities in GraphQL:
|
||||
|
||||
1\. Edit the GraphQL schema to accept the new filter types:
|
||||
```graphql {8}
|
||||
```graphql {8} title="ent.graphql"
|
||||
type Query {
|
||||
todos(
|
||||
after: Cursor,
|
||||
@@ -171,7 +172,7 @@ type Query {
|
||||
```
|
||||
|
||||
2\. Use the new filter types in GraphQL resolvers:
|
||||
```go {5}
|
||||
```go {5} title="ent.resolvers.go"
|
||||
func (r *queryResolver) Todos(ctx context.Context, after *ent.Cursor, first *int, before *ent.Cursor, last *int, orderBy *ent.TodoOrder, where *ent.TodoWhereInput) (*ent.TodoConnection, error) {
|
||||
return r.client.Todo.Query().
|
||||
Paginate(ctx, after, first, before, last,
|
||||
@@ -188,21 +189,33 @@ Go code.
|
||||
|
||||
#### Conjunction, disjunction and negation
|
||||
|
||||
The `Not`, `And` and `Or` operators can be added using the `not`, `and` and `or` fields. For example:
|
||||
The `Not`, `And` and `Or` operators can be added to the `where` clause using the `not`, `and` and `or` fields. For example:
|
||||
|
||||
```graphql
|
||||
{
|
||||
or: [
|
||||
{
|
||||
status: COMPLETED,
|
||||
},
|
||||
{
|
||||
not: {
|
||||
hasParent: true,
|
||||
status: IN_PROGRESS,
|
||||
}
|
||||
```graphql {3-15}
|
||||
query {
|
||||
todos(
|
||||
where: {
|
||||
or: [
|
||||
{
|
||||
status: COMPLETED
|
||||
},
|
||||
{
|
||||
not: {
|
||||
hasParent: true,
|
||||
status: IN_PROGRESS
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
text
|
||||
}
|
||||
cursor
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ The only thing left is to test the `UpdateTodo` resolver. Let's use it to update
|
||||
|
||||
```graphql
|
||||
mutation UpdateTodo {
|
||||
updateTodo(id: 2, input: {parent: 1}) {
|
||||
updateTodo(id: 2, input: {parentID: 1}) {
|
||||
id
|
||||
text
|
||||
createdAt
|
||||
|
||||
@@ -37,16 +37,12 @@ srv := handler.NewDefaultServer(todo.NewSchema(client))
|
||||
|
||||
2\. Then, in the GraphQL mutations, use the client from context as follows:
|
||||
```diff title="todo.resolvers.go"
|
||||
func (mutationResolver) CreateTodo(ctx context.Context, todo TodoInput) (*ent.Todo, error) {
|
||||
}
|
||||
+func (mutationResolver) CreateTodo(ctx context.Context, input ent.CreateTodoInput) (*ent.Todo, error) {
|
||||
+ client := ent.FromContext(ctx)
|
||||
+ return client.Todo.
|
||||
- return r.client.Todo.
|
||||
Create().
|
||||
SetText(todo.Text).
|
||||
SetStatus(todo.Status).
|
||||
SetNillablePriority(todo.Priority). // Set the "priority" field if provided.
|
||||
SetNillableParentID(todo.Parent). // Set the "parent_id" field if provided.
|
||||
Save(ctx)
|
||||
+ return client.Todo.Create().SetInput(input).Save(ctx)
|
||||
-func (r *mutationResolver) CreateTodo(ctx context.Context, input ent.CreateTodoInput) (*ent.Todo, error) {
|
||||
- return r.client.Todo.Create().SetInput(input).Save(ctx)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -54,17 +50,17 @@ func (mutationResolver) CreateTodo(ctx context.Context, todo TodoInput) (*ent.To
|
||||
|
||||
If you'd like to tweak the transaction's isolation level, you can do so by implementing your own `TxOpener`. For example:
|
||||
|
||||
```go
|
||||
```go title="cmd/todo/main.go"
|
||||
srv.Use(entgql.Transactioner{
|
||||
TxOpener: entgql.TxOpenerFunc(func(ctx context.Context) (context.Context, driver.Tx, error) {
|
||||
tx, err := client.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ctx = NewTxContext(ctx, tx)
|
||||
ctx = NewContext(ctx, tx.Client())
|
||||
ctx = ent.NewTxContext(ctx, tx)
|
||||
ctx = ent.NewContext(ctx, tx.Client())
|
||||
return ctx, tx, nil
|
||||
})
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user