feat: GraphQL version collection resolvers

This commit is contained in:
Dan Ribbens
2022-02-10 15:23:39 -05:00
parent ee58471aed
commit 7cfb2f7f02
13 changed files with 535 additions and 355 deletions

View File

@@ -11,10 +11,11 @@ import formatName from '../../graphql/utilities/formatName';
import buildPaginatedListType from '../../graphql/schema/buildPaginatedListType';
import { BaseFields } from './types';
import { getCollectionIDType } from '../../graphql/schema/buildMutationInputType';
import buildVersionWhereInputType from '../../graphql/schema/buildVersionWhereInputType';
function registerCollections(): void {
const {
// TODO: findVersions, findVersionByID, publishVersion
findVersions, findVersionByID, publishVersion,
create, find, findByID, deleteResolver, update,
} = this.graphQL.resolvers.collections;
@@ -180,6 +181,35 @@ function registerCollections(): void {
resolve: deleteResolver(collection),
};
if (collection.config.versions) {
collection.graphQL.versionType = this.buildVersionType(collection.graphQL.type);
this.Query.fields[`version${formatName(singularLabel)}`] = {
type: collection.graphQL.versionType,
args: {
id: { type: GraphQLString },
},
resolve: findVersionByID(collection),
};
this.Query.fields[`versions${pluralLabel}`] = {
type: buildPaginatedListType(`versions${formatName(pluralLabel)}`, collection.graphQL.versionType),
args: {
where: { type: buildVersionWhereInputType(singularLabel, collection.config) },
autosave: { type: GraphQLBoolean },
page: { type: GraphQLInt },
limit: { type: GraphQLInt },
sort: { type: GraphQLString },
},
resolve: findVersions(collection),
};
this.Mutation.fields[`restoreVersion${formatName(singularLabel)}`] = {
type: new GraphQLNonNull(GraphQLBoolean),
args: {
id: { type: GraphQLString },
},
resolve: publishVersion(collection),
};
}
if (collection.config.auth) {
collection.graphQL.JWT = this.buildObjectType(
formatName(`${slug}JWT`),

View File

@@ -0,0 +1,35 @@
/* eslint-disable no-param-reassign */
import { Response } from 'express';
import { Collection } from '../../config/types';
import { PayloadRequest } from '../../../express/types';
export type Resolver = (
_: unknown,
args: {
locale?: string
fallbackLocale?: string
},
context: {
req: PayloadRequest,
res: Response
}
) => Promise<Document>
export default function publishVersion(collection: Collection): Resolver {
async function resolver(_, args, context) {
if (args.locale) context.req.locale = args.locale;
if (args.fallbackLocale) context.req.fallbackLocale = args.fallbackLocale;
const options = {
collection,
id: args.id,
req: context.req,
};
await this.operations.collections.publishVersion(options);
return true;
}
const findVersionByIDResolver = resolver.bind(this);
return findVersionByIDResolver;
}

View File

@@ -185,7 +185,6 @@ async function create(this: Payload, incomingArgs: Arguments): Promise<Document>
}
let result: Document = doc.toJSON({ virtuals: true });
// TODO: default status to 'draft';
const verificationToken = result._verificationToken;
// custom id type reset

View File

@@ -16,6 +16,7 @@ import update from '../collections/graphql/resolvers/update';
import deleteResolver from '../collections/graphql/resolvers/delete';
import findVersions from '../collections/graphql/resolvers/findVersions';
import findVersionByID from '../collections/graphql/resolvers/findVersionByID';
import publishVersion from '../collections/graphql/resolvers/publishVersion';
import findOne from '../globals/graphql/resolvers/findOne';
import globalUpdate from '../globals/graphql/resolvers/update';
@@ -29,6 +30,7 @@ export type GraphQLResolvers = {
findVersions: typeof findVersions,
findByID: typeof findByID,
findVersionByID: typeof findVersionByID,
publishVersion: typeof publishVersion,
update: typeof update,
deleteResolver: typeof deleteResolver,
auth: {
@@ -59,6 +61,7 @@ function bindResolvers(ctx: Payload): void {
findVersions: findVersions.bind(ctx),
findByID: findByID.bind(ctx),
findVersionByID: findVersionByID.bind(ctx),
publishVersion: publishVersion.bind(ctx),
update: update.bind(ctx),
deleteResolver: deleteResolver.bind(ctx),
auth: {

View File

@@ -13,7 +13,8 @@ import initCollections from '../collections/graphql/init';
import initGlobals from '../globals/graphql/init';
import initPreferences from '../preferences/graphql/init';
import { GraphQLResolvers } from './bindResolvers';
import buildWhereInputType from './schema/buildWhereInputType';
import buildVersionType from './schema/buildVersionType';
import { buildWhereInputType } from './schema/buildWhereInputType';
import { SanitizedConfig } from '../config/types';
type GraphQLTypes = {
@@ -46,6 +47,8 @@ class InitializeGraphQL {
buildPoliciesType: typeof buildPoliciesType;
buildVersionType: typeof buildVersionType;
initCollections: typeof initCollections;
initGlobals: typeof initGlobals;
@@ -90,6 +93,7 @@ class InitializeGraphQL {
this.buildWhereInputType = buildWhereInputType;
this.buildObjectType = buildObjectType.bind(this);
this.buildPoliciesType = buildPoliciesType.bind(this);
this.buildVersionType = buildVersionType.bind(this);
this.initCollections = initCollections.bind(this);
this.initGlobals = initGlobals.bind(this);
this.initPreferences = initPreferences.bind(this);

View File

@@ -0,0 +1,34 @@
import {
GraphQLInputFieldConfigMap,
GraphQLInputObjectType,
GraphQLInt,
GraphQLList,
GraphQLString,
Thunk,
} from 'graphql';
const buildInputObject = (name: string, fieldTypes: Thunk<GraphQLInputFieldConfigMap>): GraphQLInputObjectType => {
return new GraphQLInputObjectType({
name: `${name}_where`,
fields: {
...fieldTypes,
OR: {
type: new GraphQLList(new GraphQLInputObjectType({
name: `${name}_where_or`,
fields: fieldTypes,
})),
},
AND: {
type: new GraphQLList(new GraphQLInputObjectType({
name: `${name}_where_and`,
fields: fieldTypes,
})),
},
page: { type: GraphQLInt },
limit: { type: GraphQLInt },
sort: { type: GraphQLString },
},
});
};
export default buildInputObject;

View File

@@ -0,0 +1,19 @@
import { GraphQLBoolean, GraphQLNonNull, GraphQLObjectType, GraphQLString } from 'graphql';
import { DateTimeResolver } from 'graphql-scalars';
import formatName from '../utilities/formatName';
const buildVersionType = (type: GraphQLObjectType): GraphQLObjectType => {
return new GraphQLObjectType({
name: formatName(`${type.name}Version`),
fields: {
id: { type: GraphQLString },
parent: { type: GraphQLString },
autosave: { type: GraphQLBoolean },
version: { type },
updatedAt: { type: new GraphQLNonNull(DateTimeResolver) },
createdAt: { type: new GraphQLNonNull(DateTimeResolver) },
},
});
};
export default buildVersionType;

View File

@@ -0,0 +1,47 @@
import {
GraphQLBoolean,
GraphQLInputObjectType,
GraphQLString,
} from 'graphql';
import { DateTimeResolver } from 'graphql-scalars';
import { GraphQLJSON } from 'graphql-type-json';
import formatName from '../utilities/formatName';
import withOperators from './withOperators';
import { FieldAffectingData } from '../../fields/config/types';
import buildInputObject from './buildInputObject';
import { operators } from './operators';
import { SanitizedCollectionConfig } from '../../collections/config/types';
import { recursivelyBuildNestedPaths } from './recursivelyBuildNestedPaths';
const buildVersionWhereInputType = (singularLabel: string, parentCollection: SanitizedCollectionConfig): GraphQLInputObjectType => {
const name = `version${formatName(singularLabel)}`;
const fieldTypes = {
id: { type: GraphQLString },
autosave: { type: GraphQLBoolean },
// TODO: test with custom id field types, may need to support number
updatedAt: { type: DateTimeResolver },
createdAt: { type: DateTimeResolver },
parent: {
type: withOperators(
{ name: 'parent' } as FieldAffectingData,
GraphQLJSON,
name,
[...operators.equality, ...operators.contains],
),
},
};
const versionFields = recursivelyBuildNestedPaths(name, {
name: 'version',
type: 'group',
fields: parentCollection.fields,
});
versionFields.forEach((versionField) => {
fieldTypes[versionField.key] = versionField.type;
});
return buildInputObject(name, fieldTypes);
};
export default buildVersionWhereInputType;

View File

@@ -1,46 +1,22 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable no-use-before-define */
import {
GraphQLBoolean,
GraphQLEnumType,
GraphQLFloat,
GraphQLInputObjectType,
GraphQLInt,
GraphQLList,
GraphQLString,
} from 'graphql';
import { GraphQLJSON } from 'graphql-type-json';
import { DateTimeResolver, EmailAddressResolver } from 'graphql-scalars';
import {
optionIsObject,
ArrayField,
CheckboxField,
CodeField,
DateField,
EmailField,
Field,
FieldWithSubFields,
GroupField,
NumberField,
RadioField,
RelationshipField,
RichTextField,
RowField,
SelectField,
TextareaField,
TextField,
UploadField,
PointField,
FieldAffectingData,
fieldAffectsData,
fieldHasSubFields,
fieldIsPresentationalOnly,
} from '../../fields/config/types';
import formatName from '../utilities/formatName';
import combineParentName from '../utilities/combineParentName';
import withOperators from './withOperators';
import { operators } from './operators';
import buildInputObject from './buildInputObject';
import { fieldToSchemaMap } from './fieldToSchemaMap';
// buildWhereInputType is similar to buildObjectType and operates
// on a field basis with a few distinct differences.
@@ -49,284 +25,13 @@ import withOperators from './withOperators';
// 2. Relationships, groups, repeaters and flex content are not
// directly searchable. Instead, we need to build a chained pathname
// using dot notation so Mongo can properly search nested paths.
const buildWhereInputType = (name: string, fields: Field[], parentName: string): GraphQLInputObjectType => {
export const buildWhereInputType = (name: string, fields: Field[], parentName: string): GraphQLInputObjectType => {
// This is the function that builds nested paths for all
// field types with nested paths.
const recursivelyBuildNestedPaths = (field: FieldWithSubFields & FieldAffectingData) => {
const nestedPaths = field.fields.reduce((nestedFields, nestedField) => {
if (!fieldIsPresentationalOnly(nestedField)) {
const getFieldSchema = fieldToSchemaMap[nestedField.type];
const nestedFieldName = fieldAffectsData(nestedField) ? `${field.name}__${nestedField.name}` : undefined;
if (getFieldSchema) {
const fieldSchema = getFieldSchema({
...nestedField,
name: nestedFieldName,
});
if (Array.isArray(fieldSchema)) {
return [
...nestedFields,
...fieldSchema,
];
}
return [
...nestedFields,
{
key: nestedFieldName,
type: fieldSchema,
},
];
}
}
return nestedFields;
}, []);
return nestedPaths;
};
const operators = {
equality: ['equals', 'not_equals'],
contains: ['in', 'not_in', 'all'],
comparison: ['greater_than_equal', 'greater_than', 'less_than_equal', 'less_than'],
geo: ['near'],
};
const fieldToSchemaMap = {
number: (field: NumberField) => {
const type = GraphQLFloat;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, ...operators.comparison],
),
};
},
text: (field: TextField) => {
const type = GraphQLString;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
email: (field: EmailField) => {
const type = EmailAddressResolver;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
textarea: (field: TextareaField) => {
const type = GraphQLString;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
richText: (field: RichTextField) => {
const type = GraphQLJSON;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
code: (field: CodeField) => {
const type = GraphQLString;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
radio: (field: RadioField) => ({
type: withOperators(
field,
new GraphQLEnumType({
name: `${combineParentName(parentName, field.name)}_Input`,
values: field.options.reduce((values, option) => {
if (optionIsObject(option)) {
return {
...values,
[formatName(option.value)]: {
value: option.value,
},
};
}
return {
...values,
[formatName(option)]: {
value: option,
},
};
}, {}),
}),
parentName,
[...operators.equality, 'like'],
),
}),
date: (field: DateField) => {
const type = DateTimeResolver;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, ...operators.comparison, 'like'],
),
};
},
point: (field: PointField) => {
const type = GraphQLList(GraphQLFloat);
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, ...operators.comparison, ...operators.geo],
),
};
},
relationship: (field: RelationshipField) => {
let type = withOperators(
field,
GraphQLString,
parentName,
[...operators.equality, ...operators.contains],
);
if (Array.isArray(field.relationTo)) {
type = new GraphQLInputObjectType({
name: `${combineParentName(parentName, field.name)}_Relation`,
fields: {
relationTo: {
type: new GraphQLEnumType({
name: `${combineParentName(parentName, field.name)}_Relation_RelationTo`,
values: field.relationTo.reduce((values, relation) => ({
...values,
[formatName(relation)]: {
value: relation,
},
}), {}),
}),
},
value: { type: GraphQLString },
},
});
}
if (field.hasMany) {
return {
type: new GraphQLList(type),
};
}
return { type };
},
upload: (field: UploadField) => ({
type: withOperators(
field,
GraphQLString,
parentName,
[...operators.equality],
),
}),
checkbox: (field: CheckboxField) => ({
type: withOperators(
field,
GraphQLBoolean,
parentName,
[...operators.equality],
),
}),
select: (field: SelectField) => ({
type: withOperators(
field,
new GraphQLEnumType({
name: `${combineParentName(parentName, field.name)}_Input`,
values: field.options.reduce((values, option) => {
if (typeof option === 'object' && option.value) {
return {
...values,
[formatName(option.value)]: {
value: option.value,
},
};
}
if (typeof option === 'string') {
return {
...values,
[option]: {
value: option,
},
};
}
return values;
}, {}),
}),
parentName,
[...operators.equality, ...operators.contains],
),
}),
array: (field: ArrayField) => recursivelyBuildNestedPaths(field),
group: (field: GroupField) => recursivelyBuildNestedPaths(field),
row: (field: RowField) => field.fields.reduce((rowSchema, rowField) => {
const getFieldSchema = fieldToSchemaMap[rowField.type];
if (getFieldSchema) {
const rowFieldSchema = getFieldSchema(rowField);
if (fieldHasSubFields(rowField)) {
return [
...rowSchema,
...rowFieldSchema,
];
}
if (fieldAffectsData(rowField)) {
return [
...rowSchema,
{
key: rowField.name,
type: rowFieldSchema,
},
];
}
}
return rowSchema;
}, []),
};
const fieldTypes = fields.reduce((schema, field) => {
if (!fieldIsPresentationalOnly(field) && !field.hidden) {
const getFieldSchema = fieldToSchemaMap[field.type];
const getFieldSchema = fieldToSchemaMap(parentName)[field.type];
if (getFieldSchema) {
const fieldSchema = getFieldSchema(field);
@@ -362,31 +67,5 @@ const buildWhereInputType = (name: string, fields: Field[], parentName: string):
const fieldName = formatName(name);
return new GraphQLInputObjectType({
name: `${fieldName}_where`,
fields: {
...fieldTypes,
OR: {
type: new GraphQLList(new GraphQLInputObjectType({
name: `${fieldName}_where_or`,
fields: {
...fieldTypes,
},
})),
},
AND: {
type: new GraphQLList(new GraphQLInputObjectType({
name: `${fieldName}_where_and`,
fields: {
...fieldTypes,
},
})),
},
page: { type: GraphQLInt },
limit: { type: GraphQLInt },
sort: { type: GraphQLString },
},
});
return buildInputObject(fieldName, fieldTypes);
};
export default buildWhereInputType;

View File

@@ -0,0 +1,256 @@
import {
GraphQLBoolean,
GraphQLEnumType,
GraphQLFloat,
GraphQLInputObjectType,
GraphQLList,
GraphQLString,
} from 'graphql';
import { DateTimeResolver, EmailAddressResolver } from 'graphql-scalars';
import { GraphQLJSON } from 'graphql-type-json';
import {
ArrayField,
CheckboxField,
CodeField, DateField,
EmailField, fieldAffectsData, fieldHasSubFields, GroupField,
NumberField, optionIsObject, PointField,
RadioField, RelationshipField,
RichTextField, RowField, SelectField,
TextareaField,
TextField, UploadField,
} from '../../fields/config/types';
import withOperators from './withOperators';
import { operators } from './operators';
import combineParentName from '../utilities/combineParentName';
import formatName from '../utilities/formatName';
import { recursivelyBuildNestedPaths } from './recursivelyBuildNestedPaths';
export const fieldToSchemaMap = (parentName: string) => ({
number: (field: NumberField) => {
const type = GraphQLFloat;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, ...operators.comparison],
),
};
},
text: (field: TextField) => {
const type = GraphQLString;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
email: (field: EmailField) => {
const type = EmailAddressResolver;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
textarea: (field: TextareaField) => {
const type = GraphQLString;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
richText: (field: RichTextField) => {
const type = GraphQLJSON;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
code: (field: CodeField) => {
const type = GraphQLString;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, 'like'],
),
};
},
radio: (field: RadioField) => ({
type: withOperators(
field,
new GraphQLEnumType({
name: `${combineParentName(parentName, field.name)}_Input`,
values: field.options.reduce((values, option) => {
if (optionIsObject(option)) {
return {
...values,
[formatName(option.value)]: {
value: option.value,
},
};
}
return {
...values,
[formatName(option)]: {
value: option,
},
};
}, {}),
}),
parentName,
[...operators.equality, 'like'],
),
}),
date: (field: DateField) => {
const type = DateTimeResolver;
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, ...operators.comparison, 'like'],
),
};
},
point: (field: PointField) => {
const type = GraphQLList(GraphQLFloat);
return {
type: withOperators(
field,
type,
parentName,
[...operators.equality, ...operators.comparison, ...operators.geo],
),
};
},
relationship: (field: RelationshipField) => {
let type = withOperators(
field,
GraphQLString,
parentName,
[...operators.equality, ...operators.contains],
);
if (Array.isArray(field.relationTo)) {
type = new GraphQLInputObjectType({
name: `${combineParentName(parentName, field.name)}_Relation`,
fields: {
relationTo: {
type: new GraphQLEnumType({
name: `${combineParentName(parentName, field.name)}_Relation_RelationTo`,
values: field.relationTo.reduce((values, relation) => ({
...values,
[formatName(relation)]: {
value: relation,
},
}), {}),
}),
},
value: { type: GraphQLString },
},
});
}
if (field.hasMany) {
return {
type: new GraphQLList(type),
};
}
return { type };
},
upload: (field: UploadField) => ({
type: withOperators(
field,
GraphQLString,
parentName,
[...operators.equality],
),
}),
checkbox: (field: CheckboxField) => ({
type: withOperators(
field,
GraphQLBoolean,
parentName,
[...operators.equality],
),
}),
select: (field: SelectField) => ({
type: withOperators(
field,
new GraphQLEnumType({
name: `${combineParentName(parentName, field.name)}_Input`,
values: field.options.reduce((values, option) => {
if (typeof option === 'object' && option.value) {
return {
...values,
[formatName(option.value)]: {
value: option.value,
},
};
}
if (typeof option === 'string') {
return {
...values,
[option]: {
value: option,
},
};
}
return values;
}, {}),
}),
parentName,
[...operators.equality, ...operators.contains],
),
}),
array: (field: ArrayField) => recursivelyBuildNestedPaths(parentName, field),
group: (field: GroupField) => recursivelyBuildNestedPaths(parentName, field),
row: (field: RowField) => field.fields.reduce((rowSchema, rowField) => {
const getFieldSchema = fieldToSchemaMap(parentName)[rowField.type];
if (getFieldSchema) {
const rowFieldSchema = getFieldSchema(rowField);
if (fieldHasSubFields(rowField)) {
return [
...rowSchema,
...rowFieldSchema,
];
}
if (fieldAffectsData(rowField)) {
return [
...rowSchema,
{
key: rowField.name,
type: rowFieldSchema,
},
];
}
}
return rowSchema;
}, []),
});

View File

@@ -0,0 +1,6 @@
export const operators = {
equality: ['equals', 'not_equals'],
contains: ['in', 'not_in', 'all'],
comparison: ['greater_than_equal', 'greater_than', 'less_than_equal', 'less_than'],
geo: ['near'],
};

View File

@@ -0,0 +1,42 @@
import {
FieldAffectingData,
fieldAffectsData,
fieldIsPresentationalOnly,
FieldWithSubFields,
} from '../../fields/config/types';
import { fieldToSchemaMap } from './fieldToSchemaMap';
export const recursivelyBuildNestedPaths = (parentName: string, field: FieldWithSubFields & FieldAffectingData) => {
const nestedPaths = field.fields.reduce((nestedFields, nestedField) => {
if (!fieldIsPresentationalOnly(nestedField)) {
const getFieldSchema = fieldToSchemaMap(parentName)[nestedField.type];
const nestedFieldName = fieldAffectsData(nestedField) ? `${field.name}__${nestedField.name}` : undefined;
if (getFieldSchema) {
const fieldSchema = getFieldSchema({
...nestedField,
name: nestedFieldName,
});
if (Array.isArray(fieldSchema)) {
return [
...nestedFields,
...fieldSchema,
];
}
return [
...nestedFields,
{
key: nestedFieldName,
type: fieldSchema,
},
];
}
}
return nestedFields;
}, []);
return nestedPaths;
};

View File

@@ -16,7 +16,9 @@ let token;
let postID;
let versionID;
describe('GrahpQL Resolvers', () => {
describe('GrahpQL Version Resolvers', () => {
const title = 'autosave title';
beforeAll(async (done) => {
const login = `
mutation {
@@ -39,7 +41,6 @@ describe('GrahpQL Resolvers', () => {
describe('Create', () => {
it('should allow a new autosavePost to be created with draft status', async () => {
const title = 'autosave title';
const description = 'autosave description';
const query = `mutation {
@@ -49,6 +50,7 @@ describe('GrahpQL Resolvers', () => {
description
createdAt
updatedAt
_status
}
}`;
@@ -57,44 +59,68 @@ describe('GrahpQL Resolvers', () => {
const data = response.createAutosavePost;
postID = data.id;
expect(typeof data._status).toBe('undefined');
expect(data._status).toStrictEqual('draft');
});
});
describe('Read', () => {
it('should allow read of autosavePost versions', async () => {
const updatedTitle = 'updated title';
// modify the post so it will create a new version
// language=graphQL
const update = `mutation {
updateAutosavePost(id: "${postID}", data: {title: "${updatedTitle}"}) {
title
}
}`;
await client.request(update);
// query the version
// language=graphQL
const query = `query {
versionsAutosavePost(where: { parent: { equals: ${postID} } }) {
id
version {
title
versionsAutosavePosts(where: { parent: { equals: "${postID}" } }) {
docs {
id
parent
version {
title
}
}
}
}`;
const response = await client.request(query);
const data = response.versionsAutosavePost;
const data = response.versionsAutosavePosts;
const doc = data.docs[0];
versionID = doc.id;
versionID = data.docs[0].id;
expect(versionID).toBeDefined();
expect(data.docs[0].version.title).toBeDefined();
expect(doc.id).toBeDefined();
expect(doc.parent).toStrictEqual(postID);
expect(doc.version.title).toStrictEqual(title);
});
});
// describe('Restore', () => {
// it('should allow a version to be restored', async () => {
// // update a versionsPost
// const query = `mutation {
// restoreAutosavePost {
// id
// title
// }`;
// const response = await client.request(query);
//
// const data = response.versionsAutosavePost;
// });
// });
describe('Restore', () => {
it('should allow a version to be restored', async () => {
// update a versionsPost
const restore = `mutation {
restoreVersionAutosavePost(id: "${versionID}")
}`;
await client.request(restore);
const query = `query {
AutosavePost(id: "${postID}") {
title
}
}`;
const response = await client.request(query);
const data = response.AutosavePost;
expect(data.title).toStrictEqual(title);
});
});
});