Skip to content

Commit

Permalink
add examples/versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
dcousens committed Aug 17, 2022
1 parent 7804bd5 commit 610ae59
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 0 deletions.
38 changes: 38 additions & 0 deletions examples/versioning/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## Optimistic Locking

This project implements a basic **Blog**, with `Posts` and `Authors`.

Use it as a starting place for learning how to use Keystone.

## Instructions

To run this project, clone the Keystone repository locally, run `yarn` at the root of this repository, then navigate to this directory and run:

```shell
yarn dev
```

This will start the Admin UI at [localhost:3000](http://localhost:3000).
You can use the Admin UI to create items in your database.

You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations.

Congratulations, you're now up and running with Keystone! 🚀

### Optional: add sample data

This example includes sample data. To add it to your database:

1. Ensure you’ve initialised your project with `yarn dev` at least once.
2. Run `yarn seed-data`. This will populate your database with sample content.
3. Run `yarn dev` again to startup Admin UI with sample data in place.

## Try it out in CodeSandbox 🧪

You can play with this example online in a web browser using the free [codesandbox.io](https://codesandbox.io/) service. To launch this example, open the URL <https://githubbox.com/keystonejs/keystone/tree/main/examples/blog>. You can also fork this sandbox to make your own changes.

## Next steps

Experiment with the code in this example to see how Keystone works, familiarise yourself with the Admin UI, and learn about the GraphQL Playground.

When you’ve got the hang of this base project, try a [feature project](../) to learn Keystone’s advanced features and take your knowledge to the next level.
31 changes: 31 additions & 0 deletions examples/versioning/keystone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { config } from '@keystone-6/core';
import { lists } from './schema';
import { Context } from '.keystone/types';

async function seed (context: Context) {
for (const data of [
{
title: 'The Adventures of Sherlock Holmes',
content:
'One night—it was on the 20th of March, 1888—I was returning from a journey to a patient (for I had now returned to civil practice), when my way led me through Baker-street. As I passed the well-remembered door, which must always be associated in my mind with my wooing, and with the dark incidents of the Study in Scarlet, I was seized with a keen desire to see Holmes again, and to know how he was employing his extraordinary powers. His rooms were brilliantly lit, and, even as I looked up, I saw his tall spare figure pass twice in a dark silhouette against the blind. He was pacing the room swiftly, eagerly, with his head sunk upon his chest and his hands clasped behind him. To me, who knew his every mood and habit, his attitude and manner told their own story. He was at work again. He had risen out of his drug-created dreams and was hot upon the scent of some new problem. I rang the bell, and was shown up to the chamber which had formerly been in part my own. ',
version: 1
},
] as const) {
await context.query.Post.createOne({
data
});
}
}

export default config({
db: {
provider: 'sqlite',
url: process.env.DATABASE_URL || 'file:./keystone-example.db',
async onConnect(context: Context) {
if (process.argv.includes('--seed-data')) {
await seed(context);
}
},
},
lists,
});
22 changes: 22 additions & 0 deletions examples/versioning/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@keystone-6/example-versioning",
"version": "0.0.1",
"private": true,
"license": "MIT",
"scripts": {
"dev": "keystone dev",
"start": "keystone start",
"build": "keystone build",
"seed-data": "keystone --seed-data"
},
"dependencies": {
"@keystone-6/core": "^2.0.0"
},
"devDependencies": {
"typescript": "^4.7.4"
},
"engines": {
"node": "^14.15 || ^16.13"
},
"repository": "https://github.com/keystonejs/keystone/tree/main/examples/versioning"
}
7 changes: 7 additions & 0 deletions examples/versioning/sandbox.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"template": "node",
"container": {
"startScript": "keystone dev",
"node": "14"
}
}
219 changes: 219 additions & 0 deletions examples/versioning/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
# This file is automatically generated by Keystone, do not modify it manually.
# Modify your Keystone config when you want to change this.

type Post {
id: ID!
title: String
content: String
version: Int
}

input PostWhereUniqueInput {
id: ID
}

input PostWhereInput {
AND: [PostWhereInput!]
OR: [PostWhereInput!]
NOT: [PostWhereInput!]
id: IDFilter
title: StringFilter
content: StringFilter
version: IntFilter
}

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

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

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

input IntFilter {
equals: Int
in: [Int!]
notIn: [Int!]
lt: Int
lte: Int
gt: Int
gte: Int
not: IntFilter
}

