Relay Spec (#6089)

* Install graphql-relay

* Add relayNodeInterface to ParseGraphQLSchema

* Add support to global id

* Add support to global id in other operations

* Fix sort by glboal id

* Fix where by global id

* Introduce IdWhereInput

* Add Relay object identification tests

* Client mutation id on createFile mutation

* Client mutation id on callCloudCode mutation

* Client mutation id on signUp mutation

* Client mutation id on logIn mutation

* Client mutation id on logOut mutation

* Client mutation id on createClass mutation

* Client mutation id on updateClass mutation

* Client mutation id on deleteClass mutation

* Client mutation id on create object mutation

* Improve Viewer type

* Client mutation id on update object mutation

* Client mutation id on delete object mutation

* Introducing connections

* Fix tests

* Add pagination test

* Fix file location

* Fix postgres tests

* Add comments

* Tests to calculateSkipAndLimit
This commit is contained in:
Antonio Davi Macedo Coelho de Castro
2019-12-01 21:43:08 -08:00
committed by GitHub
parent 67e3c33ffe
commit a9066e20dc
22 changed files with 4685 additions and 2816 deletions

View File

@@ -1,5 +1,6 @@
import Parse from 'parse/node';
import { GraphQLNonNull } from 'graphql';
import { mutationWithClientMutationId } from 'graphql-relay';
import * as schemaTypes from './schemaTypes';
import {
transformToParse,
@@ -9,135 +10,183 @@ import { enforceMasterKeyAccess } from '../parseGraphQLUtils';
import { getClass } from './schemaQueries';
const load = parseGraphQLSchema => {
const createClassMutation = mutationWithClientMutationId({
name: 'CreateClass',
description:
'The createClass mutation can be used to create the schema for a new object class.',
inputFields: {
name: schemaTypes.CLASS_NAME_ATT,
schemaFields: {
description: "These are the schema's fields of the object class.",
type: schemaTypes.SCHEMA_FIELDS_INPUT,
},
},
outputFields: {
class: {
description: 'This is the created class.',
type: new GraphQLNonNull(schemaTypes.CLASS),
},
},
mutateAndGetPayload: async (args, context) => {
try {
const { name, schemaFields } = args;
const { config, auth } = context;
enforceMasterKeyAccess(auth);
if (auth.isReadOnly) {
throw new Parse.Error(
Parse.Error.OPERATION_FORBIDDEN,
"read-only masterKey isn't allowed to create a schema."
);
}
const schema = await config.database.loadSchema({ clearCache: true });
const parseClass = await schema.addClassIfNotExists(
name,
transformToParse(schemaFields)
);
return {
class: {
name: parseClass.className,
schemaFields: transformToGraphQL(parseClass.fields),
},
};
} catch (e) {
parseGraphQLSchema.handleError(e);
}
},
});
parseGraphQLSchema.addGraphQLType(
createClassMutation.args.input.type.ofType,
true,
true
);
parseGraphQLSchema.addGraphQLType(createClassMutation.type, true, true);
parseGraphQLSchema.addGraphQLMutation(
'createClass',
{
description:
'The createClass mutation can be used to create the schema for a new object class.',
args: {
name: schemaTypes.CLASS_NAME_ATT,
schemaFields: {
description: "These are the schema's fields of the object class.",
type: schemaTypes.SCHEMA_FIELDS_INPUT,
},
},
type: new GraphQLNonNull(schemaTypes.CLASS),
resolve: async (_source, args, context) => {
try {
const { name, schemaFields } = args;
const { config, auth } = context;
enforceMasterKeyAccess(auth);
if (auth.isReadOnly) {
throw new Parse.Error(
Parse.Error.OPERATION_FORBIDDEN,
"read-only masterKey isn't allowed to create a schema."
);
}
const schema = await config.database.loadSchema({ clearCache: true });
const parseClass = await schema.addClassIfNotExists(
name,
transformToParse(schemaFields)
);
return {
name: parseClass.className,
schemaFields: transformToGraphQL(parseClass.fields),
};
} catch (e) {
parseGraphQLSchema.handleError(e);
}
},
},
createClassMutation,
true,
true
);
const updateClassMutation = mutationWithClientMutationId({
name: 'UpdateClass',
description:
'The updateClass mutation can be used to update the schema for an existing object class.',
inputFields: {
name: schemaTypes.CLASS_NAME_ATT,
schemaFields: {
description: "These are the schema's fields of the object class.",
type: schemaTypes.SCHEMA_FIELDS_INPUT,
},
},
outputFields: {
class: {
description: 'This is the updated class.',
type: new GraphQLNonNull(schemaTypes.CLASS),
},
},
mutateAndGetPayload: async (args, context) => {
try {
const { name, schemaFields } = args;
const { config, auth } = context;
enforceMasterKeyAccess(auth);
if (auth.isReadOnly) {
throw new Parse.Error(
Parse.Error.OPERATION_FORBIDDEN,
"read-only masterKey isn't allowed to update a schema."
);
}
const schema = await config.database.loadSchema({ clearCache: true });
const existingParseClass = await getClass(name, schema);
const parseClass = await schema.updateClass(
name,
transformToParse(schemaFields, existingParseClass.fields),
undefined,
undefined,
config.database
);
return {
class: {
name: parseClass.className,
schemaFields: transformToGraphQL(parseClass.fields),
},
};
} catch (e) {
parseGraphQLSchema.handleError(e);
}
},
});
parseGraphQLSchema.addGraphQLType(
updateClassMutation.args.input.type.ofType,
true,
true
);
parseGraphQLSchema.addGraphQLType(updateClassMutation.type, true, true);
parseGraphQLSchema.addGraphQLMutation(
'updateClass',
{
description:
'The updateClass mutation can be used to update the schema for an existing object class.',
args: {
name: schemaTypes.CLASS_NAME_ATT,
schemaFields: {
description: "These are the schema's fields of the object class.",
type: schemaTypes.SCHEMA_FIELDS_INPUT,
},
},
type: new GraphQLNonNull(schemaTypes.CLASS),
resolve: async (_source, args, context) => {
try {
const { name, schemaFields } = args;
const { config, auth } = context;
enforceMasterKeyAccess(auth);
if (auth.isReadOnly) {
throw new Parse.Error(
Parse.Error.OPERATION_FORBIDDEN,
"read-only masterKey isn't allowed to update a schema."
);
}
const schema = await config.database.loadSchema({ clearCache: true });
const existingParseClass = await getClass(name, schema);
const parseClass = await schema.updateClass(
name,
transformToParse(schemaFields, existingParseClass.fields),
undefined,
undefined,
config.database
);
return {
name: parseClass.className,
schemaFields: transformToGraphQL(parseClass.fields),
};
} catch (e) {
parseGraphQLSchema.handleError(e);
}
},
},
updateClassMutation,
true,
true
);
parseGraphQLSchema.addGraphQLMutation(
'deleteClass',
{
description:
'The deleteClass mutation can be used to delete an existing object class.',
args: {
name: schemaTypes.CLASS_NAME_ATT,
},
type: new GraphQLNonNull(schemaTypes.CLASS),
resolve: async (_source, args, context) => {
try {
const { name } = args;
const { config, auth } = context;
enforceMasterKeyAccess(auth);
if (auth.isReadOnly) {
throw new Parse.Error(
Parse.Error.OPERATION_FORBIDDEN,
"read-only masterKey isn't allowed to delete a schema."
);
}
const schema = await config.database.loadSchema({ clearCache: true });
const existingParseClass = await getClass(name, schema);
await config.database.deleteSchema(name);
return {
name: existingParseClass.className,
schemaFields: transformToGraphQL(existingParseClass.fields),
};
} catch (e) {
parseGraphQLSchema.handleError(e);
}
const deleteClassMutation = mutationWithClientMutationId({
name: 'DeleteClass',
description:
'The deleteClass mutation can be used to delete an existing object class.',
inputFields: {
name: schemaTypes.CLASS_NAME_ATT,
},
outputFields: {
class: {
description: 'This is the deleted class.',
type: new GraphQLNonNull(schemaTypes.CLASS),
},
},
mutateAndGetPayload: async (args, context) => {
try {
const { name } = args;
const { config, auth } = context;
enforceMasterKeyAccess(auth);
if (auth.isReadOnly) {
throw new Parse.Error(
Parse.Error.OPERATION_FORBIDDEN,
"read-only masterKey isn't allowed to delete a schema."
);
}
const schema = await config.database.loadSchema({ clearCache: true });
const existingParseClass = await getClass(name, schema);
await config.database.deleteSchema(name);
return {
class: {
name: existingParseClass.className,
schemaFields: transformToGraphQL(existingParseClass.fields),
},
};
} catch (e) {
parseGraphQLSchema.handleError(e);
}
},
});
parseGraphQLSchema.addGraphQLType(
deleteClassMutation.args.input.type.ofType,
true,
true
);
parseGraphQLSchema.addGraphQLType(deleteClassMutation.type, true, true);
parseGraphQLSchema.addGraphQLMutation(
'deleteClass',
deleteClassMutation,
true,
true
);