This project demonstrates how to add virtual fields to a Keystone list It builds on the Blog starter project.
To run this project, clone the Keystone repository locally then navigate to this directory and run:
yarn dev
This will start the Admin UI at 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, which allows you to directly run GraphQL queries and mutations.
This project demonstrates how to use virtual fields.
It uses the graphql
export from @keystone-next/keystone
to define the GraphQL schema used by the virtual fields.
The isPublished
field shows how to use the virtual
field to return some derived data.
isPublished: virtual({
field: graphql.field({
type: graphql.Boolean,
resolve(item: any) {
return item.status === 'published';
},
}),
}),
The counts
field shows how to return a GraphQL object rather than a scalar from a virtual field.
counts: virtual({
field: graphql.field({
type: graphql.object<{ content: string }>()({
name: 'PostCounts',
fields: {
words: graphql.field({
type: graphql.Int,
resolve({ content }) {
return content.split(' ').length;
},
}),
sentences: graphql.field({
type: graphql.Int,
resolve({ content }) {
return content.split('.').length;
},
}),
paragraphs: graphql.field({
type: graphql.Int,
resolve({ content }) {
return content.split('\n\n').length;
},
}),
},
}),
resolve(item: any) {
return { content: item.content || '' };
},
}),
graphQLReturnFragment: '{ words sentences paragraphs }',
}),
The excerpt
field shows how to add GraphQL arguments to a virtual field.
excerpt: virtual({
field: graphql.field({
type: graphql.String,
args: {
length: graphql.arg({ type: graphql.nonNull(graphql.Int), defaultValue: 200 }),
},
resolve(item, { length }) {
if (!item.content) {
return null;
}
return (item.content as string).slice(0, length - 3) + '...';
},
}),
}),
The relatedPosts
field shows how to use the GraphQL types defined by a Keystone list.
relatedPosts: virtual({
field: lists =>
graphql.field({
type: graphql.list(graphql.nonNull(lists.Post.types.output)),
resolve(item, args, context) {
// this could have some logic to get posts that are actually related to this one somehow
// this is a just a naive "get the three latest posts that aren't this one"
return context.db.lists.Post.findMany({
take: 3,
where: { id_not: item.id, status: 'published' },
orderBy: [{ publishDate: 'desc' }],
});
},
}),
graphQLReturnFragment: '{ title }',
}),