input PostOrderByInput {
id: OrderDirection
title: OrderDirection
content: OrderDirection
version: OrderDirection
}

enum OrderDirection {
asc
desc
}

input PostUpdateInput {
title: String
content: String
version: Int
}

input PostUpdateArgs {
where: PostWhereUniqueInput!
data: PostUpdateInput!
}

input PostCreateInput {
title: String
content: String
version: Int
}

"""
The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
"""
scalar JSON
@specifiedBy(
url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf"
)

type Mutation {
createPost(data: PostCreateInput!): Post
createPosts(data: [PostCreateInput!]!): [Post]
updatePost(where: PostWhereUniqueInput!, data: PostUpdateInput!): Post
updatePosts(data: [PostUpdateArgs!]!): [Post]
deletePost(where: PostWhereUniqueInput!): Post
deletePosts(where: [PostWhereUniqueInput!]!): [Post]
}

type Query {
posts(
where: PostWhereInput! = {}
orderBy: [PostOrderByInput!]! = []
take: Int
skip: Int! = 0
): [Post!]
post(where: PostWhereUniqueInput!): Post
postsCount(where: PostWhereInput! = {}): Int
keystone: KeystoneMeta!
}

type KeystoneMeta {
adminMeta: KeystoneAdminMeta!
}

type KeystoneAdminMeta {
enableSignout: Boolean!
enableSessionItem: Boolean!
lists: [KeystoneAdminUIListMeta!]!
list(key: String!): KeystoneAdminUIListMeta
}

type KeystoneAdminUIListMeta {
key: String!
itemQueryName: String!
listQueryName: String!
hideCreate: Boolean!
hideDelete: Boolean!
path: String!
label: String!
singular: String!
plural: String!
description: String
initialColumns: [String!]!
pageSize: Int!
labelField: String!
fields: [KeystoneAdminUIFieldMeta!]!
initialSort: KeystoneAdminUISort
isHidden: Boolean!
}

type KeystoneAdminUIFieldMeta {
path: String!
label: String!
description: String
isOrderable: Boolean!
isFilterable: Boolean!
fieldMeta: JSON
viewsIndex: Int!
customViewsIndex: Int
createView: KeystoneAdminUIFieldMetaCreateView!
listView: KeystoneAdminUIFieldMetaListView!
itemView(id: ID): KeystoneAdminUIFieldMetaItemView
search: QueryMode
}

type KeystoneAdminUIFieldMetaCreateView {
fieldMode: KeystoneAdminUIFieldMetaCreateViewFieldMode!
}

enum KeystoneAdminUIFieldMetaCreateViewFieldMode {
edit
hidden
}

type KeystoneAdminUIFieldMetaListView {
fieldMode: KeystoneAdminUIFieldMetaListViewFieldMode!
}

enum KeystoneAdminUIFieldMetaListViewFieldMode {
read
hidden
}

type KeystoneAdminUIFieldMetaItemView {
fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode
}

enum KeystoneAdminUIFieldMetaItemViewFieldMode {
edit
read
hidden
}

enum QueryMode {
default
insensitive
}

type KeystoneAdminUISort {
field: String!
direction: KeystoneAdminUISortDirection!
}

enum KeystoneAdminUISortDirection {
ASC
DESC
}
20 changes: 20 additions & 0 deletions examples/versioning/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This file is automatically generated by Keystone, do not modify it manually.
// Modify your Keystone config when you want to change this.

datasource sqlite {
url = env("DATABASE_URL")
shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
provider = "sqlite"
}

generator client {
provider = "prisma-client-js"
output = "node_modules/.prisma/client"
}

model Post {
id String @id @default(cuid())
title String @default("")
content String @default("")
version Int @default(0)
}
25 changes: 25 additions & 0 deletions examples/versioning/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { list } from '@keystone-6/core';
import { integer, text } from '@keystone-6/core/fields';
import { Lists } from '.keystone/types';

export const lists: Lists = {
Post: list({
fields: {
title: text({ validation: { isRequired: true } }),
content: text(),
version: integer({
defaultValue: 0,
validation: { isRequired: true },
db: { isNullable: false },
hooks: {
resolveInput: async ({ resolvedData, operation, item }) => {
if (operation === 'create') return resolvedData.version;
if (resolvedData.version !== item.version) throw new Error('Out of sync');

return item.version + 1;
}
},
})
},
}),
};

0 comments on commit 610ae59

Please sign in to comment.