Skip to content

Commit

Permalink
Enhance initial-data tutorials with createItems
Browse files Browse the repository at this point in the history
- add seeding tutorials
- remove relationship-utils module
- remove leftover `createItem` usage in the docs
  • Loading branch information
singhArmani committed Jul 30, 2020
1 parent 5ee1392 commit 9cfd5a4
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 246 deletions.
4 changes: 2 additions & 2 deletions .changeset/hot-olives-reply.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
'@keystonejs/keystone': major
---

Removed the `keystone.createItems` method. This has been replaced with the `createItems` function in `@keystonejs/server-side-graphql-client`.
Removed the `keystone.createItems` and `keystone.createItem` method. This has been replaced with the corresponding `createItems` and `createItem` function in `@keystonejs/server-side-graphql-client`.

If you have examples like:

Expand All @@ -21,4 +21,4 @@ createItems({
listName: 'User',
items: [{ data: { name: 'Ticiana' } }, {data: { name: 'Lauren' } }]
})
```
```
216 changes: 216 additions & 0 deletions docs/tutorials/initial-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ yarn add @keystonejs/app-graphql
yarn add @keystonejs/fields
yarn add @keystonejs/app-admin-ui
yarn add @keystonejs/auth-password
yarn add @keystonejs/server-side-graphql-client
```

### Preparation
Expand Down Expand Up @@ -74,3 +75,218 @@ module.exports = {
```

> **Tip:** A similar setup can be achieved by running the Keystone CLI `yarn create keystone-app` and selecting `Starter (Users + Authentication)`. This starter project has a `User` list, `PasswordAuthStrategy` and seeding of the database already configured. For now, we will proceed manually.
## Creating items

