---
id: tutorial-todo-gql-filter-input
title: Filter Inputs
sidebar_label: Filter Inputs
---

In this section, we continue the [GraphQL example](tutorial-todo-gql.md) by explaining how to generate
type-safe GraphQL filters (i.e. `Where` predicates) from our `ent/schema`, and allow users to seamlessly
map GraphQL queries to Ent queries. For example, the following GraphQL query, maps to the Ent query below:

**GraphQL**

```graphql
{
  hasParent: true,
  hasChildrenWith: {
    status: IN_PROGRESS,
  }
}
```

**Ent**

```go
client.Todo.
    Query().
    Where(
        todo.HasParent(),
        todo.HasChildrenWith(
            todo.StatusEQ(todo.StatusInProgress),
        ),
    ).
    All(ctx)
```

#### Clone the code (optional)

The code for this tutorial is available under [github.com/a8m/ent-graphql-example](https://github.com/a8m/ent-graphql-example),
and tagged (using Git) in each step. If you want to skip the basic setup and start with the initial version of the GraphQL
server, you can clone the repository and run the program as follows:

```console
git clone git@github.com:a8m/ent-graphql-example.git
cd ent-graphql-example 
go run ./cmd/todo/
```

### Configure Ent

Go to your `ent/entc.go` file, and add the 3 highlighted lines (extension options):

```go {3-5} title="ent/entc.go"
func main() {
	ex, err := entgql.NewExtension(
		entgql.WithWhereFilters(true),
		entgql.WithConfigPath("../gqlgen.yml"),
		entgql.WithSchemaPath("../ent.graphql"),
	)
	if err != nil {
		log.Fatalf("creating entgql extension: %v", err)
	}
	opts := []entc.Option{
		entc.Extensions(ex),
		entc.TemplateDir("./template"),
	}
	if err := entc.Generate("./schema", &gen.Config{}, opts...); err != nil {
		log.Fatalf("running ent codegen: %v", err)
	}
} 
```

The `WithWhereFilters` option enables the filter generation, the `WithConfigPath` configures the path to the `gqlgen`
config file, which allows the extension to more accurately map GraphQL to Ent types. The last option `WithSchemaPath`,
configures a path to a new, or an existing GraphQL schema to write the generated filters to.

After changing the `entc.go` configuration, we're ready to execute the code generation as follows:

```console
go generate ./ent/...
```

Observe that Ent has generated `<T>WhereInput` for each type in your schema in a file named `ent/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"
// TodoWhereInput represents a where input for filtering Todo queries.
type TodoWhereInput struct {
	Not *TodoWhereInput   `json:"not,omitempty"`
	Or  []*TodoWhereInput `json:"or,omitempty"`
	And []*TodoWhereInput `json:"and,omitempty"`

	// "created_at" field predicates.
	CreatedAt      *time.Time  `json:"createdAt,omitempty"`
	CreatedAtNEQ   *time.Time  `json:"createdAtNEQ,omitempty"`
	CreatedAtIn    []time.Time `json:"createdAtIn,omitempty"`
	CreatedAtNotIn []time.Time `json:"createdAtNotIn,omitempty"`
	CreatedAtGT    *time.Time  `json:"createdAtGT,omitempty"`
	CreatedAtGTE   *time.Time  `json:"createdAtGTE,omitempty"`
	CreatedAtLT    *time.Time  `json:"createdAtLT,omitempty"`
	CreatedAtLTE   *time.Time  `json:"createdAtLTE,omitempty"`

	// "status" field predicates.
	Status      *todo.Status  `json:"status,omitempty"`
	StatusNEQ   *todo.Status  `json:"statusNEQ,omitempty"`
	StatusIn    []todo.Status `json:"statusIn,omitempty"`
	StatusNotIn []todo.Status `json:"statusNotIn,omitempty"`

    // .. truncated ..
}
```

```graphql title="ent.graphql"
"""
TodoWhereInput is used for filtering Todo objects.
Input was generated by ent.
"""
input TodoWhereInput {
  not: TodoWhereInput
  and: [TodoWhereInput!]
  or: [TodoWhereInput!]
  
  """created_at field predicates"""
  createdAt: Time
  createdAtNEQ: Time
  createdAtIn: [Time!]
  createdAtNotIn: [Time!]
  createdAtGT: Time
  createdAtGTE: Time
  createdAtLT: Time
  createdAtLTE: Time
  
  """status field predicates"""
  status: Status
  statusNEQ: Status
  statusIn: [Status!]
  statusNotIn: [Status!]
    
  # .. truncated ..
}
```

:::info
If your project contains more than 1 GraphQL schema (e.g. `todo.graphql` and `ent.graphql`), you should configure
`gqlgen.yml` file as follows:

```yaml
schema:
  - todo.graphql
  # The ent.graphql schema was generated by Ent.
  - ent.graphql
```
:::

### Configure GQL

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} 
type Query {
  todos(
    after: Cursor,
    first: Int,
    before: Cursor,
    last: Int,
    orderBy: TodoOrder,
    where: TodoWhereInput,
  ): TodoConnection
}
```

2\. Use the new filter types in GraphQL resolvers:
```go {5}
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,
			ent.WithTodoOrder(orderBy),
			ent.WithTodoFilter(where.Filter),
		)
}
```

### Execute Queries

As mentioned above, with the new GraphQL filter types, you can express the same Ent filters you use in your
Go code.

#### Conjunction, disjunction and negation

The `Not`, `And` and `Or` operators can be added using the `not`, `and` and `or` fields. For example:

```graphql
{
  or: [
    {
      status: COMPLETED,
    },
    {
      not: {
        hasParent: true,
        status: IN_PROGRESS,
      }
    }
  ]
}
```

When multiple filter fields are provided, Ent implicitly adds the `And` operator.

```graphql
{
  status: COMPLETED,
  textHasPrefix: "GraphQL",
}
```
The above query will produce the following Ent query:

```go
client.Todo.
	Query().
	Where(
		todo.And(
			todo.StatusEQ(todo.StatusCompleted),
			todo.TextHasPrefix("GraphQL"),
		)
	).
	All(ctx)
```

#### Edge/Relation filters

[Edge (relation) predicates](https://entgo.io/docs/predicates#edge-predicates) can be expressed in the same Ent syntax:

```graphql
{
  hasParent: true,
  hasChildrenWith: {
    status: IN_PROGRESS,
  }
}
```

The above query will produce the following Ent query:

```go
client.Todo.
	Query().
	Where(
		todo.HasParent(),
		todo.HasChildrenWith(
			todo.StatusEQ(todo.StatusInProgress),
		),
	).
	All(ctx)
```

---

Well done! As you can see, by changing a few lines of code our application now exposes a type-safe GraphQL filters
that automatically map to Ent queries. Have questions? Need help with getting started? Feel free to join our [Slack channel](https://entgo.io/docs/slack).
