Skip to content

Commit

Permalink
Nested filters (#6095)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmatown authored Aug 12, 2021
1 parent 0dcb1c9 commit 272b97b
Show file tree
Hide file tree
Showing 104 changed files with 4,705 additions and 2,267 deletions.
17 changes: 17 additions & 0 deletions .changeset/funny-dots-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@keystone-next/fields': major
'@keystone-next/fields-document': major
'@keystone-next/keystone': major
'@keystone-next/types': major
---

Updated filters to be nested instead of flattened and add top-level `NOT` operator. See the [Query Filter API docs](https://keystonejs.com/docs/apis/filters) and the upgrade guide for more information.

```graphql
query {
posts(where: { title: { contains: "Something" } }) {
title
content
}
}
```
2 changes: 2 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,5 @@ jobs:
run: yarn lint:markdown
- name: Example schemas
run: yarn lint:examples
- name: Prisma Filters
run: yarn lint:filters
149 changes: 71 additions & 78 deletions docs/pages/docs/apis/filters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,98 +6,92 @@ Each field type provides its own set of filters which can be used with [queries]
This page lists all the filters available for each field type.
For more details on how to use filters in queries please consult to the [GraphQL Queries - Filters](../guides/filters) guide.

Keystone filters are typically named after the field they are filtering. For example, a `text` field called `foo` would have filters named `foo_starts_with`, `foo_contains`, etc.
In all the examples below we will use a field named `foo` as the base of the filter names.

## Scalar types

### checkbox

| **Filter name** | **Type** | **Description** |
| --------------- | --------- | --------------- |
| `foo` | `Boolean` | Equals |
| `foo_not` | `Boolean` | Does not equal |
| **Filter name** | **Type** | **Description** |
| --------------- | ----------------------- | ------------------------------- |
| `equals` | `Boolean` | Equals |
| `not` | `BooleanNullableFilter` | Does not match the inner filter |

### integer

| **Filter name** | **Type** | **Description** |
| --------------- | -------- | --------------------- |
| `foo` | `Int` | Equals |
| `foo_not` | `Int` | Does not equal |
| `foo_lt` | `Int` | Less than |
| `foo_lte` | `Int` | Less than or equal |
| `foo_gt` | `Int` | Greater than |
| `foo_gte` | `Int` | Greater than or equal |
| `foo_in` | `[Int]` | Is in the array |
| `foo_not_in` | `[Int]` | Is not in the array |
| **Filter name** | **Type** | **Description** |
| --------------- | ------------------- | ------------------------------- |
| `equals` | `Int` | Equals |
| `lt` | `Int` | Less than |
| `lte` | `Int` | Less than or equal |
| `gt` | `Int` | Greater than |
| `gte` | `Int` | Greater than or equal |
| `in` | `[Int!]` | Is in the array |
| `notIn` | `[Int!]` | Is not in the array |
| `not` | `IntNullableFilter` | Does not match the inner filter |

### json

The `json` field type does not support filters.

### float

| **Filter name** | **Type** | **Description** |
| --------------- | --------- | --------------------- |
| `foo` | `Float` | Equals |
| `foo_not` | `Float` | Does not equal |
| `foo_lt` | `Float` | Less than |
| `foo_lte` | `Float` | Less than or equal |
| `foo_gt` | `Float` | Greater than |
| `foo_gte` | `Float` | Greater than or equal |
| `foo_in` | `[Float]` | Is in the array |
| `foo_not_in` | `[Float]` | Is not in the array |
| **Filter name** | **Type** | **Description** |
| --------------- | --------------------- | ------------------------------- |
| `equals` | `Float` | Equals |
| `lt` | `Float` | Less than |
| `lte` | `Float` | Less than or equal |
| `gt` | `Float` | Greater than |
| `gte` | `Float` | Greater than or equal |
| `in` | `[Float!]` | Is in the array |
| `notIn` | `[Float!]` | Is not in the array |
| `not` | `FloatNullableFilter` | Does not match the inner filter |

### password

| **Filter name** | **Type** | **Description** |
| --------------- | --------- | --------------- |
| `foo_is_set` | `Boolean` | A value is set |
| `isSet` | `Boolean` | A value is set |

### select

| **Filter name** | **Type** | **Description** |
| --------------- | ---------- | ------------------- |
| `foo` | `String` | Equals |
| `foo_not` | `String` | Does not equal |
| `foo_in` | `[String]` | Is in the array |
| `foo_not_in` | `[String]` | Is not in the array |
- If the `dataType` is `string`(the default), the same filters as `text` will be available.
- If the `dataType` is `integer`, the same filters as `integer` will be available.
- If the `dataType` is `enum`, the following filters will be available:
| **Filter name** | **Type** | **Description** |
| --------------- | ---------- | ------------------- |
| `equals` | `ListKeyFieldKeyType` | Equals |
| `in` | `[ListKeyFieldKeyType!]` | Is in the array |
| `notIn` | `[ListKeyFieldKeyType!]` | Is not in the array |
| `not` | `ListKeyFieldKeyTypeNullableFilter` | Does not match the inner filter |

### text

| **Filter name** | **Type** | **Description** | ** Notes ** |
| ----------------------- | ---------- | -------------------------------------- | ----------------- |
| `foo` | `String` | Equals |
| `foo_not` | `String` | Does not equal |
| `foo_contains` | `String` | Contains |
| `foo_not_contains` | `String` | Does not contain |
| `foo_starts_with` | `String` | Starts with | `postgresql` only |
| `foo_not_starts_with` | `String` | Does not start with | `postgresql` only |
| `foo_ends_with` | `String` | Ends with | `postgresql` only |
| `foo_not_ends_with` | `String` | Does not end with | `postgresql` only |
| `foo_i` | `String` | Equals (case insensitive) | `postgresql` only |
| `foo_not_i` | `String` | Does not equal (case insensitive) | `postgresql` only |
| `foo_contains_i` | `String` | Contains (case insensitive) | `postgresql` only |
| `foo_not_contains_i` | `String` | Does not contain (case insensitive) | `postgresql` only |
| `foo_starts_with_i` | `String` | Starts with (case insensitive) | `postgresql` only |
| `foo_not_starts_with_i` | `String` | Does not start with (case insensitive) | `postgresql` only |
| `foo_ends_with_i` | `String` | Ends with (case insensitive) | `postgresql` only |
| `foo_not_ends_with_i` | `String` | Does not end with (case insensitive) | `postgresql` only |
| `foo_in` | `[String]` | Is in the array |
| `foo_not_in` | `[String]` | Is not in the array |
| **Filter name** | **Type** | **Description** | **Notes** |
| --------------- | ---------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `equals` | `String` | Equals |
| `lt` | `String` | Less than |
| `lte` | `String` | Less than or equal |
| `gt` | `String` | Greater than |
| `gte` | `String` | Greater than or equal |
| `contains` | `String` | Contains | Will follow the setting of the `mode` on `postgresql` and will be case insensitive but only for ASCII characters on `sqlite` |
| `startsWith` | `String` | Starts with | Will follow the setting of the `mode` on `postgresql` and will be case insensitive but only for ASCII characters on `sqlite` |
| `endsWith` | `String` | Ends with | Will follow the setting of the `mode` on `postgresql` and will be case insensitive but only for ASCII characters on `sqlite` |
| `in` | `[String!]` | Is in the array |
| `notIn` | `[String!]` | Is not in the array |
| `mode` | `QueryMode` (`default` or `insensitive`) | Whether the filters should be case insensitive or not | `postgresql` only |
| `not` | `NestedStringNullableFilter` | Does not match the inner filter |

### timestamp

| **Filter name** | **Type** | **Description** |
| --------------- | ---------- | --------------------- |
| `foo` | `String` | Equals |
| `foo_not` | `String` | Does not equal |
| `foo_lt` | `String` | Less than |
| `foo_lte` | `String` | Less than or equal |
| `foo_gt` | `String` | Greater than |
| `foo_gte` | `String` | Greater than or equal |
| `foo_in` | `[String]` | Is in the array |
| `foo_not_in` | `[String]` | Is not in the array |
| **Filter name** | **Type** | **Description** |
| --------------- | ------------------------ | ------------------------------- |
| `equals` | `String` | Equals |
| `lt` | `String` | Less than |
| `lte` | `String` | Less than or equal |
| `gt` | `String` | Greater than |
| `gte` | `String` | Greater than or equal |
| `in` | `[String!]` | Is in the array |
| `notIn` | `[String!]` | Is not in the array |
| `not` | `DateTimeNullableFilter` | Does not match the inner filter |

## Relationship type

Expand All @@ -107,31 +101,30 @@ The `json` field type does not support filters.

| **Filter name** | **Type** | **Description** |
| --------------- | --------------- | ------------------------------------------ |
| `foos_every` | `FooWhereInput` | All related items match the nested filter |
| `foos_some` | `FooWhereInput` | Some related items match the nested filter |
| `foos_none` | `FooWhereInput` | No related items match the nested filter |
| `every` | `FooWhereInput` | All related items match the nested filter |
| `some` | `FooWhereInput` | Some related items match the nested filter |
| `none` | `FooWhereInput` | No related items match the nested filter |

#### many: false

| **Filter name** | **Type** | **Description** |
| --------------- | --------------- | ------------------------- |
| `foo` | `FooWhereInput` | Matches the nested filter |
| `foo_is_null` | `Boolean` | Is `null` |

## Index types

### autoIncrement

| **Filter name** | **Type** | **Description** |
| --------------- | -------- | --------------------- |
| `id` | `ID` | Equals |
| `id_not` | `ID` | Does not equal |
| `id_lt` | `ID` | Less than |
| `id_lte` | `ID` | Less than or equal |
| `id_gt` | `ID` | Greater than |
| `id_gte` | `ID` | Greater than or equal |
| `id_in` | `[ID]` | Is in the array |
| `id_not_in` | `[ID]` | Is not in the array |
| **Filter name** | **Type** | **Description** |
| --------------- | ------------------- | ------------------------------- |
| `equals` | `Int` | Equals |
| `lt` | `Int` | Less than |
| `lte` | `Int` | Less than or equal |
| `gt` | `Int` | Greater than |
| `gte` | `Int` | Greater than or equal |
| `in` | `[Int!]` | Is in the array |
| `notIn` | `[Int!]` | Is not in the array |
| `not` | `IntNullableFilter` | Does not match the inner filter |

## Virtual type

Expand Down
130 changes: 74 additions & 56 deletions examples-staging/assets-cloud/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -58,40 +58,70 @@ type LocalFileFieldOutput implements FileFieldOutput {
input PostWhereInput {
AND: [PostWhereInput!]
OR: [PostWhereInput!]
id: ID
id_not: ID
id_lt: ID
id_lte: ID
id_gt: ID
id_gte: ID
id_in: [ID!]
id_not_in: [ID!]
title: String
title_not: String
title_contains: String
title_not_contains: String
title_in: [String]
title_not_in: [String]
status: PostStatusType
status_not: PostStatusType
status_in: [PostStatusType]
status_not_in: [PostStatusType]
content: String
content_not: String
content_contains: String
content_not_contains: String
content_in: [String]
content_not_in: [String]
publishDate: String
publishDate_not: String
publishDate_lt: String
publishDate_lte: String
publishDate_gt: String
publishDate_gte: String
publishDate_in: [String]
publishDate_not_in: [String]
NOT: [PostWhereInput!]
id: IDFilter
title: StringNullableFilter
status: PostStatusTypeNullableFilter
content: StringNullableFilter
publishDate: DateTimeNullableFilter
author: AuthorWhereInput
author_is_null: Boolean
}

input IDFilter {
equals: ID
in: [ID!]
notIn: [ID!]
lt: ID
lte: ID
gt: ID
gte: ID
not: IDFilter
}

input StringNullableFilter {
equals: String
in: [String!]
notIn: [String!]
lt: String
lte: String
gt: String
gte: String
contains: String
startsWith: String
endsWith: String
not: NestedStringNullableFilter
}

input NestedStringNullableFilter {
equals: String
in: [String!]
notIn: [String!]
lt: String
lte: String
gt: String
gte: String
contains: String
startsWith: String
endsWith: String
not: NestedStringNullableFilter
}

input PostStatusTypeNullableFilter {
equals: PostStatusType
in: [PostStatusType!]
notIn: [PostStatusType!]
not: PostStatusTypeNullableFilter
}

input DateTimeNullableFilter {
equals: String
in: [String!]
notIn: [String!]
lt: String
lte: String
gt: String
gte: String
not: DateTimeNullableFilter
}

input PostWhereUniqueInput {
Expand Down Expand Up @@ -178,29 +208,17 @@ type Author {
input AuthorWhereInput {
AND: [AuthorWhereInput!]
OR: [AuthorWhereInput!]
id: ID
id_not: ID
id_lt: ID
id_lte: ID
id_gt: ID
id_gte: ID
id_in: [ID!]
id_not_in: [ID!]
name: String
name_not: String
name_contains: String
name_not_contains: String
name_in: [String]
name_not_in: [String]
email: String
email_not: String
email_contains: String
email_not_contains: String
email_in: [String]
email_not_in: [String]
posts_every: PostWhereInput
posts_some: PostWhereInput
posts_none: PostWhereInput
NOT: [AuthorWhereInput!]
id: IDFilter
name: StringNullableFilter
email: StringNullableFilter
posts: PostManyRelationFilter
}

input PostManyRelationFilter {
every: PostWhereInput
some: PostWhereInput
none: PostWhereInput
}

input AuthorWhereUniqueInput {
Expand Down
Loading

0 comments on commit 272b97b

Please sign in to comment.