The [`createItems`](https://www.keystonejs.com/keystonejs/server-side-graphql-client/#createitems) utility function requires a config object argument. It has the following `required` keys:

- `keystone`: a Keystone instance
- `listKey`: the Keystone list name
- `items`: the array of objects to be created.


```javascript
createItems({
keystone,
listKey: 'User',
items: [
{ data: { name: 'John Duck', email: '[email protected]', password: 'dolphins' } },
{ data: { name: 'Barry', email: '[email protected]', password: 'dolphins' } },
],
});
```

**Note**: The format of the objects in the `items` array must align with the schema setup of the corresponding list name.
As an example in our schema, the `email` field has `isUnique:true` constraint, therefore it would not be possible for the above code to generate users with exactly same email.

Example on how to `seed` the data upon database connection:

```javascript
const keystone = new Keystone({
adapter: new MongooseAdapter(),
onConnect: async keystone => {
await createItems({
keystone,
listKey: 'User',
items: [
{ data: { name: 'John Duck', email: '[email protected]', password: 'dolphins' } },
{ data: { name: 'Barry', email: '[email protected]', password: 'dolphins' } },
],
});
},
});
```

Start the application and visit the Admin UI, two users are available on startup.

> **Note:** In this example the same two users would be generated _every_ startup. Since email should be unique, this will cause a duplicate error to show up. To avoid this, clear the database before starting Keystone.
## Relationships

The `items` in the `createItems` config object has the data type of GraphQL `[listKey]sCreateInput`. In our example, it's the `UsersCreateInput` which keystone created for us as part of the schema.

Consequently, while seeding it's possible to create relationships between items using keystone `connect` [nested mutations](https://www.keystonejs.com/keystonejs/fields/src/types/relationship/#nested-mutations).

### Single relationships

Add the `Relationship` field to the imports:

```javascript
const { Text, Checkbox, Password, Relationship } = require('@keystonejs/fields');
```

Create a list with a relationship to another list:

```javascript
keystone.createList('Post', {
fields: {
title: {
type: Text,
},
author: {
type: Relationship,
ref: 'User',
},
},
});
```

As part of `connect` nested mutation, we need to provide the id of the item for which the single relationship is required. This implies that we need to extract the id of the previously created items.

Example on how to seed an item with a relationship using `connect` nested mutation:

```javascript
await createItems({
keystone,
listKey: 'Post',
items: [
{data: {
title: 'Hello World',
author: {
// Extracting the id from `users` array
connect: { id: users.find(user => user.name === 'John Duck').id },
},
}
},
],
},
})
```

The full example:

```javascript
const keystone = new Keystone({
adapter: new MongooseAdapter(),
onConnect: async keystone => {

// 1. Insert the user list first as it has no associated relationship.
const users = await createItems({
keystone,
listKey: 'User',
items: [
{data: { name: 'John Duck', email: '[email protected]', password: 'dolphins' } },
{data: { name: 'Barry', email: '[email protected]', password: 'dolphins' } },
],
});

// 2. Insert `Post` data, with the required relationships, via `connect` nested mutation.
await createItems({
keystone,
listKey: 'Post',
items: [
{data: {
title: 'Hello World',
author: {
// Extracting the id of the User list item
connect: { id: users.find(user => user.name === 'John Duck').id },
},
}
},
],
},
});
```
Clear the database, then start Keystone and visit the Admin UI to see that two users are generated and one post is generated. The post has an `author` named `John Duck`. In the database `author` will be the ID of the user with name John Duck
### Many relationships
A user can have many posts, add the `to-many` relationship field `posts` to the `User`:
```javascript
keystone.createList('User', {
fields: {
name: { type: Text },
email: {
type: Text,
isUnique: true,
},
isAdmin: { type: Checkbox },
password: {
type: Password,
},
posts: {
type: Relationship,
ref: 'Post',
many: true,
},
},
});
```
Following the same pattern as discussed above, we can easily establish a `to-many` relationship via `connect` [nested mutations](https://www.keystonejs.com/keystonejs/fields/src/types/relationship/#nested-mutations) approach. Instead of passing a single item id, we are required to pass an array of item ids.
**Note**: We need to create posts first as it has no relationship, and we require the post ids to create `to-many` relationship with user items.
To associate all the posts where `title` contains the word `React`:
In action:
```javascript
const keystone = new Keystone({
adapter: new MongooseAdapter(),
onConnect: async keystone => {
// 1. Create posts first as we need generated ids to establish relationship with user items.
const posts = await createItems({
keystone,
listKey: 'Post',
items: [
{ data: { title: 'Hello Everyone' } },
{ data: { title: 'Talking about React' } },
{ data: { title: 'React is the Best' } },
{ data: { title: 'Keystone Rocks' } },
],
});

// 2. Insert User data with required relationship via nested mutations. `connect` requires an array of post item ids.
await createItems({
keystone,
listKey: 'User',
items: [
{
data: {
name: 'John Duck',
email: '[email protected]',
password: 'dolphins',
posts: {
// Filtering list of items where title contains the word `React`
connect: post.filter(p => /\bReact\b/i.test(p.title)).map(i => ({ id: i.id })),
},
},
{
data: {
name: 'Barry',
email: '[email protected]',
password: 'dolphins',
isAdmin: true,
},
},
],
});
},
});
```
Clear the database, start the Keystone application and visit the Admin UI. Take a look at the user `John Duck`, he has two posts associated with him (there were two posts with the word `React` in the `title`).
If you want to explore other utility functions for `CRUD` operations, please refer to [server-side GraphQL client](https://www.keystonejs.com/keystonejs/server-side-graphql-client) API for more details.
1 change: 0 additions & 1 deletion packages/keystone/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ Please note: We use these internally but provide no support or assurance if used
| `dumpSchema` | Dump schema to a string. |
| `getTypeDefs` | Remove from user documentation? |
| `getResolvers` | Remove from user documentation? |
| `createItem` | Remove from user documentation? |
| `getAdminMeta` | Remove from user documentation? |
-->

Expand Down
Loading

0 comments on commit 9cfd5a4

Please sign in to comment.