Skip to content

Commit

Permalink
Change isUnique: true to isIndexed: 'unique' in fields (#6437)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmatown authored Aug 31, 2021
1 parent c4dcdc1 commit af5e59b
Show file tree
Hide file tree
Showing 42 changed files with 113 additions and 135 deletions.
8 changes: 8 additions & 0 deletions .changeset/quiet-tables-hunt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@keystone-next/keystone': major
'@keystone-next/auth': patch
'@keystone-next/cloudinary': patch
'@keystone-next/fields-document': patch
---

Changed `isUnique: true` config in fields to `isIndexed: 'unique'`
4 changes: 2 additions & 2 deletions docs/pages/docs/apis/auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default withAuth(
lists: createSchema({
User: list({
fields: {
email: text({ isUnique: true }),
email: text({ isIndexed: 'unique', isFilterable: true }),
password: password(),
isAdmin: checkbox(),
},
Expand All @@ -62,7 +62,7 @@ The `createAuth` function must be used in conjunction with a [session](./session
The core functionality of the authentication system provides a GraphQL mutation to authenticate a user and then start a session, and a sign in page in the Admin UI.

- `listKey`: The name of the list to authenticate against.
- `identityField`: The name of the field to use as an identity field. This field must have `{ isUnique: true }` set.
- `identityField`: The name of the field to use as an identity field. This field must have `{ isIndexed: 'unique', isFilterable: true }` set.
- `secretField`: The name of the field to use as a secret. This field must be a `password()` field type.

```typescript
Expand Down
40 changes: 26 additions & 14 deletions docs/pages/docs/apis/fields.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,9 @@ Options:
`context` is a [`KeystoneContext`](./context) object.
`originalInput` is an object containing the data passed in to the `create` mutation.
- `isRequired` (default: `false`): If `true` then this field can never be set to `null`.
- `isUnique` (default: `false`): If `true` then all values of this field must be unique. This will also allow you to uniquely filter by this field in the GraphQL API.
- `isIndexed` (default: `false`)
- If `true` then this field will be indexed by the database.
- If `'unique'` then all values of this field must be unique.

```typescript
import { config, createSchema, list } from '@keystone-next/keystone';
Expand All @@ -188,7 +190,7 @@ export default config({
fieldName: integer({
defaultValue: 0,
isRequired: true,
isUnique: true,
isIndexed: 'unique',
}),
/* ... */
},
Expand Down Expand Up @@ -237,7 +239,9 @@ Options:
`context` is a [`KeystoneContext`](./context) object.
`originalInput` is an object containing the data passed in to the `create` mutation.
- `isRequired` (default: `false`): If `true` then this field can never be set to `null`.
- `isUnique` (default: `false`): If `true` then all values of this field must be unique.
- `isIndexed` (default: `false`)
- If `true` then this field will be indexed by the database.
- If `'unique'` then all values of this field must be unique.

```typescript
import { config, createSchema, list } from '@keystone-next/keystone';
Expand All @@ -250,7 +254,7 @@ export default config({
fieldName: float({
defaultValue: 3.14159,
isRequired: true,
isUnique: true,
isIndexed: 'unique',
}),
/* ... */
},
Expand All @@ -274,7 +278,9 @@ Options:
- `precision` (default: `18`): Maximum number of digits that are present in the number.
- `scale` (default: `4`): Maximum number of decimal places.
- `isRequired` (default: `false`): If `true` then this field can never be set to `null`.
- `isUnique` (default: `false`): If `true` then all values of this field must be unique.
- `isIndexed` (default: `false`)
- If `true` then this field will be indexed by the database.
- If `'unique'` then all values of this field must be unique.

```typescript
import { config, createSchema, list } from '@keystone-next/keystone';
Expand All @@ -289,7 +295,7 @@ export default config({
precision: 12,
scale: 3,
isRequired: true,
isUnique: true,
isIndexed: 'unique',
}),
/* ... */
},
Expand Down Expand Up @@ -354,7 +360,9 @@ Options:
`context` is a [`KeystoneContext`](./context) object.
`originalInput` is an object containing the data passed in to the `create` mutation.
- `isRequired` (default: `false`): If `true` then this field can never be set to `null`.
- `isUnique` (default: `false`): If `true` then all values of this field must be unique.
- `isIndexed` (default: `false`)
- If `true` then this field will be indexed by the database.
- If `'unique'` then all values of this field must be unique.
- `ui` (default: `{ displayMode: 'select' }`): Configures the display mode of the field in the Admin UI.
Can be one of `['select', 'segmented-control']`.

Expand All @@ -374,7 +382,7 @@ export default config({
],
defaultValue: '...',
isRequired: true,
isUnique: true,
isIndexed: 'unique',
ui: { displayMode: 'select' },
}),
/* ... */
Expand All @@ -397,7 +405,9 @@ Options:
`context` is a [`KeystoneContext`](./context) object.
`originalInput` is an object containing the data passed in to the `create` mutation.
- `isRequired` (default: `false`): If `true` then this field can never be set to `null`.
- `isUnique` (default: `false`): If `true` then all values of this field must be unique. This will also allow you to uniquely filter by this field in the GraphQL API.
- `isIndexed` (default: `false`)
- If `true` then this field will be indexed by the database.
- If `'unique'` then all values of this field must be unique.
- `ui` (default: `{ displayMode: 'input' }`): Configures the display mode of the field in the Admin UI.
Can be one of `['input', 'textarea']`.

Expand All @@ -412,7 +422,7 @@ export default config({
fieldName: text({
defaultValue: '...',
isRequired: true,
isUnique: true,
isIndexed: 'unique',
ui: { displayMode: 'textarea' },
}),
/* ... */
Expand All @@ -436,7 +446,9 @@ Options:
`context` is a [`KeystoneContext`](./context) object.
`originalInput` is an object containing the data passed in to the `create` mutation.
- `isRequired` (default: `false`): If `true` then this field can never be set to `null`.
- `isUnique` (default: `false`): If `true` then all values of this field must be unique.
- `isIndexed` (default: `false`)
- If `true` then this field will be indexed by the database.
- If `'unique'` then all values of this field must be unique.

```typescript
import { config, createSchema, list } from '@keystone-next/keystone';
Expand All @@ -449,7 +461,7 @@ export default config({
fieldName: timestamp({
defaultValue: '1970-01-01T00:00:00.000Z',
isRequired: true,
isUnique: true,
isIndexed: 'unique',
}),
/* ... */
},
Expand Down Expand Up @@ -537,7 +549,7 @@ Options:

- `defaultValue`
- `isRequired`
- `isUnique`
- `isIndexed`

```typescript
import { config, createSchema, list } from '@keystone-next/keystone';
Expand All @@ -550,7 +562,7 @@ export default config({
fieldName: autoIncrement({
defaultValue: 0,
isRequired: true,
isUnique: true,
isIndexed: 'unique',
}),
/* ... */
},
Expand Down
6 changes: 2 additions & 4 deletions docs/pages/docs/guides/custom-fields.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,12 @@ export type MyIntFieldConfig<TGeneratedListTypes extends BaseGeneratedListTypes>
CommonFieldConfig<TGeneratedListTypes> & {
defaultValue?: FieldDefaultValue<number, TGeneratedListTypes>;
isRequired?: boolean;
isIndexed?: boolean;
isUnique?: boolean;
isIndexed?: boolean | 'unique';
};

export const myInt =
<TGeneratedListTypes extends BaseGeneratedListTypes>({
isIndexed,
isUnique,
isRequired,
defaultValue,
...config
Expand All @@ -56,7 +54,7 @@ export const myInt =
kind: 'scalar',
mode: 'optional',
scalar: 'Int',
index: isIndexed ? 'index' : isUnique ? 'unique' : undefined,
index: isIndexed === true ? 'index' : isIndexed || undefined,
})({
...config,
input: {
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/docs/guides/virtual-fields.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ To achieve this, rather than passing in `graphql.field({ ... })` as the `field`
The argument `lists` contains the type information for all of the Keystone lists.
In our case, we want the output type of the `Post` list, so we specify `type: lists.Post.types.output`.
```
```ts
export const lists = createSchema({
Post: list({
fields: {
Expand All @@ -274,7 +274,7 @@ export const lists = createSchema({
Author: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
posts: relationship({ ref: 'Post.author', many: true }),
latestPost: virtual({
field: lists =>
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ export const lists = createSchema({
Author: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
password: password(),
posts: relationship({ ref: 'Post.author', many: true }),
},
Expand Down
2 changes: 1 addition & 1 deletion examples-staging/assets-cloud/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const lists = createSchema({
Author: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
posts: relationship({ ref: 'Post.author', many: true }),
},
}),
Expand Down
2 changes: 1 addition & 1 deletion examples-staging/assets-local/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const lists = createSchema({
Author: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
posts: relationship({ ref: 'Post.author', many: true }),
},
}),
Expand Down
2 changes: 1 addition & 1 deletion examples-staging/auth/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const lists = createSchema({
// The user's name
name: text({ isRequired: true }),
// The user's email address, used as the identity field for auth
email: text({ isRequired: true, isUnique: true, isFilterable: true }),
email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }),
// The user's password, used as the secret field for auth
password: password({
access: {
Expand Down
2 changes: 1 addition & 1 deletion examples-staging/basic/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const lists = createSchema({
/** The user's first and last name. */
name: text({ isRequired: true }),
/** Email is used to log into the system. */
email: text({ isRequired: true, isUnique: true, isFilterable: true }),
email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }),
/** Avatar upload for the users profile, stored locally */
avatar: image(),
attachment: file(),
Expand Down
2 changes: 1 addition & 1 deletion examples-staging/ecommerce/schemas/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const User = list({
},
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true, isFilterable: true }),
email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }),
password: password(),
cart: relationship({
ref: 'CartItem.user',
Expand Down
2 changes: 1 addition & 1 deletion examples-staging/graphql-api-endpoint/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const lists = createSchema({
},
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true, isFilterable: true }),
email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }),
password: password(),
posts: relationship({ ref: 'Post.author', many: true }),
},
Expand Down
2 changes: 1 addition & 1 deletion examples-staging/roles/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export const lists = createSchema({
/* The name of the user */
name: text({ isRequired: true }),
/* The email of the user, used to sign in */
email: text({ isRequired: true, isUnique: true, isFilterable: true }),
email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }),
/* The password of the user */
password: password({
isRequired: true,
Expand Down
2 changes: 1 addition & 1 deletion examples/blog/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const lists = createSchema({
Author: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
posts: relationship({ ref: 'Post.author', many: true }),
noRead: text({ graphql: { omit: ['read'] } }),
noUpdate: text({ graphql: { omit: ['update'] } }),
Expand Down
2 changes: 1 addition & 1 deletion examples/custom-field/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const lists = createSchema({
Author: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
posts: relationship({ ref: 'Post.author', many: true }),
},
}),
Expand Down
19 changes: 2 additions & 17 deletions examples/custom-field/stars-field/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ export type StarsFieldConfig<TGeneratedListTypes extends BaseGeneratedListTypes>
CommonFieldConfig<TGeneratedListTypes> & {
defaultValue?: FieldDefaultValue<number, TGeneratedListTypes>;
isRequired?: boolean;
isUnique?: boolean;
isIndexed?: boolean;
isIndexed?: boolean | 'unique';
maxStars?: number;
};

export const stars =
<TGeneratedListTypes extends BaseGeneratedListTypes>({
isIndexed,
isUnique,
isRequired,
defaultValue,
maxStars = 5,
Expand All @@ -38,7 +36,7 @@ export const stars =
kind: 'scalar',
mode: 'optional',
scalar: 'Int',
index: getIndexType({ isIndexed, isUnique }),
index: isIndexed === true ? 'index' : isIndexed || undefined,
})({
// this passes through all of the common configuration like access control and etc.
...config,
Expand Down Expand Up @@ -104,16 +102,3 @@ export const stars =
defaultValue,
},
});

function getIndexType({
isIndexed,
isUnique,
}: {
isIndexed?: boolean;
isUnique?: boolean;
}): undefined | 'index' | 'unique' {
if (isUnique && isIndexed) {
throw new Error('Only one of isUnique and isIndexed can be passed to field types');
}
return isIndexed ? 'index' : isUnique ? 'unique' : undefined;
}
4 changes: 2 additions & 2 deletions examples/document-field/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const lists = createSchema({
Post: list({
fields: {
title: text({ isRequired: true }),
slug: text({ isRequired: true, isUnique: true }),
slug: text({ isRequired: true, isIndexed: 'unique' }),
status: select({
dataType: 'enum',
options: [
Expand Down Expand Up @@ -43,7 +43,7 @@ export const lists = createSchema({
Author: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
posts: relationship({ ref: 'Post.author', many: true }),
bio: document({
// We want to constrain the formatting in Author bios to a limited set of options.
Expand Down
2 changes: 1 addition & 1 deletion examples/extend-graphql-schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const lists = createSchema({
Author: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
posts: relationship({ ref: 'Post.author', many: true }),
},
}),
Expand Down
2 changes: 1 addition & 1 deletion examples/testing/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const lists = createSchema({
Person: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
password: password({ isRequired: true }),
tasks: relationship({ ref: 'Task.assignedTo', many: true }),
},
Expand Down
2 changes: 1 addition & 1 deletion examples/virtual-field/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const lists = createSchema({
Author: list({
fields: {
name: text({ isRequired: true }),
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique' }),
posts: relationship({ ref: 'Post.author', many: true }),
// A virtual field which returns a type derived from a Keystone list.
latestPost: virtual({
Expand Down
2 changes: 1 addition & 1 deletion examples/with-auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ We add two new fields, `email` and `password`, to the `Person` list.
These are used as our _identity_ and _secret_ fields for login.

```typescript
email: text({ isRequired: true, isUnique: true }),
email: text({ isRequired: true, isIndexed: 'unique', isFilterable: true }),
password: password({ isRequired: true }),
```

Expand Down
Loading

0 comments on commit af5e59b

Please sign in to comment.