From ea7a6dc507c0fd0ad541f65996673de82e728441 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 16 Aug 2019 14:44:52 -0700 Subject: [PATCH 01/60] Remove nested operations --- src/GraphQL/ParseGraphQLSchema.js | 43 ++-- src/GraphQL/loaders/defaultGraphQLQueries.js | 17 +- src/GraphQL/loaders/filesMutations.js | 140 ++++++------- src/GraphQL/loaders/functionsMutations.js | 83 ++++---- src/GraphQL/loaders/objectsMutations.js | 21 +- src/GraphQL/loaders/objectsQueries.js | 24 +-- src/GraphQL/loaders/parseClassMutations.js | 4 +- src/GraphQL/loaders/parseClassQueries.js | 4 +- src/GraphQL/loaders/schemaDirectives.js | 9 - src/GraphQL/loaders/usersMutations.js | 199 ++++++++++--------- src/GraphQL/loaders/usersQueries.js | 45 ++--- 11 files changed, 263 insertions(+), 326 deletions(-) diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index b4ad2b8701..6d9010a8fb 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -25,18 +25,21 @@ const RESERVED_GRAPHQL_TYPE_NAMES = [ 'Query', 'Mutation', 'Subscription', - 'ObjectsQuery', - 'UsersQuery', - 'ObjectsMutation', - 'FilesMutation', - 'UsersMutation', - 'FunctionsMutation', 'Viewer', 'SignUpFieldsInput', 'LogInFieldsInput', ]; -const RESERVED_GRAPHQL_OBJECT_QUERY_NAMES = ['get', 'find']; -const RESERVED_GRAPHQL_OBJECT_MUTATION_NAMES = ['create', 'update', 'delete']; +const RESERVED_GRAPHQL_QUERY_NAMES = ['health', 'viewer', 'get', 'find']; +const RESERVED_GRAPHQL_MUTATION_NAMES = [ + 'signUp', + 'logIn', + 'logOut', + 'createFile', + 'call', + 'create', + 'update', + 'delete', +]; class ParseGraphQLSchema { databaseController: DatabaseController; @@ -87,9 +90,7 @@ class ParseGraphQLSchema { this.graphQLAutoSchema = null; this.graphQLSchema = null; this.graphQLTypes = []; - this.graphQLObjectsQueries = {}; this.graphQLQueries = {}; - this.graphQLObjectsMutations = {}; this.graphQLMutations = {}; this.graphQLSubscriptions = {}; this.graphQLSchemaDirectivesDefinitions = null; @@ -104,6 +105,7 @@ class ParseGraphQLSchema { parseClassMutations.load(this, parseClass, parseClassConfig); } ); + defaultGraphQLTypes.loadArrayResult(this, parseClasses); defaultGraphQLQueries.load(this); defaultGraphQLMutations.load(this); @@ -211,29 +213,28 @@ class ParseGraphQLSchema { return type; } - addGraphQLObjectQuery( + addGraphQLQuery( fieldName, field, throwError = false, ignoreReserved = false ) { if ( - (!ignoreReserved && - RESERVED_GRAPHQL_OBJECT_QUERY_NAMES.includes(fieldName)) || - this.graphQLObjectsQueries[fieldName] + (!ignoreReserved && RESERVED_GRAPHQL_QUERY_NAMES.includes(fieldName)) || + this.graphQLQueries[fieldName] ) { - const message = `Object query ${fieldName} could not be added to the auto schema because it collided with an existing field.`; + const message = `Query ${fieldName} could not be added to the auto schema because it collided with an existing field.`; if (throwError) { throw new Error(message); } this.log.warn(message); return undefined; } - this.graphQLObjectsQueries[fieldName] = field; + this.graphQLQueries[fieldName] = field; return field; } - addGraphQLObjectMutation( + addGraphQLMutation( fieldName, field, throwError = false, @@ -241,17 +242,17 @@ class ParseGraphQLSchema { ) { if ( (!ignoreReserved && - RESERVED_GRAPHQL_OBJECT_MUTATION_NAMES.includes(fieldName)) || - this.graphQLObjectsMutations[fieldName] + RESERVED_GRAPHQL_MUTATION_NAMES.includes(fieldName)) || + this.graphQLMutations[fieldName] ) { - const message = `Object mutation ${fieldName} could not be added to the auto schema because it collided with an existing field.`; + const message = `Mutation ${fieldName} could not be added to the auto schema because it collided with an existing field.`; if (throwError) { throw new Error(message); } this.log.warn(message); return undefined; } - this.graphQLObjectsMutations[fieldName] = field; + this.graphQLMutations[fieldName] = field; return field; } diff --git a/src/GraphQL/loaders/defaultGraphQLQueries.js b/src/GraphQL/loaders/defaultGraphQLQueries.js index 3618bf1553..07edc21f1e 100644 --- a/src/GraphQL/loaders/defaultGraphQLQueries.js +++ b/src/GraphQL/loaders/defaultGraphQLQueries.js @@ -3,12 +3,17 @@ import * as objectsQueries from './objectsQueries'; import * as usersQueries from './usersQueries'; const load = parseGraphQLSchema => { - parseGraphQLSchema.graphQLQueries.health = { - description: - 'The health query can be used to check if the server is up and running.', - type: new GraphQLNonNull(GraphQLBoolean), - resolve: () => true, - }; + parseGraphQLSchema.addGraphQLQuery( + 'health', + { + description: + 'The health query can be used to check if the server is up and running.', + type: new GraphQLNonNull(GraphQLBoolean), + resolve: () => true, + }, + true, + true + ); objectsQueries.load(parseGraphQLSchema); usersQueries.load(parseGraphQLSchema); diff --git a/src/GraphQL/loaders/filesMutations.js b/src/GraphQL/loaders/filesMutations.js index 6dafa39995..5ea224b3af 100644 --- a/src/GraphQL/loaders/filesMutations.js +++ b/src/GraphQL/loaders/filesMutations.js @@ -1,93 +1,83 @@ -import { GraphQLObjectType, GraphQLNonNull } from 'graphql'; +import { GraphQLNonNull } from 'graphql'; import { GraphQLUpload } from 'graphql-upload'; import Parse from 'parse/node'; import * as defaultGraphQLTypes from './defaultGraphQLTypes'; import logger from '../../logger'; const load = parseGraphQLSchema => { - const fields = {}; - - fields.create = { - description: - 'The create mutation can be used to create and upload a new file.', - args: { - upload: { - description: 'This is the new file to be created and uploaded', - type: new GraphQLNonNull(GraphQLUpload), + parseGraphQLSchema.addGraphQLMutation( + 'createFile', + { + description: + 'The create mutation can be used to create and upload a new file.', + args: { + upload: { + description: 'This is the new file to be created and uploaded', + type: new GraphQLNonNull(GraphQLUpload), + }, }, - }, - type: new GraphQLNonNull(defaultGraphQLTypes.FILE_INFO), - async resolve(_source, args, context) { - try { - const { upload } = args; - const { config } = context; + type: new GraphQLNonNull(defaultGraphQLTypes.FILE_INFO), + async resolve(_source, args, context) { + try { + const { upload } = args; + const { config } = context; - const { createReadStream, filename, mimetype } = await upload; - let data = null; - if (createReadStream) { - const stream = createReadStream(); - data = await new Promise((resolve, reject) => { - let data = ''; - stream - .on('error', reject) - .on('data', chunk => (data += chunk)) - .on('end', () => resolve(data)); - }); - } + const { createReadStream, filename, mimetype } = await upload; + let data = null; + if (createReadStream) { + const stream = createReadStream(); + data = await new Promise((resolve, reject) => { + let data = ''; + stream + .on('error', reject) + .on('data', chunk => (data += chunk)) + .on('end', () => resolve(data)); + }); + } - if (!data || !data.length) { - throw new Parse.Error( - Parse.Error.FILE_SAVE_ERROR, - 'Invalid file upload.' - ); - } + if (!data || !data.length) { + throw new Parse.Error( + Parse.Error.FILE_SAVE_ERROR, + 'Invalid file upload.' + ); + } - if (filename.length > 128) { - throw new Parse.Error( - Parse.Error.INVALID_FILE_NAME, - 'Filename too long.' - ); - } + if (filename.length > 128) { + throw new Parse.Error( + Parse.Error.INVALID_FILE_NAME, + 'Filename too long.' + ); + } - if (!filename.match(/^[_a-zA-Z0-9][a-zA-Z0-9@\.\ ~_-]*$/)) { - throw new Parse.Error( - Parse.Error.INVALID_FILE_NAME, - 'Filename contains invalid characters.' - ); - } + if (!filename.match(/^[_a-zA-Z0-9][a-zA-Z0-9@\.\ ~_-]*$/)) { + throw new Parse.Error( + Parse.Error.INVALID_FILE_NAME, + 'Filename contains invalid characters.' + ); + } - try { - return await config.filesController.createFile( - config, - filename, - data, - mimetype - ); + try { + return await config.filesController.createFile( + config, + filename, + data, + mimetype + ); + } catch (e) { + logger.error('Error creating a file: ', e); + throw new Parse.Error( + Parse.Error.FILE_SAVE_ERROR, + `Could not store file: ${filename}.` + ); + } } catch (e) { - logger.error('Error creating a file: ', e); - throw new Parse.Error( - Parse.Error.FILE_SAVE_ERROR, - `Could not store file: ${filename}.` - ); + parseGraphQLSchema.handleError(e); } - } catch (e) { - parseGraphQLSchema.handleError(e); - } + }, }, - }; - - const filesMutation = new GraphQLObjectType({ - name: 'FilesMutation', - description: 'FilesMutation is the top level type for files mutations.', - fields, - }); - parseGraphQLSchema.addGraphQLType(filesMutation, true, true); - - parseGraphQLSchema.graphQLMutations.files = { - description: 'This is the top level for files mutations.', - type: filesMutation, - resolve: () => new Object(), - }; + true, + true + ); }; export { load }; diff --git a/src/GraphQL/loaders/functionsMutations.js b/src/GraphQL/loaders/functionsMutations.js index ffb6b8ee06..fa5c280c33 100644 --- a/src/GraphQL/loaders/functionsMutations.js +++ b/src/GraphQL/loaders/functionsMutations.js @@ -1,57 +1,46 @@ -import { GraphQLObjectType, GraphQLNonNull, GraphQLString } from 'graphql'; +import { GraphQLNonNull, GraphQLString } from 'graphql'; import { FunctionsRouter } from '../../Routers/FunctionsRouter'; import * as defaultGraphQLTypes from './defaultGraphQLTypes'; const load = parseGraphQLSchema => { - const fields = {}; - - fields.call = { - description: - 'The call mutation can be used to invoke a cloud code function.', - args: { - functionName: { - description: 'This is the name of the function to be called.', - type: new GraphQLNonNull(GraphQLString), - }, - params: { - description: 'These are the params to be passed to the function.', - type: defaultGraphQLTypes.OBJECT, + parseGraphQLSchema.addGraphQLMutation( + 'call', + { + description: + 'The call mutation can be used to invoke a cloud code function.', + args: { + functionName: { + description: 'This is the name of the function to be called.', + type: new GraphQLNonNull(GraphQLString), + }, + params: { + description: 'These are the params to be passed to the function.', + type: defaultGraphQLTypes.OBJECT, + }, }, - }, - type: defaultGraphQLTypes.ANY, - async resolve(_source, args, context) { - try { - const { functionName, params } = args; - const { config, auth, info } = context; + type: defaultGraphQLTypes.ANY, + async resolve(_source, args, context) { + try { + const { functionName, params } = args; + const { config, auth, info } = context; - return (await FunctionsRouter.handleCloudFunction({ - params: { - functionName, - }, - config, - auth, - info, - body: params, - })).response.result; - } catch (e) { - parseGraphQLSchema.handleError(e); - } + return (await FunctionsRouter.handleCloudFunction({ + params: { + functionName, + }, + config, + auth, + info, + body: params, + })).response.result; + } catch (e) { + parseGraphQLSchema.handleError(e); + } + }, }, - }; - - const functionsMutation = new GraphQLObjectType({ - name: 'FunctionsMutation', - description: - 'FunctionsMutation is the top level type for functions mutations.', - fields, - }); - parseGraphQLSchema.addGraphQLType(functionsMutation, true, true); - - parseGraphQLSchema.graphQLMutations.functions = { - description: 'This is the top level for functions mutations.', - type: functionsMutation, - resolve: () => new Object(), - }; + true, + true + ); }; export { load }; diff --git a/src/GraphQL/loaders/objectsMutations.js b/src/GraphQL/loaders/objectsMutations.js index 2a8beff525..9250ed4c53 100644 --- a/src/GraphQL/loaders/objectsMutations.js +++ b/src/GraphQL/loaders/objectsMutations.js @@ -1,4 +1,4 @@ -import { GraphQLNonNull, GraphQLBoolean, GraphQLObjectType } from 'graphql'; +import { GraphQLNonNull, GraphQLBoolean } from 'graphql'; import * as defaultGraphQLTypes from './defaultGraphQLTypes'; import rest from '../../rest'; import { transformMutationInputToParse } from '../transformers/mutation'; @@ -44,7 +44,7 @@ const deleteObject = async (className, objectId, config, auth, info) => { }; const load = parseGraphQLSchema => { - parseGraphQLSchema.addGraphQLObjectMutation( + parseGraphQLSchema.addGraphQLMutation( 'create', { description: @@ -69,7 +69,7 @@ const load = parseGraphQLSchema => { true ); - parseGraphQLSchema.addGraphQLObjectMutation( + parseGraphQLSchema.addGraphQLMutation( 'update', { description: @@ -102,7 +102,7 @@ const load = parseGraphQLSchema => { true ); - parseGraphQLSchema.addGraphQLObjectMutation( + parseGraphQLSchema.addGraphQLMutation( 'delete', { description: @@ -126,19 +126,6 @@ const load = parseGraphQLSchema => { true, true ); - - const objectsMutation = new GraphQLObjectType({ - name: 'ObjectsMutation', - description: 'ObjectsMutation is the top level type for objects mutations.', - fields: parseGraphQLSchema.graphQLObjectsMutations, - }); - parseGraphQLSchema.addGraphQLType(objectsMutation, true, true); - - parseGraphQLSchema.graphQLMutations.objects = { - description: 'This is the top level for objects mutations.', - type: objectsMutation, - resolve: () => new Object(), - }; }; export { createObject, updateObject, deleteObject, load }; diff --git a/src/GraphQL/loaders/objectsQueries.js b/src/GraphQL/loaders/objectsQueries.js index 9b761c1c5a..2cb76e3e5a 100644 --- a/src/GraphQL/loaders/objectsQueries.js +++ b/src/GraphQL/loaders/objectsQueries.js @@ -1,9 +1,4 @@ -import { - GraphQLNonNull, - GraphQLBoolean, - GraphQLString, - GraphQLObjectType, -} from 'graphql'; +import { GraphQLNonNull, GraphQLBoolean, GraphQLString } from 'graphql'; import getFieldNames from 'graphql-list-fields'; import Parse from 'parse/node'; import * as defaultGraphQLTypes from './defaultGraphQLTypes'; @@ -134,7 +129,7 @@ const findObjects = async ( }; const load = parseGraphQLSchema => { - parseGraphQLSchema.addGraphQLObjectQuery( + parseGraphQLSchema.addGraphQLQuery( 'get', { description: @@ -181,7 +176,7 @@ const load = parseGraphQLSchema => { true ); - parseGraphQLSchema.addGraphQLObjectQuery( + parseGraphQLSchema.addGraphQLQuery( 'find', { description: @@ -252,19 +247,6 @@ const load = parseGraphQLSchema => { true, true ); - - const objectsQuery = new GraphQLObjectType({ - name: 'ObjectsQuery', - description: 'ObjectsQuery is the top level type for objects queries.', - fields: parseGraphQLSchema.graphQLObjectsQueries, - }); - parseGraphQLSchema.addGraphQLType(objectsQuery, true, true); - - parseGraphQLSchema.graphQLQueries.objects = { - description: 'This is the top level for objects queries.', - type: objectsQuery, - resolve: () => new Object(), - }; }; export { getObject, findObjects, load }; diff --git a/src/GraphQL/loaders/parseClassMutations.js b/src/GraphQL/loaders/parseClassMutations.js index f6842db164..6259c635bc 100644 --- a/src/GraphQL/loaders/parseClassMutations.js +++ b/src/GraphQL/loaders/parseClassMutations.js @@ -94,7 +94,7 @@ const load = function( if (isCreateEnabled) { const createGraphQLMutationName = `create${graphQLClassName}`; - parseGraphQLSchema.addGraphQLObjectMutation(createGraphQLMutationName, { + parseGraphQLSchema.addGraphQLMutation(createGraphQLMutationName, { description: `The ${createGraphQLMutationName} mutation can be used to create a new object of the ${graphQLClassName} class.`, args: { fields: { @@ -155,7 +155,7 @@ const load = function( if (isUpdateEnabled) { const updateGraphQLMutationName = `update${graphQLClassName}`; - parseGraphQLSchema.addGraphQLObjectMutation(updateGraphQLMutationName, { + parseGraphQLSchema.addGraphQLMutation(updateGraphQLMutationName, { description: `The ${updateGraphQLMutationName} mutation can be used to update an object of the ${graphQLClassName} class.`, args: { objectId: defaultGraphQLTypes.OBJECT_ID_ATT, diff --git a/src/GraphQL/loaders/parseClassQueries.js b/src/GraphQL/loaders/parseClassQueries.js index 12a3dfaf9e..0f381a1292 100644 --- a/src/GraphQL/loaders/parseClassQueries.js +++ b/src/GraphQL/loaders/parseClassQueries.js @@ -54,7 +54,7 @@ const load = function( if (isGetEnabled) { const getGraphQLQueryName = graphQLClassName.charAt(0).toLowerCase() + graphQLClassName.slice(1); - parseGraphQLSchema.addGraphQLObjectQuery(getGraphQLQueryName, { + parseGraphQLSchema.addGraphQLQuery(getGraphQLQueryName, { description: `The ${getGraphQLQueryName} query can be used to get an object of the ${graphQLClassName} class by its id.`, args: { objectId: defaultGraphQLTypes.OBJECT_ID_ATT, @@ -78,7 +78,7 @@ const load = function( const findGraphQLQueryName = pluralize( graphQLClassName.charAt(0).toLowerCase() + graphQLClassName.slice(1) ); - parseGraphQLSchema.addGraphQLObjectQuery(findGraphQLQueryName, { + parseGraphQLSchema.addGraphQLQuery(findGraphQLQueryName, { description: `The ${findGraphQLQueryName} query can be used to find objects of the ${graphQLClassName} class.`, args: classGraphQLFindArgs, type: new GraphQLNonNull( diff --git a/src/GraphQL/loaders/schemaDirectives.js b/src/GraphQL/loaders/schemaDirectives.js index 171a5d2bd7..d8ff5ad552 100644 --- a/src/GraphQL/loaders/schemaDirectives.js +++ b/src/GraphQL/loaders/schemaDirectives.js @@ -3,7 +3,6 @@ import { SchemaDirectiveVisitor } from 'graphql-tools'; import { FunctionsRouter } from '../../Routers/FunctionsRouter'; export const definitions = gql` - directive @namespace on FIELD_DEFINITION directive @resolve(to: String) on FIELD_DEFINITION directive @mock(with: Any!) on FIELD_DEFINITION `; @@ -11,14 +10,6 @@ export const definitions = gql` const load = parseGraphQLSchema => { parseGraphQLSchema.graphQLSchemaDirectivesDefinitions = definitions; - class NamespaceDirectiveVisitor extends SchemaDirectiveVisitor { - visitFieldDefinition(field) { - field.resolve = () => ({}); - } - } - - parseGraphQLSchema.graphQLSchemaDirectives.namespace = NamespaceDirectiveVisitor; - class ResolveDirectiveVisitor extends SchemaDirectiveVisitor { visitFieldDefinition(field) { field.resolve = async (_source, args, context) => { diff --git a/src/GraphQL/loaders/usersMutations.js b/src/GraphQL/loaders/usersMutations.js index 40579514dc..98f3ea7a59 100644 --- a/src/GraphQL/loaders/usersMutations.js +++ b/src/GraphQL/loaders/usersMutations.js @@ -1,4 +1,4 @@ -import { GraphQLNonNull, GraphQLObjectType } from 'graphql'; +import { GraphQLNonNull } from 'graphql'; import UsersRouter from '../../Routers/UsersRouter'; import * as objectsMutations from './objectsMutations'; import { getUserFromSessionToken } from './usersQueries'; @@ -9,110 +9,111 @@ const load = parseGraphQLSchema => { if (parseGraphQLSchema.isUsersClassDisabled) { return; } - const fields = {}; - fields.signUp = { - description: 'The signUp mutation can be used to sign the user up.', - args: { - fields: { - descriptions: 'These are the fields of the user.', - type: parseGraphQLSchema.parseClassTypes['_User'].signUpInputType, + parseGraphQLSchema.addGraphQLMutation( + 'signUp', + { + description: 'The signUp mutation can be used to sign the user up.', + args: { + fields: { + descriptions: 'These are the fields of the user.', + type: parseGraphQLSchema.parseClassTypes['_User'].signUpInputType, + }, }, - }, - type: new GraphQLNonNull(parseGraphQLSchema.viewerType), - async resolve(_source, args, context, mutationInfo) { - try { - const { fields } = args; - - const { config, auth, info } = context; - - const { sessionToken } = await objectsMutations.createObject( - '_User', - fields, - config, - auth, - info - ); - - info.sessionToken = sessionToken; - - return await getUserFromSessionToken(config, info, mutationInfo); - } catch (e) { - parseGraphQLSchema.handleError(e); - } - }, - }; - - fields.logIn = { - description: 'The logIn mutation can be used to log the user in.', - args: { - fields: { - description: 'This is data needed to login', - type: parseGraphQLSchema.parseClassTypes['_User'].logInInputType, + type: new GraphQLNonNull(parseGraphQLSchema.viewerType), + async resolve(_source, args, context, mutationInfo) { + try { + const { fields } = args; + + const { config, auth, info } = context; + + const { sessionToken } = await objectsMutations.createObject( + '_User', + fields, + config, + auth, + info + ); + + info.sessionToken = sessionToken; + + return await getUserFromSessionToken(config, info, mutationInfo); + } catch (e) { + parseGraphQLSchema.handleError(e); + } }, }, - type: new GraphQLNonNull(parseGraphQLSchema.viewerType), - async resolve(_source, args, context) { - try { - const { - fields: { username, password }, - } = args; - const { config, auth, info } = context; - - return (await usersRouter.handleLogIn({ - body: { - username, - password, - }, - query: {}, - config, - auth, - info, - })).response; - } catch (e) { - parseGraphQLSchema.handleError(e); - } + true, + true + ); + + parseGraphQLSchema.addGraphQLMutation( + 'logIn', + { + description: 'The logIn mutation can be used to log the user in.', + args: { + fields: { + description: 'This is data needed to login', + type: parseGraphQLSchema.parseClassTypes['_User'].logInInputType, + }, + }, + type: new GraphQLNonNull(parseGraphQLSchema.viewerType), + async resolve(_source, args, context) { + try { + const { + fields: { username, password }, + } = args; + const { config, auth, info } = context; + + return (await usersRouter.handleLogIn({ + body: { + username, + password, + }, + query: {}, + config, + auth, + info, + })).response; + } catch (e) { + parseGraphQLSchema.handleError(e); + } + }, }, - }; - - fields.logOut = { - description: 'The logOut mutation can be used to log the user out.', - type: new GraphQLNonNull(parseGraphQLSchema.viewerType), - async resolve(_source, _args, context, mutationInfo) { - try { - const { config, auth, info } = context; - - const viewer = await getUserFromSessionToken( - config, - info, - mutationInfo - ); - - await usersRouter.handleLogOut({ - config, - auth, - info, - }); - - return viewer; - } catch (e) { - parseGraphQLSchema.handleError(e); - } + true, + true + ); + + parseGraphQLSchema.addGraphQLMutation( + 'logOut', + { + description: 'The logOut mutation can be used to log the user out.', + type: new GraphQLNonNull(parseGraphQLSchema.viewerType), + async resolve(_source, _args, context, mutationInfo) { + try { + const { config, auth, info } = context; + + const viewer = await getUserFromSessionToken( + config, + info, + mutationInfo + ); + + await usersRouter.handleLogOut({ + config, + auth, + info, + }); + + return viewer; + } catch (e) { + parseGraphQLSchema.handleError(e); + } + }, }, - }; - - const usersMutation = new GraphQLObjectType({ - name: 'UsersMutation', - description: 'UsersMutation is the top level type for files mutations.', - fields, - }); - parseGraphQLSchema.addGraphQLType(usersMutation, true, true); - - parseGraphQLSchema.graphQLMutations.users = { - description: 'This is the top level for users mutations.', - type: usersMutation, - resolve: () => new Object(), - }; + true, + true + ); }; export { load }; diff --git a/src/GraphQL/loaders/usersQueries.js b/src/GraphQL/loaders/usersQueries.js index bc50fee4a9..19c98e9453 100644 --- a/src/GraphQL/loaders/usersQueries.js +++ b/src/GraphQL/loaders/usersQueries.js @@ -1,4 +1,4 @@ -import { GraphQLNonNull, GraphQLObjectType } from 'graphql'; +import { GraphQLNonNull } from 'graphql'; import getFieldNames from 'graphql-list-fields'; import Parse from 'parse/node'; import rest from '../../rest'; @@ -49,34 +49,25 @@ const load = parseGraphQLSchema => { if (parseGraphQLSchema.isUsersClassDisabled) { return; } - const fields = {}; - fields.viewer = { - description: - 'The viewer query can be used to return the current user data.', - type: new GraphQLNonNull(parseGraphQLSchema.viewerType), - async resolve(_source, _args, context, queryInfo) { - try { - const { config, info } = context; - return await getUserFromSessionToken(config, info, queryInfo); - } catch (e) { - parseGraphQLSchema.handleError(e); - } + parseGraphQLSchema.addGraphQLQuery( + 'viewer', + { + description: + 'The viewer query can be used to return the current user data.', + type: new GraphQLNonNull(parseGraphQLSchema.viewerType), + async resolve(_source, _args, context, queryInfo) { + try { + const { config, info } = context; + return await getUserFromSessionToken(config, info, queryInfo); + } catch (e) { + parseGraphQLSchema.handleError(e); + } + }, }, - }; - - const usersQuery = new GraphQLObjectType({ - name: 'UsersQuery', - description: 'UsersQuery is the top level type for users queries.', - fields, - }); - parseGraphQLSchema.addGraphQLType(usersQuery, true, true); - - parseGraphQLSchema.graphQLQueries.users = { - description: 'This is the top level for users queries.', - type: usersQuery, - resolve: () => new Object(), - }; + true, + true + ); }; export { load, getUserFromSessionToken }; From 06fb9de4356d3ad939ab2ee6c6ad10b203308b4f Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 16 Aug 2019 15:00:09 -0700 Subject: [PATCH 02/60] Improve error log --- src/GraphQL/ParseGraphQLServer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/GraphQL/ParseGraphQLServer.js b/src/GraphQL/ParseGraphQLServer.js index e5381d2149..b78ac730de 100644 --- a/src/GraphQL/ParseGraphQLServer.js +++ b/src/GraphQL/ParseGraphQLServer.js @@ -47,7 +47,9 @@ class ParseGraphQLServer { }, }; } catch (e) { - this.log.error(e); + this.log.error( + e.stack || (typeof e.toString === 'function' && e.toString()) || e + ); throw e; } } From c01700ca2f4e89658ef8a262df3528f1aa6cad10 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 16 Aug 2019 15:01:27 -0700 Subject: [PATCH 03/60] Fix bug schema to load --- src/GraphQL/loaders/parseClassMutations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GraphQL/loaders/parseClassMutations.js b/src/GraphQL/loaders/parseClassMutations.js index 6259c635bc..32e31c1e72 100644 --- a/src/GraphQL/loaders/parseClassMutations.js +++ b/src/GraphQL/loaders/parseClassMutations.js @@ -215,7 +215,7 @@ const load = function( if (isDestroyEnabled) { const deleteGraphQLMutationName = `delete${graphQLClassName}`; - parseGraphQLSchema.addGraphQLObjectMutation(deleteGraphQLMutationName, { + parseGraphQLSchema.addGraphQLMutation(deleteGraphQLMutationName, { description: `The ${deleteGraphQLMutationName} mutation can be used to delete an object of the ${graphQLClassName} class.`, args: { objectId: defaultGraphQLTypes.OBJECT_ID_ATT, From ea860b0244e76f90e6ce5f4a79e230b591076066 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 16 Aug 2019 15:29:18 -0700 Subject: [PATCH 04/60] Fix ParseGraphQLSchema tests --- spec/ParseGraphQLSchema.spec.js | 134 +++++++++++++++----------------- 1 file changed, 64 insertions(+), 70 deletions(-) diff --git a/spec/ParseGraphQLSchema.spec.js b/spec/ParseGraphQLSchema.spec.js index 6991c6c0f7..80cd93e3a3 100644 --- a/spec/ParseGraphQLSchema.spec.js +++ b/spec/ParseGraphQLSchema.spec.js @@ -211,7 +211,7 @@ describe('ParseGraphQLSchema', () => { }); }); - describe('addGraphQLObjectQuery', () => { + describe('addGraphQLQuery', () => { it('should not load and warn duplicated queries', async () => { let logged = false; const parseGraphQLSchema = new ParseGraphQLSchema({ @@ -221,21 +221,19 @@ describe('ParseGraphQLSchema', () => { warn: message => { logged = true; expect(message).toEqual( - 'Object query someClasses could not be added to the auto schema because it collided with an existing field.' + 'Query someClasses could not be added to the auto schema because it collided with an existing field.' ); }, }, }); await parseGraphQLSchema.load(); const field = {}; - expect( - parseGraphQLSchema.addGraphQLObjectQuery('someClasses', field) - ).toBe(field); - expect(parseGraphQLSchema.graphQLObjectsQueries['someClasses']).toBe( + expect(parseGraphQLSchema.addGraphQLQuery('someClasses', field)).toBe( field ); + expect(parseGraphQLSchema.graphQLQueries['someClasses']).toBe(field); expect( - parseGraphQLSchema.addGraphQLObjectQuery('someClasses', {}) + parseGraphQLSchema.addGraphQLQuery('someClasses', {}) ).toBeUndefined(); expect(logged).toBeTruthy(); }); @@ -252,16 +250,14 @@ describe('ParseGraphQLSchema', () => { }); await parseGraphQLSchema.load(); const field = {}; - expect( - parseGraphQLSchema.addGraphQLObjectQuery('someClasses', field) - ).toBe(field); - expect(parseGraphQLSchema.graphQLObjectsQueries['someClasses']).toBe( + expect(parseGraphQLSchema.addGraphQLQuery('someClasses', field)).toBe( field ); + expect(parseGraphQLSchema.graphQLQueries['someClasses']).toBe(field); expect(() => - parseGraphQLSchema.addGraphQLObjectQuery('someClasses', {}, true) + parseGraphQLSchema.addGraphQLQuery('someClasses', {}, true) ).toThrowError( - 'Object query someClasses could not be added to the auto schema because it collided with an existing field.' + 'Query someClasses could not be added to the auto schema because it collided with an existing field.' ); }); @@ -274,15 +270,13 @@ describe('ParseGraphQLSchema', () => { warn: message => { logged = true; expect(message).toEqual( - 'Object query get could not be added to the auto schema because it collided with an existing field.' + 'Query get could not be added to the auto schema because it collided with an existing field.' ); }, }, }); await parseGraphQLSchema.load(); - expect( - parseGraphQLSchema.addGraphQLObjectQuery('get', {}) - ).toBeUndefined(); + expect(parseGraphQLSchema.addGraphQLQuery('get', {})).toBeUndefined(); expect(logged).toBeTruthy(); }); @@ -297,16 +291,16 @@ describe('ParseGraphQLSchema', () => { }, }); await parseGraphQLSchema.load(); - delete parseGraphQLSchema.graphQLObjectsQueries.get; + delete parseGraphQLSchema.graphQLQueries.get; const field = {}; - expect( - parseGraphQLSchema.addGraphQLObjectQuery('get', field, true, true) - ).toBe(field); - expect(parseGraphQLSchema.graphQLObjectsQueries['get']).toBe(field); + expect(parseGraphQLSchema.addGraphQLQuery('get', field, true, true)).toBe( + field + ); + expect(parseGraphQLSchema.graphQLQueries['get']).toBe(field); }); }); - describe('addGraphQLObjectMutation', () => { + describe('addGraphQLMutation', () => { it('should not load and warn duplicated mutations', async () => { let logged = false; const parseGraphQLSchema = new ParseGraphQLSchema({ @@ -316,7 +310,7 @@ describe('ParseGraphQLSchema', () => { warn: message => { logged = true; expect(message).toEqual( - 'Object mutation createSomeClass could not be added to the auto schema because it collided with an existing field.' + 'Mutation createSomeClass could not be added to the auto schema because it collided with an existing field.' ); }, }, @@ -324,13 +318,13 @@ describe('ParseGraphQLSchema', () => { await parseGraphQLSchema.load(); const field = {}; expect( - parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', field) - ).toBe(field); - expect( - parseGraphQLSchema.graphQLObjectsMutations['createSomeClass'] + parseGraphQLSchema.addGraphQLMutation('createSomeClass', field) ).toBe(field); + expect(parseGraphQLSchema.graphQLMutations['createSomeClass']).toBe( + field + ); expect( - parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', {}) + parseGraphQLSchema.addGraphQLMutation('createSomeClass', {}) ).toBeUndefined(); expect(logged).toBeTruthy(); }); @@ -348,15 +342,15 @@ describe('ParseGraphQLSchema', () => { await parseGraphQLSchema.load(); const field = {}; expect( - parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', field) - ).toBe(field); - expect( - parseGraphQLSchema.graphQLObjectsMutations['createSomeClass'] + parseGraphQLSchema.addGraphQLMutation('createSomeClass', field) ).toBe(field); + expect(parseGraphQLSchema.graphQLMutations['createSomeClass']).toBe( + field + ); expect(() => - parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', {}, true) + parseGraphQLSchema.addGraphQLMutation('createSomeClass', {}, true) ).toThrowError( - 'Object mutation createSomeClass could not be added to the auto schema because it collided with an existing field.' + 'Mutation createSomeClass could not be added to the auto schema because it collided with an existing field.' ); }); @@ -369,14 +363,14 @@ describe('ParseGraphQLSchema', () => { warn: message => { logged = true; expect(message).toEqual( - 'Object mutation create could not be added to the auto schema because it collided with an existing field.' + 'Mutation create could not be added to the auto schema because it collided with an existing field.' ); }, }, }); await parseGraphQLSchema.load(); expect( - parseGraphQLSchema.addGraphQLObjectMutation('create', {}) + parseGraphQLSchema.addGraphQLMutation('create', {}) ).toBeUndefined(); expect(logged).toBeTruthy(); }); @@ -392,12 +386,12 @@ describe('ParseGraphQLSchema', () => { }, }); await parseGraphQLSchema.load(); - delete parseGraphQLSchema.graphQLObjectsMutations.create; + delete parseGraphQLSchema.graphQLMutations.create; const field = {}; expect( - parseGraphQLSchema.addGraphQLObjectMutation('create', field, true, true) + parseGraphQLSchema.addGraphQLMutation('create', field, true, true) ).toBe(field); - expect(parseGraphQLSchema.graphQLObjectsMutations['create']).toBe(field); + expect(parseGraphQLSchema.graphQLMutations['create']).toBe(field); }); }); @@ -453,27 +447,27 @@ describe('ParseGraphQLSchema', () => { await parseGraphQLSchema.databaseController.schemaCache.clear(); const schema1 = await parseGraphQLSchema.load(); const types1 = parseGraphQLSchema.graphQLTypes; - const objectQueries1 = parseGraphQLSchema.graphQLObjectsQueries; - const objectMutations1 = parseGraphQLSchema.graphQLObjectsMutations; + const queries1 = parseGraphQLSchema.graphQLQueries; + const mutations1 = parseGraphQLSchema.graphQLMutations; const user = new Parse.Object('User'); await user.save(); await parseGraphQLSchema.databaseController.schemaCache.clear(); const schema2 = await parseGraphQLSchema.load(); const types2 = parseGraphQLSchema.graphQLTypes; - const objectQueries2 = parseGraphQLSchema.graphQLObjectsQueries; - const objectMutations2 = parseGraphQLSchema.graphQLObjectsMutations; + const queries2 = parseGraphQLSchema.graphQLQueries; + const mutations2 = parseGraphQLSchema.graphQLMutations; expect(schema1).not.toBe(schema2); expect(types1).not.toBe(types2); expect(types1.map(type => type.name).sort()).toEqual( types2.map(type => type.name).sort() ); - expect(objectQueries1).not.toBe(objectQueries2); - expect(Object.keys(objectQueries1).sort()).toEqual( - Object.keys(objectQueries2).sort() + expect(queries1).not.toBe(queries2); + expect(Object.keys(queries1).sort()).toEqual( + Object.keys(queries2).sort() ); - expect(objectMutations1).not.toBe(objectMutations2); - expect(Object.keys(objectMutations1).sort()).toEqual( - Object.keys(objectMutations2).sort() + expect(mutations1).not.toBe(mutations2); + expect(Object.keys(mutations1).sort()).toEqual( + Object.keys(mutations2).sort() ); }); @@ -488,27 +482,27 @@ describe('ParseGraphQLSchema', () => { await parseGraphQLSchema.databaseController.schemaCache.clear(); const schema1 = await parseGraphQLSchema.load(); const types1 = parseGraphQLSchema.graphQLTypes; - const objectQueries1 = parseGraphQLSchema.graphQLObjectsQueries; - const objectMutations1 = parseGraphQLSchema.graphQLObjectsMutations; + const queries1 = parseGraphQLSchema.graphQLQueries; + const mutations1 = parseGraphQLSchema.graphQLMutations; const car2 = new Parse.Object('car'); await car2.save(); await parseGraphQLSchema.databaseController.schemaCache.clear(); const schema2 = await parseGraphQLSchema.load(); const types2 = parseGraphQLSchema.graphQLTypes; - const objectQueries2 = parseGraphQLSchema.graphQLObjectsQueries; - const objectMutations2 = parseGraphQLSchema.graphQLObjectsMutations; + const queries2 = parseGraphQLSchema.graphQLQueries; + const mutations2 = parseGraphQLSchema.graphQLMutations; expect(schema1).not.toBe(schema2); expect(types1).not.toBe(types2); expect(types1.map(type => type.name).sort()).toEqual( types2.map(type => type.name).sort() ); - expect(objectQueries1).not.toBe(objectQueries2); - expect(Object.keys(objectQueries1).sort()).toEqual( - Object.keys(objectQueries2).sort() + expect(queries1).not.toBe(queries2); + expect(Object.keys(queries1).sort()).toEqual( + Object.keys(queries2).sort() ); - expect(objectMutations1).not.toBe(objectMutations2); - expect(Object.keys(objectMutations1).sort()).toEqual( - Object.keys(objectMutations2).sort() + expect(mutations1).not.toBe(mutations2); + expect(Object.keys(mutations1).sort()).toEqual( + Object.keys(mutations2).sort() ); }); @@ -522,25 +516,25 @@ describe('ParseGraphQLSchema', () => { await car.save(); await parseGraphQLSchema.databaseController.schemaCache.clear(); const schema1 = await parseGraphQLSchema.load(); - const objectQueries1 = parseGraphQLSchema.graphQLObjectsQueries; - const objectMutations1 = parseGraphQLSchema.graphQLObjectsMutations; + const queries1 = parseGraphQLSchema.graphQLQueries; + const mutations1 = parseGraphQLSchema.graphQLMutations; const cars = new Parse.Object('cars'); await cars.save(); await parseGraphQLSchema.databaseController.schemaCache.clear(); const schema2 = await parseGraphQLSchema.load(); - const objectQueries2 = parseGraphQLSchema.graphQLObjectsQueries; - const objectMutations2 = parseGraphQLSchema.graphQLObjectsMutations; + const queries2 = parseGraphQLSchema.graphQLQueries; + const mutations2 = parseGraphQLSchema.graphQLMutations; expect(schema1).not.toBe(schema2); - expect(objectQueries1).not.toBe(objectQueries2); - expect(Object.keys(objectQueries1).sort()).toEqual( - Object.keys(objectQueries2).sort() + expect(queries1).not.toBe(queries2); + expect(Object.keys(queries1).sort()).toEqual( + Object.keys(queries2).sort() ); - expect(objectMutations1).not.toBe(objectMutations2); + expect(mutations1).not.toBe(mutations2); expect( - Object.keys(objectMutations1) + Object.keys(mutations1) .concat('createCars', 'updateCars', 'deleteCars') .sort() - ).toEqual(Object.keys(objectMutations2).sort()); + ).toEqual(Object.keys(mutations2).sort()); }); }); }); From 816101379450e5c91d93ed8fba3e4a39e5ce31dd Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 16 Aug 2019 16:10:05 -0700 Subject: [PATCH 05/60] Fix tests --- spec/ParseGraphQLServer.spec.js | 2029 +++++++++++++------------------ 1 file changed, 818 insertions(+), 1211 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index be2caa8550..8454d043ae 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -712,10 +712,7 @@ describe('ParseGraphQLServer', () => { 'CreateResult', 'Date', 'FileInfo', - 'FilesMutation', 'FindResult', - 'ObjectsMutation', - 'ObjectsQuery', 'ReadPreference', 'UpdateResult', 'Upload', @@ -900,10 +897,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query GetSuperCar($objectId: ID!) { - objects { - superCar(objectId: $objectId) { - objectId - } + superCar(objectId: $objectId) { + objectId } } `, @@ -917,10 +912,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindCustomer { - objects { - customers { - count - } + customers { + count } } `, @@ -952,10 +945,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query GetSuperCar($objectId: ID!) { - objects { - superCar(objectId: $objectId) { - objectId - } + superCar(objectId: $objectId) { + objectId } } `, @@ -968,10 +959,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query GetCustomer($objectId: ID!) { - objects { - customer(objectId: $objectId) { - objectId - } + customer(objectId: $objectId) { + objectId } } `, @@ -984,10 +973,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars { - count - } + superCars { + count } } `, @@ -997,10 +984,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindCustomer { - objects { - customers { - count - } + customers { + count } } `, @@ -1018,10 +1003,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` mutation UpdateSuperCar($objectId: ID!, $foo: String!) { - objects { - updateSuperCar(objectId: $objectId, fields: { foo: $foo }) { - updatedAt - } + updateSuperCar(objectId: $objectId, fields: { foo: $foo }) { + updatedAt } } `, @@ -1036,10 +1019,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` mutation DeleteCustomer($objectId: ID!) { - objects { - deleteCustomer(objectId: $objectId) { - objectId - } + deleteCustomer(objectId: $objectId) { + objectId } } `, @@ -1052,10 +1033,8 @@ describe('ParseGraphQLServer', () => { const { data: customerData } = await apolloClient.query({ query: gql` mutation CreateCustomer($foo: String!) { - objects { - createCustomer(fields: { foo: $foo }) { - objectId - } + createCustomer(fields: { foo: $foo }) { + objectId } } `, @@ -1063,10 +1042,10 @@ describe('ParseGraphQLServer', () => { foo: 'rah', }, }); - expect(customerData.objects.createCustomer).toBeTruthy(); + expect(customerData.createCustomer).toBeTruthy(); // used later - const customer2Id = customerData.objects.createCustomer.objectId; + const customer2Id = customerData.createCustomer.objectId; await parseGraphQLServer.setGraphQLConfig({ classConfigs: [ @@ -1093,10 +1072,8 @@ describe('ParseGraphQLServer', () => { const { data: superCarData } = await apolloClient.query({ query: gql` mutation CreateSuperCar($foo: String!) { - objects { - createSuperCar(fields: { foo: $foo }) { - objectId - } + createSuperCar(fields: { foo: $foo }) { + objectId } } `, @@ -1104,17 +1081,15 @@ describe('ParseGraphQLServer', () => { foo: 'mah', }, }); - expect(superCarData.objects.createSuperCar).toBeTruthy(); - const superCar3Id = superCarData.objects.createSuperCar.objectId; + expect(superCarData.createSuperCar).toBeTruthy(); + const superCar3Id = superCarData.createSuperCar.objectId; await expectAsync( apolloClient.query({ query: gql` mutation UpdateSupercar($objectId: ID!, $foo: String!) { - objects { - updateSuperCar(objectId: $objectId, fields: { foo: $foo }) { - updatedAt - } + updateSuperCar(objectId: $objectId, fields: { foo: $foo }) { + updatedAt } } `, @@ -1128,10 +1103,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` mutation DeleteSuperCar($objectId: ID!) { - objects { - deleteSuperCar(objectId: $objectId) { - objectId - } + deleteSuperCar(objectId: $objectId) { + objectId } } `, @@ -1145,10 +1118,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` mutation CreateCustomer($foo: String!) { - objects { - createCustomer(fields: { foo: $foo }) { - objectId - } + createCustomer(fields: { foo: $foo }) { + objectId } } `, @@ -1161,10 +1132,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` mutation UpdateCustomer($objectId: ID!, $foo: String!) { - objects { - updateCustomer(objectId: $objectId, fields: { foo: $foo }) { - updatedAt - } + updateCustomer(objectId: $objectId, fields: { foo: $foo }) { + updatedAt } } `, @@ -1178,9 +1147,7 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` mutation DeleteCustomer($objectId: ID!, $foo: String!) { - objects { - deleteCustomer(objectId: $objectId) - } + deleteCustomer(objectId: $objectId) } `, variables: { @@ -1218,12 +1185,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` mutation InvalidCreateSuperCar { - objects { - createSuperCar( - fields: { engine: "diesel", mileage: 1000 } - ) { - objectId - } + createSuperCar(fields: { engine: "diesel", mileage: 1000 }) { + objectId } } `, @@ -1232,16 +1195,14 @@ describe('ParseGraphQLServer', () => { const { objectId: superCarId } = (await apolloClient.query({ query: gql` mutation ValidCreateSuperCar { - objects { - createSuperCar( - fields: { engine: "diesel", doors: 5, price: "£10000" } - ) { - objectId - } + createSuperCar( + fields: { engine: "diesel", doors: 5, price: "£10000" } + ) { + objectId } } `, - })).data.objects.createSuperCar; + })).data.createSuperCar; expect(superCarId).toBeTruthy(); @@ -1249,13 +1210,11 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` mutation InvalidUpdateSuperCar($objectId: ID!) { - objects { - updateSuperCar( - objectId: $objectId - fields: { engine: "petrol" } - ) { - updatedAt - } + updateSuperCar( + objectId: $objectId + fields: { engine: "petrol" } + ) { + updatedAt } } `, @@ -1268,20 +1227,15 @@ describe('ParseGraphQLServer', () => { const updatedSuperCar = (await apolloClient.query({ query: gql` mutation ValidUpdateSuperCar($objectId: ID!) { - objects { - updateSuperCar( - objectId: $objectId - fields: { mileage: 2000 } - ) { - updatedAt - } + updateSuperCar(objectId: $objectId, fields: { mileage: 2000 }) { + updatedAt } } `, variables: { objectId: superCarId, }, - })).data.objects.updateSuperCar; + })).data.updateSuperCar; expect(updatedSuperCar).toBeTruthy(); }); @@ -1321,15 +1275,13 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query GetSuperCar($objectId: ID!) { - objects { - superCar(objectId: $objectId) { - objectId - engine - doors - price - mileage - insuranceCertificate - } + superCar(objectId: $objectId) { + objectId + engine + doors + price + mileage + insuranceCertificate } } `, @@ -1341,21 +1293,19 @@ describe('ParseGraphQLServer', () => { let getSuperCar = (await apolloClient.query({ query: gql` query GetSuperCar($objectId: ID!) { - objects { - superCar(objectId: $objectId) { - objectId - engine - doors - price - mileage - } + superCar(objectId: $objectId) { + objectId + engine + doors + price + mileage } } `, variables: { objectId: superCar.id, }, - })).data.objects.superCar; + })).data.superCar; expect(getSuperCar).toBeTruthy(); await parseGraphQLServer.setGraphQLConfig({ @@ -1374,10 +1324,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query GetSuperCar($objectId: ID!) { - objects { - superCar(objectId: $objectId) { - engine - } + superCar(objectId: $objectId) { + engine } } `, @@ -1389,17 +1337,15 @@ describe('ParseGraphQLServer', () => { getSuperCar = (await apolloClient.query({ query: gql` query GetSuperCar($objectId: ID!) { - objects { - superCar(objectId: $objectId) { - objectId - } + superCar(objectId: $objectId) { + objectId } } `, variables: { objectId: superCar.id, }, - })).data.objects.superCar; + })).data.superCar; expect(getSuperCar.objectId).toBe(superCar.id); }); it('should only allow the supplied constraint fields for a class', async () => { @@ -1440,14 +1386,10 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars( - where: { - insuranceCertificate: { _eq: "private-file.pdf" } - } - ) { - count - } + superCars( + where: { insuranceCertificate: { _eq: "private-file.pdf" } } + ) { + count } } `, @@ -1458,10 +1400,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars(where: { mileage: { _eq: 0 } }) { - count - } + superCars(where: { mileage: { _eq: 0 } }) { + count } } `, @@ -1472,10 +1412,8 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars(where: { engine: { _eq: "petrol" } }) { - count - } + superCars(where: { engine: { _eq: "petrol" } }) { + count } } `, @@ -1532,11 +1470,9 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars(order: [engine_ASC]) { - results { - objectId - } + superCars(order: [engine_ASC]) { + results { + objectId } } } @@ -1547,11 +1483,9 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars(order: [engine_DESC]) { - results { - objectId - } + superCars(order: [engine_DESC]) { + results { + objectId } } } @@ -1562,11 +1496,9 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars(order: [mileage_DESC]) { - results { - objectId - } + superCars(order: [mileage_DESC]) { + results { + objectId } } } @@ -1578,11 +1510,9 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars(order: [mileage_ASC]) { - results { - objectId - } + superCars(order: [mileage_ASC]) { + results { + objectId } } } @@ -1593,11 +1523,9 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars(order: [doors_ASC]) { - results { - objectId - } + superCars(order: [doors_ASC]) { + results { + objectId } } } @@ -1608,11 +1536,9 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars(order: [price_DESC]) { - results { - objectId - } + superCars(order: [price_DESC]) { + results { + objectId } } } @@ -1623,11 +1549,9 @@ describe('ParseGraphQLServer', () => { apolloClient.query({ query: gql` query FindSuperCar { - objects { - superCars(order: [price_ASC, doors_DESC]) { - results { - objectId - } + superCars(order: [price_ASC, doors_DESC]) { + results { + objectId } } } @@ -1647,15 +1571,13 @@ describe('ParseGraphQLServer', () => { const result = (await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "SomeClass", objectId: $objectId) - } + get(className: "SomeClass", objectId: $objectId) } `, variables: { objectId: obj.id, }, - })).data.objects.get; + })).data.get; expect(result.objectId).toEqual(obj.id); expect(result.someField).toEqual('someValue'); @@ -1673,20 +1595,18 @@ describe('ParseGraphQLServer', () => { const result = (await apolloClient.query({ query: gql` query GetCustomer($objectId: ID!) { - objects { - customer(objectId: $objectId) { - objectId - someField - createdAt - updatedAt - } + customer(objectId: $objectId) { + objectId + someField + createdAt + updatedAt } } `, variables: { objectId: obj.id, }, - })).data.objects.customer; + })).data.customer; expect(result.objectId).toEqual(obj.id); expect(result.someField).toEqual('someValue'); @@ -1718,34 +1638,32 @@ describe('ParseGraphQLServer', () => { const result = (await apolloClient.query({ query: gql` query GetCustomer($objectId: ID!) { - objects { - customer(objectId: $objectId) { - objectId - manyRelations { - ... on Customer { - objectId - someCustomerField - arrayField { - ... on Element { - value - } + customer(objectId: $objectId) { + objectId + manyRelations { + ... on Customer { + objectId + someCustomerField + arrayField { + ... on Element { + value } } - ... on SomeClass { - objectId - someClassField - } } - createdAt - updatedAt + ... on SomeClass { + objectId + someClassField + } } + createdAt + updatedAt } } `, variables: { objectId: obj3.id, }, - })).data.objects.customer; + })).data.customer; expect(result.objectId).toEqual(obj3.id); expect(result.manyRelations.length).toEqual(2); @@ -1781,12 +1699,10 @@ describe('ParseGraphQLServer', () => { const specificQueryResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - ${className.charAt(0).toLowerCase() + - className.slice(1)}(objectId: $objectId) { - objectId - createdAt - } + ${className.charAt(0).toLowerCase() + + className.slice(1)}(objectId: $objectId) { + objectId + createdAt } } `, @@ -1801,9 +1717,7 @@ describe('ParseGraphQLServer', () => { const genericQueryResult = await apolloClient.query({ query: gql` query GetSomeObject($className: String!, $objectId: ID!) { - objects { - get(className: $className, objectId: $objectId) - } + get(className: $className, objectId: $objectId) } `, variables: { @@ -1834,7 +1748,7 @@ describe('ParseGraphQLServer', () => { ) ); expect( - (await getObject(object4.className, object4.id)).data.objects.get + (await getObject(object4.className, object4.id)).data.get .someField ).toEqual('someValue4'); await Promise.all( @@ -1842,7 +1756,7 @@ describe('ParseGraphQLServer', () => { expect( (await getObject(obj.className, obj.id, { 'X-Parse-Master-Key': 'test', - })).data.objects.get.someField + })).data.get.someField ).toEqual(obj.get('someField')) ) ); @@ -1851,7 +1765,7 @@ describe('ParseGraphQLServer', () => { expect( (await getObject(obj.className, obj.id, { 'X-Parse-Session-Token': user1.getSessionToken(), - })).data.objects.get.someField + })).data.get.someField ).toEqual(obj.get('someField')) ) ); @@ -1860,7 +1774,7 @@ describe('ParseGraphQLServer', () => { expect( (await getObject(obj.className, obj.id, { 'X-Parse-Session-Token': user2.getSessionToken(), - })).data.objects.get.someField + })).data.get.someField ).toEqual(obj.get('someField')) ) ); @@ -1874,7 +1788,7 @@ describe('ParseGraphQLServer', () => { expect( (await getObject(obj.className, obj.id, { 'X-Parse-Session-Token': user3.getSessionToken(), - })).data.objects.get.someField + })).data.get.someField ).toEqual(obj.get('someField')) ) ); @@ -1890,7 +1804,7 @@ describe('ParseGraphQLServer', () => { expect( (await getObject(object4.className, object4.id, { 'X-Parse-Session-Token': user4.getSessionToken(), - })).data.objects.get.someField + })).data.get.someField ).toEqual('someValue4'); await Promise.all( objects.slice(0, 2).map(obj => @@ -1904,12 +1818,12 @@ describe('ParseGraphQLServer', () => { expect( (await getObject(object3.className, object3.id, { 'X-Parse-Session-Token': user5.getSessionToken(), - })).data.objects.get.someField + })).data.get.someField ).toEqual('someValue3'); expect( (await getObject(object4.className, object4.id, { 'X-Parse-Session-Token': user5.getSessionToken(), - })).data.objects.get.someField + })).data.get.someField ).toEqual('someValue4'); }); @@ -1919,9 +1833,7 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_User", objectId: $objectId) - } + get(className: "_User", objectId: $objectId) } `, variables: { @@ -1933,7 +1845,7 @@ describe('ParseGraphQLServer', () => { }, }, }); - expect(result.data.objects.get.sessionToken).toBeUndefined(); + expect(result.data.get.sessionToken).toBeUndefined(); }); it('should not bring session token of current user', async () => { @@ -1942,9 +1854,7 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_User", objectId: $objectId) - } + get(className: "_User", objectId: $objectId) } `, variables: { @@ -1956,7 +1866,7 @@ describe('ParseGraphQLServer', () => { }, }, }); - expect(result.data.objects.get.sessionToken).toBeUndefined(); + expect(result.data.get.sessionToken).toBeUndefined(); }); it('should support keys argument', async () => { @@ -1965,13 +1875,11 @@ describe('ParseGraphQLServer', () => { const result1 = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get( - className: "GraphQLClass" - objectId: $objectId - keys: "someField" - ) - } + get( + className: "GraphQLClass" + objectId: $objectId + keys: "someField" + ) } `, variables: { @@ -1987,13 +1895,11 @@ describe('ParseGraphQLServer', () => { const result2 = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get( - className: "GraphQLClass" - objectId: $objectId - keys: "someField,pointerToUser" - ) - } + get( + className: "GraphQLClass" + objectId: $objectId + keys: "someField,pointerToUser" + ) } `, variables: { @@ -2006,10 +1912,10 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result1.data.objects.get.someField).toBeDefined(); - expect(result1.data.objects.get.pointerToUser).toBeUndefined(); - expect(result2.data.objects.get.someField).toBeDefined(); - expect(result2.data.objects.get.pointerToUser).toBeDefined(); + expect(result1.data.get.someField).toBeDefined(); + expect(result1.data.get.pointerToUser).toBeUndefined(); + expect(result2.data.get.someField).toBeDefined(); + expect(result2.data.get.pointerToUser).toBeDefined(); }); it('should support include argument', async () => { @@ -2020,9 +1926,7 @@ describe('ParseGraphQLServer', () => { const result1 = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "GraphQLClass", objectId: $objectId) - } + get(className: "GraphQLClass", objectId: $objectId) } `, variables: { @@ -2038,16 +1942,14 @@ describe('ParseGraphQLServer', () => { const result2 = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get( - className: "GraphQLClass" - objectId: $objectId - include: "pointerToUser" - ) - graphQLClass(objectId: $objectId) { - pointerToUser { - username - } + get( + className: "GraphQLClass" + objectId: $objectId + include: "pointerToUser" + ) + graphQLClass(objectId: $objectId) { + pointerToUser { + username } } } @@ -2062,14 +1964,10 @@ describe('ParseGraphQLServer', () => { }, }); + expect(result1.data.get.pointerToUser.username).toBeUndefined(); + expect(result2.data.get.pointerToUser.username).toBeDefined(); expect( - result1.data.objects.get.pointerToUser.username - ).toBeUndefined(); - expect( - result2.data.objects.get.pointerToUser.username - ).toBeDefined(); - expect( - result2.data.objects.graphQLClass.pointerToUser.username + result2.data.graphQLClass.pointerToUser.username ).toBeDefined(); }); @@ -2087,13 +1985,11 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get( - className: "GraphQLClass" - objectId: $objectId - include: "pointerToUser" - ) - } + get( + className: "GraphQLClass" + objectId: $objectId + include: "pointerToUser" + ) } `, variables: { @@ -2141,14 +2037,12 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get( - className: "GraphQLClass" - objectId: $objectId - include: "pointerToUser" - readPreference: SECONDARY - ) - } + get( + className: "GraphQLClass" + objectId: $objectId + include: "pointerToUser" + readPreference: SECONDARY + ) } `, variables: { @@ -2196,15 +2090,13 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get( - className: "GraphQLClass" - objectId: $objectId - include: "pointerToUser" - readPreference: SECONDARY - includeReadPreference: NEAREST - ) - } + get( + className: "GraphQLClass" + objectId: $objectId + include: "pointerToUser" + readPreference: SECONDARY + includeReadPreference: NEAREST + ) } `, variables: { @@ -2253,18 +2145,16 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query FindSomeObjects { - objects { - find(className: "SomeClass") { - results - } + find(className: "SomeClass") { + results } } `, }); - expect(result.data.objects.find.results.length).toEqual(2); + expect(result.data.find.results.length).toEqual(2); - result.data.objects.find.results.forEach(resultObj => { + result.data.find.results.forEach(resultObj => { const obj = resultObj.objectId === obj1.id ? obj1 : obj2; expect(resultObj.objectId).toEqual(obj.id); expect(resultObj.someField).toEqual(obj.get('someField')); @@ -2286,23 +2176,21 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query FindCustomer { - objects { - customers { - results { - objectId - someField - createdAt - updatedAt - } + customers { + results { + objectId + someField + createdAt + updatedAt } } } `, }); - expect(result.data.objects.customers.results.length).toEqual(2); + expect(result.data.customers.results.length).toEqual(2); - result.data.objects.customers.results.forEach(resultObj => { + result.data.customers.results.forEach(resultObj => { const obj = resultObj.objectId === obj1.id ? obj1 : obj2; expect(resultObj.objectId).toEqual(obj.id); expect(resultObj.someField).toEqual(obj.get('someField')); @@ -2322,15 +2210,13 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query FindSomeObjects($className: String!) { - objects { - find(className: $className) { - results - } - ${graphqlClassName} { - results { - objectId - someField - } + find(className: $className) { + results + } + ${graphqlClassName} { + results { + objectId + someField } } } @@ -2343,9 +2229,8 @@ describe('ParseGraphQLServer', () => { }, }); - const genericFindResults = result.data.objects.find.results; - const specificFindResults = - result.data.objects[graphqlClassName].results; + const genericFindResults = result.data.find.results; + const specificFindResults = result.data[graphqlClassName].results; genericFindResults.forEach(({ objectId, someField }) => { expect( specificFindResults.some( @@ -2362,62 +2247,62 @@ describe('ParseGraphQLServer', () => { } expect( - (await findObjects('GraphQLClass')).data.objects.find.results.map( + (await findObjects('GraphQLClass')).data.find.results.map( object => object.someField ) ).toEqual([]); expect( - (await findObjects('PublicClass')).data.objects.find.results.map( + (await findObjects('PublicClass')).data.find.results.map( object => object.someField ) ).toEqual(['someValue4']); expect( (await findObjects('GraphQLClass', { 'X-Parse-Master-Key': 'test', - })).data.objects.find.results + })).data.find.results .map(object => object.someField) .sort() ).toEqual(['someValue1', 'someValue2', 'someValue3']); expect( (await findObjects('PublicClass', { 'X-Parse-Master-Key': 'test', - })).data.objects.find.results.map(object => object.someField) + })).data.find.results.map(object => object.someField) ).toEqual(['someValue4']); expect( (await findObjects('GraphQLClass', { 'X-Parse-Session-Token': user1.getSessionToken(), - })).data.objects.find.results + })).data.find.results .map(object => object.someField) .sort() ).toEqual(['someValue1', 'someValue2', 'someValue3']); expect( (await findObjects('PublicClass', { 'X-Parse-Session-Token': user1.getSessionToken(), - })).data.objects.find.results.map(object => object.someField) + })).data.find.results.map(object => object.someField) ).toEqual(['someValue4']); expect( (await findObjects('GraphQLClass', { 'X-Parse-Session-Token': user2.getSessionToken(), - })).data.objects.find.results + })).data.find.results .map(object => object.someField) .sort() ).toEqual(['someValue1', 'someValue2', 'someValue3']); expect( (await findObjects('GraphQLClass', { 'X-Parse-Session-Token': user3.getSessionToken(), - })).data.objects.find.results + })).data.find.results .map(object => object.someField) .sort() ).toEqual(['someValue1', 'someValue3']); expect( (await findObjects('GraphQLClass', { 'X-Parse-Session-Token': user4.getSessionToken(), - })).data.objects.find.results.map(object => object.someField) + })).data.find.results.map(object => object.someField) ).toEqual([]); expect( (await findObjects('GraphQLClass', { 'X-Parse-Session-Token': user5.getSessionToken(), - })).data.objects.find.results.map(object => object.someField) + })).data.find.results.map(object => object.someField) ).toEqual(['someValue3']); }); @@ -2427,10 +2312,8 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query FindSomeObjects($where: Object) { - objects { - find(className: "GraphQLClass", where: $where) { - results - } + find(className: "GraphQLClass", where: $where) { + results } } `, @@ -2461,9 +2344,7 @@ describe('ParseGraphQLServer', () => { }); expect( - result.data.objects.find.results - .map(object => object.someField) - .sort() + result.data.find.results.map(object => object.someField).sort() ).toEqual(['someValue1', 'someValue3']); }); @@ -2475,11 +2356,9 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query FindSomeObjects($where: GraphQLClassWhereInput) { - objects { - graphQLClasses(where: $where) { - results { - someField - } + graphQLClasses(where: $where) { + results { + someField } } } @@ -2515,7 +2394,7 @@ describe('ParseGraphQLServer', () => { }); expect( - result.data.objects.graphQLClasses.results + result.data.graphQLClasses.results .map(object => object.someField) .sort() ).toEqual(['someValue1', 'someValue3']); @@ -2529,18 +2408,16 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query { - objects { - graphQLClasses( - where: { - _or: [ - { someField: { _eq: "someValue1" } } - { someField: { _eq: "someValue2" } } - ] - } - ) { - results { - someField - } + graphQLClasses( + where: { + _or: [ + { someField: { _eq: "someValue1" } } + { someField: { _eq: "someValue2" } } + ] + } + ) { + results { + someField } } } @@ -2553,7 +2430,7 @@ describe('ParseGraphQLServer', () => { }); expect( - result.data.objects.graphQLClasses.results + result.data.graphQLClasses.results .map(object => object.someField) .sort() ).toEqual(['someValue1', 'someValue2']); @@ -2582,25 +2459,23 @@ describe('ParseGraphQLServer', () => { $skip: Int $limit: Int ) { - objects { - find( - className: $className - where: $where - order: $order - skip: $skip - limit: $limit - ) { - results - } - someClasses( - where: $whereCustom - order: $orderCustom - skip: $skip - limit: $limit - ) { - results { - someField - } + find( + className: $className + where: $where + order: $order + skip: $skip + limit: $limit + ) { + results + } + someClasses( + where: $whereCustom + order: $orderCustom + skip: $skip + limit: $limit + ) { + results { + someField } } } @@ -2624,11 +2499,12 @@ describe('ParseGraphQLServer', () => { }, }); + expect(result.data.find.results.map(obj => obj.someField)).toEqual([ + 'someValue14', + 'someValue17', + ]); expect( - result.data.objects.find.results.map(obj => obj.someField) - ).toEqual(['someValue14', 'someValue17']); - expect( - result.data.objects.someClasses.results.map(obj => obj.someField) + result.data.someClasses.results.map(obj => obj.someField) ).toEqual(['someValue14', 'someValue17']); }); @@ -2666,21 +2542,19 @@ describe('ParseGraphQLServer', () => { $where2: GraphQLClassWhereInput $limit: Int ) { - objects { - find( - className: "GraphQLClass" - where: $where1 - limit: $limit - ) { - results - count - } - graphQLClasses(where: $where2, limit: $limit) { - results { - objectId - } - count + find( + className: "GraphQLClass" + where: $where1 + limit: $limit + ) { + results + count + } + graphQLClasses(where: $where2, limit: $limit) { + results { + objectId } + count } } `, @@ -2696,10 +2570,10 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.objects.find.results).toEqual([]); - expect(result.data.objects.find.count).toEqual(2); - expect(result.data.objects.graphQLClasses.results).toEqual([]); - expect(result.data.objects.graphQLClasses.count).toEqual(2); + expect(result.data.find.results).toEqual([]); + expect(result.data.find.count).toEqual(2); + expect(result.data.graphQLClasses.results).toEqual([]); + expect(result.data.graphQLClasses.count).toEqual(2); }); it('should only count', async () => { @@ -2735,13 +2609,11 @@ describe('ParseGraphQLServer', () => { $where1: Object $where2: GraphQLClassWhereInput ) { - objects { - find(className: "GraphQLClass", where: $where1) { - count - } - graphQLClasses(where: $where2) { - count - } + find(className: "GraphQLClass", where: $where1) { + count + } + graphQLClasses(where: $where2) { + count } } `, @@ -2756,10 +2628,10 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.objects.find.results).toBeUndefined(); - expect(result.data.objects.find.count).toEqual(2); - expect(result.data.objects.graphQLClasses.results).toBeUndefined(); - expect(result.data.objects.graphQLClasses.count).toEqual(2); + expect(result.data.find.results).toBeUndefined(); + expect(result.data.find.count).toEqual(2); + expect(result.data.graphQLClasses.results).toBeUndefined(); + expect(result.data.graphQLClasses.count).toEqual(2); }); it('should respect max limit', async () => { @@ -2779,24 +2651,22 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query FindSomeObjects($limit: Int) { - objects { - find( - className: "SomeClass" - where: { objectId: { _exists: true } } - limit: $limit - ) { - results - count - } - someClasses( - where: { objectId: { _exists: true } } - limit: $limit - ) { - results { - objectId - } - count + find( + className: "SomeClass" + where: { objectId: { _exists: true } } + limit: $limit + ) { + results + count + } + someClasses( + where: { objectId: { _exists: true } } + limit: $limit + ) { + results { + objectId } + count } } `, @@ -2810,10 +2680,10 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.objects.find.results.length).toEqual(10); - expect(result.data.objects.find.count).toEqual(100); - expect(result.data.objects.someClasses.results.length).toEqual(10); - expect(result.data.objects.someClasses.count).toEqual(100); + expect(result.data.find.results.length).toEqual(10); + expect(result.data.find.count).toEqual(100); + expect(result.data.someClasses.results.length).toEqual(10); + expect(result.data.someClasses.count).toEqual(100); }); it('should support keys argument', async () => { @@ -2822,14 +2692,12 @@ describe('ParseGraphQLServer', () => { const result1 = await apolloClient.query({ query: gql` query FindSomeObject($where: Object) { - objects { - find( - className: "GraphQLClass" - where: $where - keys: "someField" - ) { - results - } + find( + className: "GraphQLClass" + where: $where + keys: "someField" + ) { + results } } `, @@ -2848,14 +2716,12 @@ describe('ParseGraphQLServer', () => { const result2 = await apolloClient.query({ query: gql` query FindSomeObject($where: Object) { - objects { - find( - className: "GraphQLClass" - where: $where - keys: "someField,pointerToUser" - ) { - results - } + find( + className: "GraphQLClass" + where: $where + keys: "someField,pointerToUser" + ) { + results } } `, @@ -2871,18 +2737,10 @@ describe('ParseGraphQLServer', () => { }, }); - expect( - result1.data.objects.find.results[0].someField - ).toBeDefined(); - expect( - result1.data.objects.find.results[0].pointerToUser - ).toBeUndefined(); - expect( - result2.data.objects.find.results[0].someField - ).toBeDefined(); - expect( - result2.data.objects.find.results[0].pointerToUser - ).toBeDefined(); + expect(result1.data.find.results[0].someField).toBeDefined(); + expect(result1.data.find.results[0].pointerToUser).toBeUndefined(); + expect(result2.data.find.results[0].someField).toBeDefined(); + expect(result2.data.find.results[0].pointerToUser).toBeDefined(); }); it('should support include argument', async () => { @@ -2893,10 +2751,8 @@ describe('ParseGraphQLServer', () => { const result1 = await apolloClient.query({ query: gql` query FindSomeObject($where: Object) { - objects { - find(className: "GraphQLClass", where: $where) { - results - } + find(className: "GraphQLClass", where: $where) { + results } } `, @@ -2924,19 +2780,17 @@ describe('ParseGraphQLServer', () => { $where1: Object $where2: GraphQLClassWhereInput ) { - objects { - find( - className: "GraphQLClass" - where: $where1 - include: "pointerToUser" - ) { - results - } - graphQLClasses(where: $where2) { - results { - pointerToUser { - username - } + find( + className: "GraphQLClass" + where: $where1 + include: "pointerToUser" + ) { + results + } + graphQLClasses(where: $where2) { + results { + pointerToUser { + username } } } @@ -2953,14 +2807,13 @@ describe('ParseGraphQLServer', () => { }, }); expect( - result1.data.objects.find.results[0].pointerToUser.username + result1.data.find.results[0].pointerToUser.username ).toBeUndefined(); expect( - result2.data.objects.find.results[0].pointerToUser.username + result2.data.find.results[0].pointerToUser.username ).toBeDefined(); expect( - result2.data.objects.graphQLClasses.results[0].pointerToUser - .username + result2.data.graphQLClasses.results[0].pointerToUser.username ).toBeDefined(); }); @@ -2977,10 +2830,8 @@ describe('ParseGraphQLServer', () => { const result1 = await apolloClient.query({ query: gql` query FindSomeObject { - objects { - find(className: "SomeClass3") { - results - } + find(className: "SomeClass3") { + results } } `, @@ -2989,27 +2840,25 @@ describe('ParseGraphQLServer', () => { const result2 = await apolloClient.query({ query: gql` query FindSomeObject { - objects { - find(className: "SomeClass3", includeAll: true) { - results - } + find(className: "SomeClass3", includeAll: true) { + results } } `, }); expect( - result1.data.objects.find.results[0].obj1.someField1 + result1.data.find.results[0].obj1.someField1 ).toBeUndefined(); expect( - result1.data.objects.find.results[0].obj2.someField2 + result1.data.find.results[0].obj2.someField2 ).toBeUndefined(); - expect( - result2.data.objects.find.results[0].obj1.someField1 - ).toEqual('someValue1'); - expect( - result2.data.objects.find.results[0].obj2.someField2 - ).toEqual('someValue2'); + expect(result2.data.find.results[0].obj1.someField1).toEqual( + 'someValue1' + ); + expect(result2.data.find.results[0].obj2.someField2).toEqual( + 'someValue2' + ); }); describe_only_db('mongo')('read preferences', () => { @@ -3026,13 +2875,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query FindSomeObjects { - objects { - find( - className: "GraphQLClass" - include: "pointerToUser" - ) { - results - } + find(className: "GraphQLClass", include: "pointerToUser") { + results } } `, @@ -3078,14 +2922,12 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query FindSomeObjects { - objects { - find( - className: "GraphQLClass" - include: "pointerToUser" - readPreference: SECONDARY - ) { - results - } + find( + className: "GraphQLClass" + include: "pointerToUser" + readPreference: SECONDARY + ) { + results } } `, @@ -3131,15 +2973,13 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query FindSomeObjects { - objects { - find( - className: "GraphQLClass" - include: "pointerToUser" - readPreference: SECONDARY - includeReadPreference: NEAREST - ) { - results - } + find( + className: "GraphQLClass" + include: "pointerToUser" + readPreference: SECONDARY + includeReadPreference: NEAREST + ) { + results } } `, @@ -3185,15 +3025,13 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query FindSomeObjects($where: Object) { - objects { - find( - className: "GraphQLClass" - where: $where - readPreference: SECONDARY - subqueryReadPreference: NEAREST - ) { - results - } + find( + className: "GraphQLClass" + where: $where + readPreference: SECONDARY + subqueryReadPreference: NEAREST + ) { + results } } `, @@ -3242,11 +3080,9 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - createdAt - } + create(className: "SomeClass", fields: $fields) { + objectId + createdAt } } `, @@ -3257,14 +3093,14 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.objects.create.objectId).toBeDefined(); + expect(result.data.create.objectId).toBeDefined(); const obj = await new Parse.Query('SomeClass').get( - result.data.objects.create.objectId + result.data.create.objectId ); expect(obj.createdAt).toEqual( - new Date(result.data.objects.create.createdAt) + new Date(result.data.create.createdAt) ); expect(obj.get('someField')).toEqual('someValue'); }); @@ -3279,12 +3115,10 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.mutate({ mutation: gql` mutation CreateCustomer($fields: CreateCustomerFieldsInput) { - objects { - createCustomer(fields: $fields) { - objectId - createdAt - someField - } + createCustomer(fields: $fields) { + objectId + createdAt + someField } } `, @@ -3295,17 +3129,15 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.objects.createCustomer.objectId).toBeDefined(); - expect(result.data.objects.createCustomer.someField).toEqual( - 'someValue' - ); + expect(result.data.createCustomer.objectId).toBeDefined(); + expect(result.data.createCustomer.someField).toEqual('someValue'); const customer = await new Parse.Query('Customer').get( - result.data.objects.createCustomer.objectId + result.data.createCustomer.objectId ); expect(customer.createdAt).toEqual( - new Date(result.data.objects.createCustomer.createdAt) + new Date(result.data.createCustomer.createdAt) ); expect(customer.get('someField')).toEqual('someValue'); }); @@ -3319,15 +3151,13 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($className: String!) { - objects { - create(className: $className) { - objectId - createdAt - } - create${className} { - objectId - createdAt - } + create(className: $className) { + objectId + createdAt + } + create${className} { + objectId + createdAt } } `, @@ -3339,11 +3169,11 @@ describe('ParseGraphQLServer', () => { }, }); - const { create } = result.data.objects; + const { create } = result.data; expect(create.objectId).toBeDefined(); expect(create.createdAt).toBeDefined(); - const specificCreate = result.data.objects[`create${className}`]; + const specificCreate = result.data[`create${className}`]; expect(specificCreate.objectId).toBeDefined(); expect(specificCreate.createdAt).toBeDefined(); @@ -3409,14 +3239,12 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.mutate({ mutation: gql` mutation UpdateSomeObject($objectId: ID!, $fields: Object) { - objects { - update( - className: "SomeClass" - objectId: $objectId - fields: $fields - ) { - updatedAt - } + update( + className: "SomeClass" + objectId: $objectId + fields: $fields + ) { + updatedAt } } `, @@ -3428,7 +3256,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.objects.update.updatedAt).toBeDefined(); + expect(result.data.update.updatedAt).toBeDefined(); await obj.fetch(); @@ -3450,12 +3278,10 @@ describe('ParseGraphQLServer', () => { $objectId: ID! $fields: UpdateCustomerFieldsInput ) { - objects { - updateCustomer(objectId: $objectId, fields: $fields) { - updatedAt - someField1 - someField2 - } + updateCustomer(objectId: $objectId, fields: $fields) { + updatedAt + someField1 + someField2 } } `, @@ -3467,11 +3293,11 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.objects.updateCustomer.updatedAt).toBeDefined(); - expect(result.data.objects.updateCustomer.someField1).toEqual( + expect(result.data.updateCustomer.updatedAt).toBeDefined(); + expect(result.data.updateCustomer.someField1).toEqual( 'someField1Value2' ); - expect(result.data.objects.updateCustomer.someField2).toEqual( + expect(result.data.updateCustomer.someField2).toEqual( 'someField2Value1' ); @@ -3492,14 +3318,12 @@ describe('ParseGraphQLServer', () => { $objectId: ID! $fields: Object ) { - objects { - update( - className: $className - objectId: $objectId - fields: $fields - ) { - updatedAt - } + update( + className: $className + objectId: $objectId + fields: $fields + ) { + updatedAt } } `, @@ -3529,7 +3353,7 @@ describe('ParseGraphQLServer', () => { expect( (await updateObject(object4.className, object4.id, { someField: 'changedValue1', - })).data.objects.update.updatedAt + })).data.update.updatedAt ).toBeDefined(); await object4.fetch({ useMasterKey: true }); expect(object4.get('someField')).toEqual('changedValue1'); @@ -3541,7 +3365,7 @@ describe('ParseGraphQLServer', () => { obj.id, { someField: 'changedValue2' }, { 'X-Parse-Master-Key': 'test' } - )).data.objects.update.updatedAt + )).data.update.updatedAt ).toBeDefined(); await obj.fetch({ useMasterKey: true }); expect(obj.get('someField')).toEqual('changedValue2'); @@ -3555,7 +3379,7 @@ describe('ParseGraphQLServer', () => { obj.id, { someField: 'changedValue3' }, { 'X-Parse-Session-Token': user1.getSessionToken() } - )).data.objects.update.updatedAt + )).data.update.updatedAt ).toBeDefined(); await obj.fetch({ useMasterKey: true }); expect(obj.get('someField')).toEqual('changedValue3'); @@ -3569,7 +3393,7 @@ describe('ParseGraphQLServer', () => { obj.id, { someField: 'changedValue4' }, { 'X-Parse-Session-Token': user2.getSessionToken() } - )).data.objects.update.updatedAt + )).data.update.updatedAt ).toBeDefined(); await obj.fetch({ useMasterKey: true }); expect(obj.get('someField')).toEqual('changedValue4'); @@ -3583,7 +3407,7 @@ describe('ParseGraphQLServer', () => { obj.id, { someField: 'changedValue5' }, { 'X-Parse-Session-Token': user3.getSessionToken() } - )).data.objects.update.updatedAt + )).data.update.updatedAt ).toBeDefined(); await obj.fetch({ useMasterKey: true }); expect(obj.get('someField')).toEqual('changedValue5'); @@ -3621,7 +3445,7 @@ describe('ParseGraphQLServer', () => { object4.id, { someField: 'changedValue6' }, { 'X-Parse-Session-Token': user4.getSessionToken() } - )).data.objects.update.updatedAt + )).data.update.updatedAt ).toBeDefined(); await object4.fetch({ useMasterKey: true }); expect(object4.get('someField')).toEqual('changedValue6'); @@ -3646,7 +3470,7 @@ describe('ParseGraphQLServer', () => { object3.id, { someField: 'changedValue7' }, { 'X-Parse-Session-Token': user5.getSessionToken() } - )).data.objects.update.updatedAt + )).data.update.updatedAt ).toBeDefined(); await object3.fetch({ useMasterKey: true }); expect(object3.get('someField')).toEqual('changedValue7'); @@ -3656,7 +3480,7 @@ describe('ParseGraphQLServer', () => { object4.id, { someField: 'changedValue7' }, { 'X-Parse-Session-Token': user5.getSessionToken() } - )).data.objects.update.updatedAt + )).data.update.updatedAt ).toBeDefined(); await object4.fetch({ useMasterKey: true }); expect(object4.get('someField')).toEqual('changedValue7'); @@ -3674,13 +3498,11 @@ describe('ParseGraphQLServer', () => { $objectId: ID! $fields: Update${className}FieldsInput ) { - objects { - update${className}( - objectId: $objectId - fields: $fields - ) { - updatedAt - } + update${className}( + objectId: $objectId + fields: $fields + ) { + updatedAt } } `, @@ -3709,7 +3531,7 @@ describe('ParseGraphQLServer', () => { expect( (await updateObject(object4.className, object4.id, { someField: 'changedValue1', - })).data.objects[`update${object4.className}`].updatedAt + })).data[`update${object4.className}`].updatedAt ).toBeDefined(); await object4.fetch({ useMasterKey: true }); expect(object4.get('someField')).toEqual('changedValue1'); @@ -3721,7 +3543,7 @@ describe('ParseGraphQLServer', () => { obj.id, { someField: 'changedValue2' }, { 'X-Parse-Master-Key': 'test' } - )).data.objects[`update${obj.className}`].updatedAt + )).data[`update${obj.className}`].updatedAt ).toBeDefined(); await obj.fetch({ useMasterKey: true }); expect(obj.get('someField')).toEqual('changedValue2'); @@ -3735,7 +3557,7 @@ describe('ParseGraphQLServer', () => { obj.id, { someField: 'changedValue3' }, { 'X-Parse-Session-Token': user1.getSessionToken() } - )).data.objects[`update${obj.className}`].updatedAt + )).data[`update${obj.className}`].updatedAt ).toBeDefined(); await obj.fetch({ useMasterKey: true }); expect(obj.get('someField')).toEqual('changedValue3'); @@ -3749,7 +3571,7 @@ describe('ParseGraphQLServer', () => { obj.id, { someField: 'changedValue4' }, { 'X-Parse-Session-Token': user2.getSessionToken() } - )).data.objects[`update${obj.className}`].updatedAt + )).data[`update${obj.className}`].updatedAt ).toBeDefined(); await obj.fetch({ useMasterKey: true }); expect(obj.get('someField')).toEqual('changedValue4'); @@ -3763,7 +3585,7 @@ describe('ParseGraphQLServer', () => { obj.id, { someField: 'changedValue5' }, { 'X-Parse-Session-Token': user3.getSessionToken() } - )).data.objects[`update${obj.className}`].updatedAt + )).data[`update${obj.className}`].updatedAt ).toBeDefined(); await obj.fetch({ useMasterKey: true }); expect(obj.get('someField')).toEqual('changedValue5'); @@ -3801,7 +3623,7 @@ describe('ParseGraphQLServer', () => { object4.id, { someField: 'changedValue6' }, { 'X-Parse-Session-Token': user4.getSessionToken() } - )).data.objects[`update${object4.className}`].updatedAt + )).data[`update${object4.className}`].updatedAt ).toBeDefined(); await object4.fetch({ useMasterKey: true }); expect(object4.get('someField')).toEqual('changedValue6'); @@ -3826,7 +3648,7 @@ describe('ParseGraphQLServer', () => { object3.id, { someField: 'changedValue7' }, { 'X-Parse-Session-Token': user5.getSessionToken() } - )).data.objects[`update${object3.className}`].updatedAt + )).data[`update${object3.className}`].updatedAt ).toBeDefined(); await object3.fetch({ useMasterKey: true }); expect(object3.get('someField')).toEqual('changedValue7'); @@ -3836,7 +3658,7 @@ describe('ParseGraphQLServer', () => { object4.id, { someField: 'changedValue7' }, { 'X-Parse-Session-Token': user5.getSessionToken() } - )).data.objects[`update${object4.className}`].updatedAt + )).data[`update${object4.className}`].updatedAt ).toBeDefined(); await object4.fetch({ useMasterKey: true }); expect(object4.get('someField')).toEqual('changedValue7'); @@ -3851,9 +3673,7 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.mutate({ mutation: gql` mutation DeleteSomeObject($objectId: ID!) { - objects { - delete(className: "SomeClass", objectId: $objectId) - } + delete(className: "SomeClass", objectId: $objectId) } `, variables: { @@ -3861,7 +3681,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.objects.delete).toEqual(true); + expect(result.data.delete).toEqual(true); await expectAsync( obj.fetch({ useMasterKey: true }) @@ -3879,12 +3699,10 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.mutate({ mutation: gql` mutation DeleteCustomer($objectId: ID!) { - objects { - deleteCustomer(objectId: $objectId) { - objectId - someField1 - someField2 - } + deleteCustomer(objectId: $objectId) { + objectId + someField1 + someField2 } } `, @@ -3893,11 +3711,11 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.objects.deleteCustomer.objectId).toEqual(obj.id); - expect(result.data.objects.deleteCustomer.someField1).toEqual( + expect(result.data.deleteCustomer.objectId).toEqual(obj.id); + expect(result.data.deleteCustomer.someField1).toEqual( 'someField1Value1' ); - expect(result.data.objects.deleteCustomer.someField2).toEqual( + expect(result.data.deleteCustomer.someField2).toEqual( 'someField2Value1' ); @@ -3916,9 +3734,7 @@ describe('ParseGraphQLServer', () => { $className: String! $objectId: ID! ) { - objects { - delete(className: $className, objectId: $objectId) - } + delete(className: $className, objectId: $objectId) } `, variables: { @@ -3954,8 +3770,7 @@ describe('ParseGraphQLServer', () => { }) ); expect( - (await deleteObject(object4.className, object4.id)).data.objects - .delete + (await deleteObject(object4.className, object4.id)).data.delete ).toEqual(true); await expectAsync( object4.fetch({ useMasterKey: true }) @@ -3963,7 +3778,7 @@ describe('ParseGraphQLServer', () => { expect( (await deleteObject(object1.className, object1.id, { 'X-Parse-Master-Key': 'test', - })).data.objects.delete + })).data.delete ).toEqual(true); await expectAsync( object1.fetch({ useMasterKey: true }) @@ -3971,7 +3786,7 @@ describe('ParseGraphQLServer', () => { expect( (await deleteObject(object2.className, object2.id, { 'X-Parse-Session-Token': user2.getSessionToken(), - })).data.objects.delete + })).data.delete ).toEqual(true); await expectAsync( object2.fetch({ useMasterKey: true }) @@ -3979,7 +3794,7 @@ describe('ParseGraphQLServer', () => { expect( (await deleteObject(object3.className, object3.id, { 'X-Parse-Session-Token': user5.getSessionToken(), - })).data.objects.delete + })).data.delete ).toEqual(true); await expectAsync( object3.fetch({ useMasterKey: true }) @@ -3997,10 +3812,8 @@ describe('ParseGraphQLServer', () => { mutation DeleteSomeObject( $objectId: ID! ) { - objects { - delete${className}(objectId: $objectId) { - objectId - } + delete${className}(objectId: $objectId) { + objectId } } `, @@ -4036,7 +3849,7 @@ describe('ParseGraphQLServer', () => { }) ); expect( - (await deleteObject(object4.className, object4.id)).data.objects[ + (await deleteObject(object4.className, object4.id)).data[ `delete${object4.className}` ].objectId ).toEqual(object4.id); @@ -4046,7 +3859,7 @@ describe('ParseGraphQLServer', () => { expect( (await deleteObject(object1.className, object1.id, { 'X-Parse-Master-Key': 'test', - })).data.objects[`delete${object1.className}`].objectId + })).data[`delete${object1.className}`].objectId ).toEqual(object1.id); await expectAsync( object1.fetch({ useMasterKey: true }) @@ -4054,7 +3867,7 @@ describe('ParseGraphQLServer', () => { expect( (await deleteObject(object2.className, object2.id, { 'X-Parse-Session-Token': user2.getSessionToken(), - })).data.objects[`delete${object2.className}`].objectId + })).data[`delete${object2.className}`].objectId ).toEqual(object2.id); await expectAsync( object2.fetch({ useMasterKey: true }) @@ -4062,7 +3875,7 @@ describe('ParseGraphQLServer', () => { expect( (await deleteObject(object3.className, object3.id, { 'X-Parse-Session-Token': user5.getSessionToken(), - })).data.objects[`delete${object3.className}`].objectId + })).data[`delete${object3.className}`].objectId ).toEqual(object3.id); await expectAsync( object3.fetch({ useMasterKey: true }) @@ -4084,11 +3897,9 @@ describe('ParseGraphQLServer', () => { JSON.stringify({ query: ` mutation CreateFile($upload: Upload!) { - files { - create(upload: $upload) { - name - url - } + createFile(upload: $upload) { + name + url } } `, @@ -4113,14 +3924,14 @@ describe('ParseGraphQLServer', () => { const result = JSON.parse(await res.text()); - expect(result.data.files.create.name).toEqual( + expect(result.data.createFile.name).toEqual( jasmine.stringMatching(/_myFileName.txt$/) ); - expect(result.data.files.create.url).toEqual( + expect(result.data.createFile.url).toEqual( jasmine.stringMatching(/_myFileName.txt$/) ); - res = await fetch(result.data.files.create.url); + res = await fetch(result.data.createFile.url); expect(res.status).toEqual(200); expect(await res.text()).toEqual('My File Content'); @@ -4144,12 +3955,10 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query GetCurrentUser { - users { - viewer { - objectId - username - email - } + viewer { + objectId + username + email } } `, @@ -4164,7 +3973,7 @@ describe('ParseGraphQLServer', () => { objectId, username: resultUserName, email: resultEmail, - } = result.data.users.viewer; + } = result.data.viewer; expect(objectId).toBeDefined(); expect(resultUserName).toEqual(userName); expect(resultEmail).toEqual(email); @@ -4191,13 +4000,11 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query GetCurrentUser { - users { - viewer { - objectId - sessionToken - userFoo { - bar - } + viewer { + objectId + sessionToken + userFoo { + bar } } } @@ -4213,7 +4020,7 @@ describe('ParseGraphQLServer', () => { objectId, sessionToken, userFoo: resultFoo, - } = result.data.users.viewer; + } = result.data.viewer; expect(objectId).toEqual(user.id); expect(sessionToken).toBeDefined(); expect(resultFoo).toBeDefined(); @@ -4230,11 +4037,9 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.mutate({ mutation: gql` mutation SignUp($fields: SignUpFieldsInput) { - users { - signUp(fields: $fields) { - sessionToken - someField - } + signUp(fields: $fields) { + sessionToken + someField } } `, @@ -4247,9 +4052,9 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.users.signUp.sessionToken).toBeDefined(); - expect(result.data.users.signUp.someField).toEqual('someValue'); - expect(typeof result.data.users.signUp.sessionToken).toBe('string'); + expect(result.data.signUp.sessionToken).toBeDefined(); + expect(result.data.signUp.someField).toEqual('someValue'); + expect(typeof result.data.signUp.sessionToken).toBe('string'); }); it('should log the user in', async () => { @@ -4263,11 +4068,9 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.mutate({ mutation: gql` mutation LogInUser($fields: LogInFieldsInput) { - users { - logIn(fields: $fields) { - sessionToken - someField - } + logIn(fields: $fields) { + sessionToken + someField } } `, @@ -4279,9 +4082,9 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.users.logIn.sessionToken).toBeDefined(); - expect(result.data.users.logIn.someField).toEqual('someValue'); - expect(typeof result.data.users.logIn.sessionToken).toBe('string'); + expect(result.data.logIn.sessionToken).toBeDefined(); + expect(result.data.logIn.someField).toEqual('someValue'); + expect(typeof result.data.logIn.sessionToken).toBe('string'); }); it('should log the user out', async () => { @@ -4294,10 +4097,8 @@ describe('ParseGraphQLServer', () => { const logIn = await apolloClient.mutate({ mutation: gql` mutation LogInUser($fields: LogInFieldsInput) { - users { - logIn(fields: $fields) { - sessionToken - } + logIn(fields: $fields) { + sessionToken } } `, @@ -4309,15 +4110,13 @@ describe('ParseGraphQLServer', () => { }, }); - const sessionToken = logIn.data.users.logIn.sessionToken; + const sessionToken = logIn.data.logIn.sessionToken; const logOut = await apolloClient.mutate({ mutation: gql` mutation LogOutUser { - users { - logOut { - sessionToken - } + logOut { + sessionToken } } `, @@ -4327,16 +4126,14 @@ describe('ParseGraphQLServer', () => { }, }, }); - expect(logOut.data.users.logOut).toBeDefined(); + expect(logOut.data.logOut).toBeDefined(); try { await apolloClient.query({ query: gql` query GetCurrentUser { - users { - me { - username - } + me { + username } } `, @@ -4364,10 +4161,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query GetCurrentUser { - users { - me { - username - } + me { + username } } `, @@ -4393,10 +4188,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query GetCurrentUser { - users { - viewer { - username - } + viewer { + username } } `, @@ -4424,16 +4217,12 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query GetCurrentUser { - users { - viewer { - username - } + viewer { + username } - objects { - cars { - results { - objectId - } + cars { + results { + objectId } } } @@ -4462,14 +4251,12 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.mutate({ mutation: gql` mutation CallFunction { - functions { - call(functionName: "hello") - } + call(functionName: "hello") } `, }); - expect(result.data.functions.call).toEqual('Hello world!'); + expect(result.data.call).toEqual('Hello world!'); }); it('can throw errors', async () => { @@ -4481,9 +4268,7 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CallFunction { - functions { - call(functionName: "hello") - } + call(functionName: "hello") } `, }); @@ -4584,9 +4369,7 @@ describe('ParseGraphQLServer', () => { apolloClient.mutate({ mutation: gql` mutation CallFunction($params: Object) { - functions { - call(functionName: "hello", params: $params) - } + call(functionName: "hello", params: $params) } `, variables: { @@ -4603,10 +4386,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -4625,10 +4406,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -4642,25 +4421,23 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!, $someFieldValue: String) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _eq: $someFieldValue } }) { - results { - someField - } + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _eq: $someFieldValue } }) { + results { + someField } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, someFieldValue, }, }); - expect(typeof getResult.data.objects.get.someField).toEqual('string'); - expect(getResult.data.objects.get.someField).toEqual(someFieldValue); - expect(getResult.data.objects.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someField).toEqual('string'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(2); }); it('should support Int numbers', async () => { @@ -4668,11 +4445,9 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` - mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + mutation CreateSomeObject($fields: Object) { + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -4688,10 +4463,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -4708,25 +4481,23 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!, $someFieldValue: Float) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _eq: $someFieldValue } }) { - results { - someField - } + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _eq: $someFieldValue } }) { + results { + someField } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, someFieldValue, }, }); - expect(typeof getResult.data.objects.get.someField).toEqual('number'); - expect(getResult.data.objects.get.someField).toEqual(someFieldValue); - expect(getResult.data.objects.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someField).toEqual('number'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(2); }); it('should support Float numbers', async () => { @@ -4735,10 +4506,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -4757,10 +4526,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -4774,25 +4541,23 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!, $someFieldValue: Float) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _eq: $someFieldValue } }) { - results { - someField - } + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _eq: $someFieldValue } }) { + results { + someField } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, someFieldValue, }, }); - expect(typeof getResult.data.objects.get.someField).toEqual('number'); - expect(getResult.data.objects.get.someField).toEqual(someFieldValue); - expect(getResult.data.objects.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someField).toEqual('number'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(2); }); it('should support Boolean', async () => { @@ -4802,10 +4567,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -4826,10 +4589,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -4848,37 +4609,31 @@ describe('ParseGraphQLServer', () => { $someFieldValueTrue: Boolean $someFieldValueFalse: Boolean ) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses( - where: { - someFieldTrue: { _eq: $someFieldValueTrue } - someFieldFalse: { _eq: $someFieldValueFalse } - } - ) { - results { - objectId - } + get(className: "SomeClass", objectId: $objectId) + someClasses( + where: { + someFieldTrue: { _eq: $someFieldValueTrue } + someFieldFalse: { _eq: $someFieldValueFalse } + } + ) { + results { + objectId } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, someFieldValueTrue, someFieldValueFalse, }, }); - expect(typeof getResult.data.objects.get.someFieldTrue).toEqual( - 'boolean' - ); - expect(typeof getResult.data.objects.get.someFieldFalse).toEqual( - 'boolean' - ); - expect(getResult.data.objects.get.someFieldTrue).toEqual(true); - expect(getResult.data.objects.get.someFieldFalse).toEqual(false); - expect(getResult.data.objects.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someFieldTrue).toEqual('boolean'); + expect(typeof getResult.data.get.someFieldFalse).toEqual('boolean'); + expect(getResult.data.get.someFieldTrue).toEqual(true); + expect(getResult.data.get.someFieldFalse).toEqual(false); + expect(getResult.data.someClasses.results.length).toEqual(2); }); it('should support Date', async () => { @@ -4890,10 +4645,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -4912,10 +4665,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -4929,34 +4680,30 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _exists: true } }) { - results { - objectId - } + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _exists: true } }) { + results { + objectId } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, }); - expect(typeof getResult.data.objects.get.someField).toEqual('object'); - expect(getResult.data.objects.get.someField).toEqual(someFieldValue); - expect(getResult.data.objects.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someField).toEqual('object'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(2); }); it('should support createdAt', async () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - createdAt - } + create(className: "SomeClass", fields: $fields) { + createdAt } } `, @@ -4965,7 +4712,7 @@ describe('ParseGraphQLServer', () => { const schema = await new Parse.Schema('SomeClass').get(); expect(schema.fields.createdAt.type).toEqual('Date'); - const { createdAt } = createResult.data.objects.create; + const { createdAt } = createResult.data.create; expect(Date.parse(createdAt)).not.toEqual(NaN); }); @@ -4973,10 +4720,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -4988,20 +4733,16 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "SomeClass", objectId: $objectId) - } + get(className: "SomeClass", objectId: $objectId) } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, }); - expect(typeof getResult.data.objects.get.updatedAt).toEqual('string'); - expect(Date.parse(getResult.data.objects.get.updatedAt)).not.toEqual( - NaN - ); + expect(typeof getResult.data.get.updatedAt).toEqual('string'); + expect(Date.parse(getResult.data.get.updatedAt)).not.toEqual(NaN); }); it('should support pointer values', async () => { @@ -5017,10 +4758,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateChildObject($fields: Object) { - objects { - create(className: "ChildClass", fields: $fields) { - objectId - } + create(className: "ChildClass", fields: $fields) { + objectId } } `, @@ -5043,13 +4782,11 @@ describe('ParseGraphQLServer', () => { $fields1: CreateChildClassFieldsInput $fields2: CreateChildClassFieldsInput ) { - objects { - createChildClass1: createChildClass(fields: $fields1) { - objectId - } - createChildClass2: createChildClass(fields: $fields2) { - objectId - } + createChildClass1: createChildClass(fields: $fields1) { + objectId + } + createChildClass2: createChildClass(fields: $fields2) { + objectId } } `, @@ -5070,50 +4807,40 @@ describe('ParseGraphQLServer', () => { $pointerFieldValue1: ParentClassPointer $pointerFieldValue2: ParentClassPointer ) { - objects { - get(className: "ChildClass", objectId: $objectId) - findChildClass1: childClasses( - where: { pointerField: { _eq: $pointerFieldValue1 } } - ) { - results { - pointerField { - objectId - createdAt - } + get(className: "ChildClass", objectId: $objectId) + findChildClass1: childClasses( + where: { pointerField: { _eq: $pointerFieldValue1 } } + ) { + results { + pointerField { + objectId + createdAt } } - findChildClass2: childClasses( - where: { pointerField: { _eq: $pointerFieldValue2 } } - ) { - results { - pointerField { - objectId - createdAt - } + } + findChildClass2: childClasses( + where: { pointerField: { _eq: $pointerFieldValue2 } } + ) { + results { + pointerField { + objectId + createdAt } } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, pointerFieldValue1: pointerFieldValue, pointerFieldValue2: pointerFieldValue.objectId, }, }); - expect(typeof getResult.data.objects.get.pointerField).toEqual( - 'object' - ); - expect(getResult.data.objects.get.pointerField).toEqual( - pointerFieldValue - ); - expect(getResult.data.objects.findChildClass1.results.length).toEqual( - 3 - ); - expect(getResult.data.objects.findChildClass2.results.length).toEqual( - 3 - ); + expect(typeof getResult.data.get.pointerField).toEqual('object'); + expect(getResult.data.get.pointerField).toEqual(pointerFieldValue); + expect(getResult.data.findChildClass1.results.length).toEqual(3); + expect(getResult.data.findChildClass2.results.length).toEqual(3); }); it_only_db('mongo')('should support relation', async () => { @@ -5136,10 +4863,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateMainObject($fields: Object) { - objects { - create(className: "MainClass", fields: $fields) { - objectId - } + create(className: "MainClass", fields: $fields) { + objectId } } `, @@ -5171,10 +4896,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateMainObject($fields: CreateMainClassFieldsInput) { - objects { - createMainClass(fields: $fields) { - objectId - } + createMainClass(fields: $fields) { + objectId } } `, @@ -5204,46 +4927,38 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetMainObject($objectId: ID!) { - objects { - get(className: "MainClass", objectId: $objectId) - mainClass(objectId: $objectId) { - relationField { - results { - objectId - createdAt - } - count + get(className: "MainClass", objectId: $objectId) + mainClass(objectId: $objectId) { + relationField { + results { + objectId + createdAt } + count } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, }); - expect(typeof getResult.data.objects.get.relationField).toEqual( - 'object' - ); - expect(getResult.data.objects.get.relationField).toEqual({ + expect(typeof getResult.data.get.relationField).toEqual('object'); + expect(getResult.data.get.relationField).toEqual({ __type: 'Relation', className: 'SomeClass', }); - expect( - getResult.data.objects.mainClass.relationField.results.length - ).toEqual(2); - expect(getResult.data.objects.mainClass.relationField.count).toEqual( + expect(getResult.data.mainClass.relationField.results.length).toEqual( 2 ); + expect(getResult.data.mainClass.relationField.count).toEqual(2); const findResult = await apolloClient.query({ query: gql` query FindSomeObjects($where: Object) { - objects { - find(className: "SomeClass", where: $where) { - results - } + find(className: "SomeClass", where: $where) { + results } } `, @@ -5253,7 +4968,7 @@ describe('ParseGraphQLServer', () => { object: { __type: 'Pointer', className: 'MainClass', - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, key: 'relationField', }, @@ -5264,10 +4979,8 @@ describe('ParseGraphQLServer', () => { const compare = (obj1, obj2) => obj1.createdAt > obj2.createdAt ? 1 : -1; - expect(findResult.data.objects.find.results).toEqual( - jasmine.any(Array) - ); - expect(findResult.data.objects.find.results.sort(compare)).toEqual( + expect(findResult.data.find.results).toEqual(jasmine.any(Array)); + expect(findResult.data.find.results.sort(compare)).toEqual( [ { objectId: someObject1.id, @@ -5294,11 +5007,9 @@ describe('ParseGraphQLServer', () => { JSON.stringify({ query: ` mutation CreateFile($upload: Upload!) { - files { - create(upload: $upload) { - name - url - } + createFile(upload: $upload) { + name + url } } `, @@ -5323,26 +5034,24 @@ describe('ParseGraphQLServer', () => { const result = JSON.parse(await res.text()); - expect(result.data.files.create.name).toEqual( + expect(result.data.createFile.name).toEqual( jasmine.stringMatching(/_myFileName.txt$/) ); - expect(result.data.files.create.url).toEqual( + expect(result.data.createFile.url).toEqual( jasmine.stringMatching(/_myFileName.txt$/) ); const someFieldValue = { __type: 'File', - name: result.data.files.create.name, - url: result.data.files.create.url, + name: result.data.createFile.name, + url: result.data.createFile.url, }; const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -5361,13 +5070,11 @@ describe('ParseGraphQLServer', () => { $fields1: CreateSomeClassFieldsInput $fields2: CreateSomeClassFieldsInput ) { - objects { - createSomeClass1: createSomeClass(fields: $fields1) { - objectId - } - createSomeClass2: createSomeClass(fields: $fields2) { - objectId - } + createSomeClass1: createSomeClass(fields: $fields1) { + objectId + } + createSomeClass2: createSomeClass(fields: $fields2) { + objectId } } `, @@ -5387,46 +5094,40 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "SomeClass", objectId: $objectId) - findSomeClass1: someClasses( - where: { someField: { _exists: true } } - ) { - results { - someField { - name - url - } + get(className: "SomeClass", objectId: $objectId) + findSomeClass1: someClasses( + where: { someField: { _exists: true } } + ) { + results { + someField { + name + url } } - findSomeClass2: someClasses( - where: { someField: { _exists: true } } - ) { - results { - someField { - name - url - } + } + findSomeClass2: someClasses( + where: { someField: { _exists: true } } + ) { + results { + someField { + name + url } } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, }); - expect(typeof getResult.data.objects.get.someField).toEqual('object'); - expect(getResult.data.objects.get.someField).toEqual(someFieldValue); - expect(getResult.data.objects.findSomeClass1.results.length).toEqual( - 3 - ); - expect(getResult.data.objects.findSomeClass2.results.length).toEqual( - 3 - ); + expect(typeof getResult.data.get.someField).toEqual('object'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.findSomeClass1.results.length).toEqual(3); + expect(getResult.data.findSomeClass2.results.length).toEqual(3); - res = await fetch(getResult.data.objects.get.someField.url); + res = await fetch(getResult.data.get.someField.url); expect(res.status).toEqual(200); expect(await res.text()).toEqual('My File Content'); @@ -5441,10 +5142,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -5463,10 +5162,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -5492,32 +5189,26 @@ describe('ParseGraphQLServer', () => { $where: SomeClassWhereInput $genericWhere: Object ) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: $where) { - results { - objectId - someField - } - } - find(className: "SomeClass", where: $genericWhere) { - results + get(className: "SomeClass", objectId: $objectId) + someClasses(where: $where) { + results { + objectId + someField } } + find(className: "SomeClass", where: $genericWhere) { + results + } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, where, genericWhere: where, // where and genericWhere types are different }, }); - const { - get: getResult, - someClasses, - find, - } = queryResult.data.objects; + const { get: getResult, someClasses, find } = queryResult.data; const { someField } = getResult; expect(typeof someField).toEqual('object'); @@ -5549,13 +5240,11 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields1: Object, $fields2: Object) { - objects { - create1: create(className: "SomeClass", fields: $fields1) { - objectId - } - create2: create(className: "SomeClass", fields: $fields2) { - objectId - } + create1: create(className: "SomeClass", fields: $fields1) { + objectId + } + create2: create(className: "SomeClass", fields: $fields2) { + objectId } } `, @@ -5605,17 +5294,15 @@ describe('ParseGraphQLServer', () => { $where: SomeClassWhereInput $genericWhere: Object ) { - objects { - someClasses(where: $where) { - results { - objectId - someField - } - } - find(className: "SomeClass", where: $genericWhere) { - results + someClasses(where: $where) { + results { + objectId + someField } } + find(className: "SomeClass", where: $genericWhere) { + results + } } `, variables: { @@ -5624,8 +5311,8 @@ describe('ParseGraphQLServer', () => { }, }); - const { create1, create2 } = createResult.data.objects; - const { someClasses, find } = findResult.data.objects; + const { create1, create2 } = createResult.data; + const { someClasses, find } = findResult.data; // Checks class query results const { results } = someClasses; @@ -5658,10 +5345,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -5680,10 +5365,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -5697,15 +5380,13 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _exists: true } }) { - results { - objectId - someField { - ... on Element { - value - } + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _exists: true } }) { + results { + objectId + someField { + ... on Element { + value } } } @@ -5713,24 +5394,22 @@ describe('ParseGraphQLServer', () => { } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, }); - const { someField } = getResult.data.objects.get; + const { someField } = getResult.data.get; expect(Array.isArray(someField)).toBeTruthy(); expect(someField).toEqual(someFieldValue); - expect(getResult.data.objects.someClasses.results.length).toEqual(2); + expect(getResult.data.someClasses.results.length).toEqual(2); }); it('should support null values', async () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -5748,19 +5427,17 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation UpdateSomeObject($objectId: ID!, $fields: Object) { - objects { - update( - className: "SomeClass" - objectId: $objectId - fields: $fields - ) { - updatedAt - } + update( + className: "SomeClass" + objectId: $objectId + fields: $fields + ) { + updatedAt } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, fields: { someStringField: null, someNumberField: null, @@ -5774,21 +5451,19 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "SomeClass", objectId: $objectId) - } + get(className: "SomeClass", objectId: $objectId) } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, }); - expect(getResult.data.objects.get.someStringField).toBeFalsy(); - expect(getResult.data.objects.get.someNumberField).toBeFalsy(); - expect(getResult.data.objects.get.someBooleanField).toBeFalsy(); - expect(getResult.data.objects.get.someObjectField).toBeFalsy(); - expect(getResult.data.objects.get.someNullField).toEqual( + expect(getResult.data.get.someStringField).toBeFalsy(); + expect(getResult.data.get.someNumberField).toBeFalsy(); + expect(getResult.data.get.someBooleanField).toBeFalsy(); + expect(getResult.data.get.someObjectField).toBeFalsy(); + expect(getResult.data.get.someNullField).toEqual( 'now it has a string' ); }); @@ -5802,10 +5477,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -5827,13 +5500,11 @@ describe('ParseGraphQLServer', () => { $fields1: CreateSomeClassFieldsInput $fields2: CreateSomeClassFieldsInput ) { - objects { - createSomeClass1: createSomeClass(fields: $fields1) { - objectId - } - createSomeClass2: createSomeClass(fields: $fields2) { - objectId - } + createSomeClass1: createSomeClass(fields: $fields1) { + objectId + } + createSomeClass2: createSomeClass(fields: $fields2) { + objectId } } `, @@ -5850,26 +5521,24 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!, $someFieldValue: Bytes) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _eq: $someFieldValue } }) { - results { - objectId - someField - } + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _eq: $someFieldValue } }) { + results { + objectId + someField } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, someFieldValue, }, }); - expect(typeof getResult.data.objects.get.someField).toEqual('object'); - expect(getResult.data.objects.get.someField).toEqual(someFieldValue); - expect(getResult.data.objects.someClasses.results.length).toEqual(3); + expect(typeof getResult.data.get.someField).toEqual('object'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(3); }); it('should support Geo Points', async () => { @@ -5882,10 +5551,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -5904,10 +5571,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -5924,28 +5589,26 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _exists: true } }) { - results { - objectId - someField { - latitude - longitude - } + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _exists: true } }) { + results { + objectId + someField { + latitude + longitude } } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, }); - expect(typeof getResult.data.objects.get.someField).toEqual('object'); - expect(getResult.data.objects.get.someField).toEqual(someFieldValue); - expect(getResult.data.objects.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someField).toEqual('object'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(2); }); it('should support Polygons', async () => { @@ -5957,10 +5620,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -5979,10 +5640,8 @@ describe('ParseGraphQLServer', () => { await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -5999,32 +5658,26 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { somePolygonField: { _exists: true } }) { - results { - objectId - somePolygonField { - latitude - longitude - } + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { somePolygonField: { _exists: true } }) { + results { + objectId + somePolygonField { + latitude + longitude } } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, }); - expect(typeof getResult.data.objects.get.somePolygonField).toEqual( - 'object' - ); - expect(getResult.data.objects.get.somePolygonField).toEqual( - someFieldValue - ); - expect(getResult.data.objects.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.somePolygonField).toEqual('object'); + expect(getResult.data.get.somePolygonField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(2); }); it('should support polygon values', async () => { @@ -6036,10 +5689,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: Object) { - objects { - create(className: "SomeClass", fields: $fields) { - objectId - } + create(className: "SomeClass", fields: $fields) { + objectId } } `, @@ -6055,25 +5706,23 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - someClass(objectId: $objectId) { - somePolygonField { - latitude - longitude - } + someClass(objectId: $objectId) { + somePolygonField { + latitude + longitude } } } `, variables: { - objectId: createResult.data.objects.create.objectId, + objectId: createResult.data.create.objectId, }, }); const schema = await new Parse.Schema('SomeClass').get(); expect(schema.fields.somePolygonField.type).toEqual('Polygon'); - const { somePolygonField } = getResult.data.objects.someClass; + const { somePolygonField } = getResult.data.someClass; expect(Array.isArray(somePolygonField)).toBeTruthy(); somePolygonField.forEach((coord, i) => { expect(coord.latitude).toEqual(someFieldValue.coordinates[i][0]); @@ -6102,10 +5751,8 @@ describe('ParseGraphQLServer', () => { const createResult = await apolloClient.mutate({ mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - objects { - createSomeClass(fields: $fields) { - objectId - } + createSomeClass(fields: $fields) { + objectId } } `, @@ -6119,19 +5766,17 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - someClass(objectId: $objectId) { - someField - } + someClass(objectId: $objectId) { + someField } } `, variables: { - objectId: createResult.data.objects.createSomeClass.objectId, + objectId: createResult.data.createSomeClass.objectId, }, }); - expect(getResult.data.objects.someClass.someField).toEqual( + expect(getResult.data.someClass.someField).toEqual( someFieldValue.base64 ); @@ -6146,32 +5791,28 @@ describe('ParseGraphQLServer', () => { $objectId: ID! $fields: UpdateSomeClassFieldsInput ) { - objects { - updateSomeClass(objectId: $objectId, fields: $fields) { - updatedAt - } + updateSomeClass(objectId: $objectId, fields: $fields) { + updatedAt } } `, variables: { - objectId: createResult.data.objects.createSomeClass.objectId, + objectId: createResult.data.createSomeClass.objectId, fields: { someField: updatedSomeFieldValue, }, }, }); - const { updatedAt } = updatedResult.data.objects.updateSomeClass; + const { updatedAt } = updatedResult.data.updateSomeClass; expect(updatedAt).toBeDefined(); const findResult = await apolloClient.query({ query: gql` query FindSomeObject($where: SomeClassWhereInput!) { - objects { - someClasses(where: $where) { - results { - objectId - } + someClasses(where: $where) { + results { + objectId } } } @@ -6184,10 +5825,10 @@ describe('ParseGraphQLServer', () => { }, }, }); - const findResults = findResult.data.objects.someClasses.results; + const findResults = findResult.data.someClasses.results; expect(findResults.length).toBe(1); expect(findResults[0].objectId).toBe( - createResult.data.objects.createSomeClass.objectId + createResult.data.createSomeClass.objectId ); }); }); @@ -6202,9 +5843,7 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_User", objectId: $objectId) - } + get(className: "_User", objectId: $objectId) } `, variables: { @@ -6212,7 +5851,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(getResult.data.objects.get.objectId).toEqual(user.id); + expect(getResult.data.get.objectId).toEqual(user.id); }); it('should support Installation class', async () => { @@ -6224,9 +5863,7 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_Installation", objectId: $objectId) - } + get(className: "_Installation", objectId: $objectId) } `, variables: { @@ -6234,7 +5871,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(getResult.data.objects.get.objectId).toEqual(installation.id); + expect(getResult.data.get.objectId).toEqual(installation.id); }); it('should support Role class', async () => { @@ -6246,9 +5883,7 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_Role", objectId: $objectId) - } + get(className: "_Role", objectId: $objectId) } `, variables: { @@ -6256,7 +5891,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(getResult.data.objects.get.objectId).toEqual(role.id); + expect(getResult.data.get.objectId).toEqual(role.id); }); it('should support Session class', async () => { @@ -6269,9 +5904,7 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_Session", objectId: $objectId) - } + get(className: "_Session", objectId: $objectId) } `, variables: { @@ -6284,7 +5917,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(getResult.data.objects.get.objectId).toEqual(session.id); + expect(getResult.data.get.objectId).toEqual(session.id); }); it('should support Product class', async () => { @@ -6304,9 +5937,7 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_Product", objectId: $objectId) - } + get(className: "_Product", objectId: $objectId) } `, variables: { @@ -6319,7 +5950,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(getResult.data.objects.get.objectId).toEqual(product.id); + expect(getResult.data.get.objectId).toEqual(product.id); }); it('should support PushStatus class', async () => { @@ -6330,9 +5961,7 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_PushStatus", objectId: $objectId) - } + get(className: "_PushStatus", objectId: $objectId) } `, variables: { @@ -6345,7 +5974,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(getResult.data.objects.get.objectId).toEqual(pushStatus.id); + expect(getResult.data.get.objectId).toEqual(pushStatus.id); }); it('should support JobStatus class', async () => { @@ -6356,9 +5985,7 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_JobStatus", objectId: $objectId) - } + get(className: "_JobStatus", objectId: $objectId) } `, variables: { @@ -6371,7 +5998,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(getResult.data.objects.get.objectId).toEqual(jobStatus.id); + expect(getResult.data.get.objectId).toEqual(jobStatus.id); }); it('should support JobSchedule class', async () => { @@ -6382,9 +6009,7 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_JobSchedule", objectId: $objectId) - } + get(className: "_JobSchedule", objectId: $objectId) } `, variables: { @@ -6397,7 +6022,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(getResult.data.objects.get.objectId).toEqual(jobSchedule.id); + expect(getResult.data.get.objectId).toEqual(jobSchedule.id); }); it('should support Hooks class', async () => { @@ -6410,10 +6035,8 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query FindSomeObject { - objects { - find(className: "_Hooks") { - results - } + find(className: "_Hooks") { + results } } `, @@ -6424,7 +6047,7 @@ describe('ParseGraphQLServer', () => { }, }); - const { results } = getResult.data.objects.find; + const { results } = getResult.data.find; expect(results.length).toEqual(1); expect(results[0].functionName).toEqual(functionName); }); @@ -6437,9 +6060,7 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - get(className: "_Audience", objectId: $objectId) - } + get(className: "_Audience", objectId: $objectId) } `, variables: { @@ -6447,7 +6068,7 @@ describe('ParseGraphQLServer', () => { }, }); - expect(getResult.data.objects.get.objectId).toEqual(audience.id); + expect(getResult.data.get.objectId).toEqual(audience.id); }); }); }); @@ -6468,10 +6089,6 @@ describe('ParseGraphQLServer', () => { graphQLPath: '/graphql', graphQLCustomTypeDefs: gql` extend type Query { - custom: Custom @namespace - } - - type Custom { hello: String @resolve hello2: String @resolve(to: "hello") userEcho(user: CreateUserFieldsInput!): User! @resolve @@ -6510,14 +6127,12 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query Hello { - custom { - hello - } + hello } `, }); - expect(result.data.custom.hello).toEqual('Hello world!'); + expect(result.data.hello).toEqual('Hello world!'); }); it('can resolve a custom query using function name set by "to" argument', async () => { @@ -6528,14 +6143,12 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query Hello { - custom { - hello2 - } + hello2 } `, }); - expect(result.data.custom.hello2).toEqual('Hello world!'); + expect(result.data.hello2).toEqual('Hello world!'); }); it('should resolve auto types', async () => { @@ -6546,10 +6159,8 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query UserEcho($user: CreateUserFieldsInput!) { - custom { - userEcho(user: $user) { - username - } + userEcho(user: $user) { + username } } `, @@ -6560,37 +6171,33 @@ describe('ParseGraphQLServer', () => { }, }); - expect(result.data.custom.userEcho.username).toEqual('somefolk'); + expect(result.data.userEcho.username).toEqual('somefolk'); }); it('can mock a custom query with string', async () => { const result = await apolloClient.query({ query: gql` query Hello { - custom { - hello3 - } + hello3 } `, }); - expect(result.data.custom.hello3).toEqual('Hello world!'); + expect(result.data.hello3).toEqual('Hello world!'); }); it('can mock a custom query with auto type', async () => { const result = await apolloClient.query({ query: gql` query Hello { - custom { - hello4 { - username - } + hello4 { + username } } `, }); - expect(result.data.custom.hello4.username).toEqual('somefolk'); + expect(result.data.hello4.username).toEqual('somefolk'); }); }); }); From b425a16962f81b344f45d8f95adaa1410f4b2c95 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 16 Aug 2019 16:23:38 -0700 Subject: [PATCH 06/60] Fix failing tests --- spec/ParseGraphQLServer.spec.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 8d2598a594..4c329308f8 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -5417,13 +5417,11 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - objects { - someClass(objectId: $objectId) { - objectId - someArray { - ... on Element { - value - } + someClass(objectId: $objectId) { + objectId + someArray { + ... on Element { + value } } } @@ -5433,7 +5431,7 @@ describe('ParseGraphQLServer', () => { objectId: obj.id, }, }); - expect(getResult.data.objects.someClass.someArray).toEqual(null); + expect(getResult.data.someClass.someArray).toEqual(null); }); it('should support null values', async () => { From 8309a176c0d3b9bae86fa7b243ff1a9ef5b96d2e Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Sat, 17 Aug 2019 15:52:46 -0700 Subject: [PATCH 07/60] First verstion not complete of create class mutation --- src/GraphQL/ParseGraphQLSchema.js | 4 +- .../loaders/defaultGraphQLMutations.js | 2 + src/GraphQL/loaders/defaultGraphQLTypes.js | 3 + src/GraphQL/loaders/parseClassTypes.js | 150 +---------------- src/GraphQL/loaders/schemaMutations.js | 35 ++++ src/GraphQL/loaders/schemaTypes.js | 157 ++++++++++++++++++ src/GraphQL/transformers/constraintType.js | 46 +++++ src/GraphQL/transformers/inputType.js | 60 +++++++ src/GraphQL/transformers/outputType.js | 63 +++++++ 9 files changed, 377 insertions(+), 143 deletions(-) create mode 100644 src/GraphQL/loaders/schemaMutations.js create mode 100644 src/GraphQL/loaders/schemaTypes.js create mode 100644 src/GraphQL/transformers/constraintType.js create mode 100644 src/GraphQL/transformers/inputType.js create mode 100644 src/GraphQL/transformers/outputType.js diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index 6d9010a8fb..86d4cf557d 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -28,14 +28,16 @@ const RESERVED_GRAPHQL_TYPE_NAMES = [ 'Viewer', 'SignUpFieldsInput', 'LogInFieldsInput', + 'CreateClassSchemaInput', ]; const RESERVED_GRAPHQL_QUERY_NAMES = ['health', 'viewer', 'get', 'find']; const RESERVED_GRAPHQL_MUTATION_NAMES = [ 'signUp', 'logIn', 'logOut', - 'createFile', 'call', + 'createFile', + 'createClass', 'create', 'update', 'delete', diff --git a/src/GraphQL/loaders/defaultGraphQLMutations.js b/src/GraphQL/loaders/defaultGraphQLMutations.js index c7ebc6347d..87fd7135f9 100644 --- a/src/GraphQL/loaders/defaultGraphQLMutations.js +++ b/src/GraphQL/loaders/defaultGraphQLMutations.js @@ -2,12 +2,14 @@ import * as objectsMutations from './objectsMutations'; import * as filesMutations from './filesMutations'; import * as usersMutations from './usersMutations'; import * as functionsMutations from './functionsMutations'; +import * as schemaMutations from './schemaMutations'; const load = parseGraphQLSchema => { objectsMutations.load(parseGraphQLSchema); filesMutations.load(parseGraphQLSchema); usersMutations.load(parseGraphQLSchema); functionsMutations.load(parseGraphQLSchema); + schemaMutations.load(parseGraphQLSchema); }; export { load }; diff --git a/src/GraphQL/loaders/defaultGraphQLTypes.js b/src/GraphQL/loaders/defaultGraphQLTypes.js index a7f7f78806..a0df31517e 100644 --- a/src/GraphQL/loaders/defaultGraphQLTypes.js +++ b/src/GraphQL/loaders/defaultGraphQLTypes.js @@ -15,6 +15,7 @@ import { GraphQLUnionType, } from 'graphql'; import { GraphQLUpload } from 'graphql-upload'; +import * as schemaTypes from './schemaTypes'; class TypeValidationError extends Error { constructor(value, type) { @@ -1108,6 +1109,8 @@ const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(FIND_RESULT, true); parseGraphQLSchema.addGraphQLType(SIGN_UP_RESULT, true); parseGraphQLSchema.addGraphQLType(ELEMENT, true); + + schemaTypes.load(parseGraphQLSchema); }; export { diff --git a/src/GraphQL/loaders/parseClassTypes.js b/src/GraphQL/loaders/parseClassTypes.js index fb1de5bf30..1346a97aaf 100644 --- a/src/GraphQL/loaders/parseClassTypes.js +++ b/src/GraphQL/loaders/parseClassTypes.js @@ -2,8 +2,6 @@ import { Kind, GraphQLObjectType, GraphQLString, - GraphQLFloat, - GraphQLBoolean, GraphQLList, GraphQLInputObjectType, GraphQLNonNull, @@ -16,141 +14,9 @@ import * as objectsQueries from './objectsQueries'; import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController'; import { transformClassNameToGraphQL } from '../transformers/className'; import { extractKeysAndInclude } from '../parseGraphQLUtils'; - -const mapInputType = (parseType, targetClass, parseClassTypes) => { - switch (parseType) { - case 'String': - return GraphQLString; - case 'Number': - return GraphQLFloat; - case 'Boolean': - return GraphQLBoolean; - case 'Array': - return new GraphQLList(defaultGraphQLTypes.ANY); - case 'Object': - return defaultGraphQLTypes.OBJECT; - case 'Date': - return defaultGraphQLTypes.DATE; - case 'Pointer': - if ( - parseClassTypes[targetClass] && - parseClassTypes[targetClass].classGraphQLScalarType - ) { - return parseClassTypes[targetClass].classGraphQLScalarType; - } else { - return defaultGraphQLTypes.OBJECT; - } - case 'Relation': - if ( - parseClassTypes[targetClass] && - parseClassTypes[targetClass].classGraphQLRelationOpType - ) { - return parseClassTypes[targetClass].classGraphQLRelationOpType; - } else { - return defaultGraphQLTypes.OBJECT; - } - case 'File': - return defaultGraphQLTypes.FILE; - case 'GeoPoint': - return defaultGraphQLTypes.GEO_POINT_INPUT; - case 'Polygon': - return defaultGraphQLTypes.POLYGON_INPUT; - case 'Bytes': - return defaultGraphQLTypes.BYTES; - case 'ACL': - return defaultGraphQLTypes.OBJECT; - default: - return undefined; - } -}; - -const mapOutputType = (parseType, targetClass, parseClassTypes) => { - switch (parseType) { - case 'String': - return GraphQLString; - case 'Number': - return GraphQLFloat; - case 'Boolean': - return GraphQLBoolean; - case 'Array': - return new GraphQLList(defaultGraphQLTypes.ARRAY_RESULT); - case 'Object': - return defaultGraphQLTypes.OBJECT; - case 'Date': - return defaultGraphQLTypes.DATE; - case 'Pointer': - if ( - parseClassTypes[targetClass] && - parseClassTypes[targetClass].classGraphQLOutputType - ) { - return parseClassTypes[targetClass].classGraphQLOutputType; - } else { - return defaultGraphQLTypes.OBJECT; - } - case 'Relation': - if ( - parseClassTypes[targetClass] && - parseClassTypes[targetClass].classGraphQLFindResultType - ) { - return new GraphQLNonNull( - parseClassTypes[targetClass].classGraphQLFindResultType - ); - } else { - return new GraphQLNonNull(defaultGraphQLTypes.FIND_RESULT); - } - case 'File': - return defaultGraphQLTypes.FILE_INFO; - case 'GeoPoint': - return defaultGraphQLTypes.GEO_POINT; - case 'Polygon': - return defaultGraphQLTypes.POLYGON; - case 'Bytes': - return defaultGraphQLTypes.BYTES; - case 'ACL': - return defaultGraphQLTypes.OBJECT; - default: - return undefined; - } -}; - -const mapConstraintType = (parseType, targetClass, parseClassTypes) => { - switch (parseType) { - case 'String': - return defaultGraphQLTypes.STRING_WHERE_INPUT; - case 'Number': - return defaultGraphQLTypes.NUMBER_WHERE_INPUT; - case 'Boolean': - return defaultGraphQLTypes.BOOLEAN_WHERE_INPUT; - case 'Array': - return defaultGraphQLTypes.ARRAY_WHERE_INPUT; - case 'Object': - return defaultGraphQLTypes.OBJECT_WHERE_INPUT; - case 'Date': - return defaultGraphQLTypes.DATE_WHERE_INPUT; - case 'Pointer': - if ( - parseClassTypes[targetClass] && - parseClassTypes[targetClass].classGraphQLConstraintType - ) { - return parseClassTypes[targetClass].classGraphQLConstraintType; - } else { - return defaultGraphQLTypes.OBJECT; - } - case 'File': - return defaultGraphQLTypes.FILE_WHERE_INPUT; - case 'GeoPoint': - return defaultGraphQLTypes.GEO_POINT_WHERE_INPUT; - case 'Polygon': - return defaultGraphQLTypes.POLYGON_WHERE_INPUT; - case 'Bytes': - return defaultGraphQLTypes.BYTES_WHERE_INPUT; - case 'ACL': - return defaultGraphQLTypes.OBJECT_WHERE_INPUT; - case 'Relation': - default: - return undefined; - } -}; +import { transformInputTypeToGraphQL } from '../transformers/inputType'; +import { transformOutputTypeToGraphQL } from '../transformers/inputType'; +import { transformConstraintTypeToGraphQL } from '../transformers/inputType'; const getParseClassTypeConfig = function( parseClassConfig: ?ParseGraphQLClassConfig @@ -371,7 +237,7 @@ const load = ( fields: () => classCreateFields.reduce( (fields, field) => { - const type = mapInputType( + const type = transformInputTypeToGraphQL( parseClass.fields[field].type, parseClass.fields[field].targetClass, parseGraphQLSchema.parseClassTypes @@ -404,7 +270,7 @@ const load = ( fields: () => classUpdateFields.reduce( (fields, field) => { - const type = mapInputType( + const type = transformInputTypeToGraphQL( parseClass.fields[field].type, parseClass.fields[field].targetClass, parseGraphQLSchema.parseClassTypes @@ -464,7 +330,7 @@ const load = ( description: `The ${classGraphQLConstraintsTypeName} input type is used in operations that involve filtering objects of ${graphQLClassName} class.`, fields: () => ({ ...classConstraintFields.reduce((fields, field) => { - const type = mapConstraintType( + const type = transformConstraintTypeToGraphQL( parseClass.fields[field].type, parseClass.fields[field].targetClass, parseGraphQLSchema.parseClassTypes @@ -543,7 +409,7 @@ const load = ( const classGraphQLOutputTypeName = `${graphQLClassName}`; const outputFields = () => { return classOutputFields.reduce((fields, field) => { - const type = mapOutputType( + const type = transformOutputTypeToGraphQL( parseClass.fields[field].type, parseClass.fields[field].targetClass, parseGraphQLSchema.parseClassTypes @@ -730,7 +596,7 @@ const load = ( description: `The ${userSignUpInputTypeName} input type is used in operations that involve inputting objects of ${graphQLClassName} class when signing up.`, fields: () => classCreateFields.reduce((fields, field) => { - const type = mapInputType( + const type = transformInputTypeToGraphQL( parseClass.fields[field].type, parseClass.fields[field].targetClass, parseGraphQLSchema.parseClassTypes diff --git a/src/GraphQL/loaders/schemaMutations.js b/src/GraphQL/loaders/schemaMutations.js new file mode 100644 index 0000000000..075220ec16 --- /dev/null +++ b/src/GraphQL/loaders/schemaMutations.js @@ -0,0 +1,35 @@ +import { GraphQLNonNull, GraphQLInputObjectType, GraphQLList } from 'graphql'; +import * as defaultGraphQLTypes from './defaultGraphQLTypes'; +import * as schemaTypes from './schemaTypes'; + +const load = parseGraphQLSchema => { + parseGraphQLSchema.addGraphQLMutation('createClass', { + description: + 'The createClass mutation can be used to create the schema for a new object class.', + args: { + className: defaultGraphQLTypes.CLASS_NAME_ATT, + schema: { + description: 'This is the schema for the class', + type: parseGraphQLSchema.addGraphQLType( + new GraphQLInputObjectType({ + name: 'CreateClassSchemaInput', + description: `The CreateClassSchemaInput type is used to specify the schema for a new object class to be created.`, + fields: { + stringFields: { + description: + 'These are the String fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull(schemaTypes.SCHEMA_STRING_FIELD_INPUT) + ), + }, + }, + }), + true, + true + ), + }, + }, + }); +}; + +export { load }; diff --git a/src/GraphQL/loaders/schemaTypes.js b/src/GraphQL/loaders/schemaTypes.js new file mode 100644 index 0000000000..d2533fd9e2 --- /dev/null +++ b/src/GraphQL/loaders/schemaTypes.js @@ -0,0 +1,157 @@ +import { + GraphQLNonNull, + GraphQLString, + GraphQLBoolean, + GraphQLInputObjectType, +} from 'graphql'; +import { transformInputTypeToGraphQL } from '../transformers/inputType'; + +const SCHEMA_FIELD_NAME_ATT = { + description: 'This is the field name.', + type: new GraphQLNonNull(GraphQLString), +}; + +const SCHEMA_FIELD_IS_REQUIRED_ATT = { + description: + 'This is the flag to specify whether the field is required or not.', + type: GraphQLBoolean, +}; + +const SCHEMA_STRING_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaStringFieldInput', + description: + 'The SchemaStringFieldInput is used to specify a field of type string for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('String'), + }, +}); + +const SCHEMA_NUMBER_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaNumberFieldInput', + description: + 'The SchemaNumberFieldInput is used to specify a field of type number for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('Number'), + }, +}); + +const SCHEMA_BOOLEAN_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaBooleanFieldInput', + description: + 'The SchemaBooleanFieldInput is used to specify a field of type boolean for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('Booleam'), + }, +}); + +const SCHEMA_ARRAY_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaArrayFieldInput', + description: + 'The SchemaArrayFieldInput is used to specify a field of type array for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('Array'), + }, +}); + +const SCHEMA_OBJECT_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaObjectFieldInput', + description: + 'The SchemaObjectFieldInput is used to specify a field of type object for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('Object'), + }, +}); + +const SCHEMA_DATE_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaDateFieldInput', + description: + 'The SchemaDateFieldInput is used to specify a field of type date for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('Date'), + }, +}); + +const SCHEMA_FILE_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaFileFieldInput', + description: + 'The SchemaFileFieldInput is used to specify a field of type file for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('File'), + }, +}); + +const SCHEMA_GEO_POINT_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaGeoPointFieldInput', + description: + 'The SchemaGeoPointFieldInput is used to specify a field of type geo point for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('GeoPoint'), + }, +}); + +const SCHEMA_POLYGON_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaPolygonFieldInput', + description: + 'The SchemaPolygonFieldInput is used to specify a field of type polygon for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('Polygon'), + }, +}); + +const SCHEMA_BYTES_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaBytesFieldInput', + description: + 'The SchemaBytesFieldInput is used to specify a field of type bytes for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: transformInputTypeToGraphQL('Bytes'), + }, +}); + +const load = parseGraphQLSchema => { + parseGraphQLSchema.addGraphQLType(SCHEMA_STRING_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_NUMBER_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_BOOLEAN_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_ARRAY_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_OBJECT_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_DATE_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_FILE_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_GEO_POINT_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_POLYGON_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_BYTES_FIELD_INPUT, true); +}; + +export { + SCHEMA_FIELD_NAME_ATT, + SCHEMA_FIELD_IS_REQUIRED_ATT, + SCHEMA_STRING_FIELD_INPUT, + SCHEMA_NUMBER_FIELD_INPUT, + SCHEMA_BOOLEAN_FIELD_INPUT, + SCHEMA_ARRAY_FIELD_INPUT, + SCHEMA_OBJECT_FIELD_INPUT, + SCHEMA_DATE_FIELD_INPUT, + SCHEMA_FILE_FIELD_INPUT, + SCHEMA_GEO_POINT_FIELD_INPUT, + SCHEMA_POLYGON_FIELD_INPUT, + SCHEMA_BYTES_FIELD_INPUT, + load, +}; diff --git a/src/GraphQL/transformers/constraintType.js b/src/GraphQL/transformers/constraintType.js new file mode 100644 index 0000000000..83c4e4b264 --- /dev/null +++ b/src/GraphQL/transformers/constraintType.js @@ -0,0 +1,46 @@ +import * as defaultGraphQLTypes from '../loaders/defaultGraphQLTypes'; + +const transformConstraintTypeToGraphQL = ( + parseType, + targetClass, + parseClassTypes +) => { + switch (parseType) { + case 'String': + return defaultGraphQLTypes.STRING_WHERE_INPUT; + case 'Number': + return defaultGraphQLTypes.NUMBER_WHERE_INPUT; + case 'Boolean': + return defaultGraphQLTypes.BOOLEAN_WHERE_INPUT; + case 'Array': + return defaultGraphQLTypes.ARRAY_WHERE_INPUT; + case 'Object': + return defaultGraphQLTypes.OBJECT_WHERE_INPUT; + case 'Date': + return defaultGraphQLTypes.DATE_WHERE_INPUT; + case 'Pointer': + if ( + parseClassTypes[targetClass] && + parseClassTypes[targetClass].classGraphQLConstraintType + ) { + return parseClassTypes[targetClass].classGraphQLConstraintType; + } else { + return defaultGraphQLTypes.OBJECT; + } + case 'File': + return defaultGraphQLTypes.FILE_WHERE_INPUT; + case 'GeoPoint': + return defaultGraphQLTypes.GEO_POINT_WHERE_INPUT; + case 'Polygon': + return defaultGraphQLTypes.POLYGON_WHERE_INPUT; + case 'Bytes': + return defaultGraphQLTypes.BYTES_WHERE_INPUT; + case 'ACL': + return defaultGraphQLTypes.OBJECT_WHERE_INPUT; + case 'Relation': + default: + return undefined; + } +}; + +export { transformConstraintTypeToGraphQL }; diff --git a/src/GraphQL/transformers/inputType.js b/src/GraphQL/transformers/inputType.js new file mode 100644 index 0000000000..d94106ecc2 --- /dev/null +++ b/src/GraphQL/transformers/inputType.js @@ -0,0 +1,60 @@ +import { + GraphQLString, + GraphQLFloat, + GraphQLBoolean, + GraphQLList, +} from 'graphql'; +import * as defaultGraphQLTypes from '../loaders/defaultGraphQLTypes'; + +const transformInputTypeToGraphQL = ( + parseType, + targetClass, + parseClassTypes +) => { + switch (parseType) { + case 'String': + return GraphQLString; + case 'Number': + return GraphQLFloat; + case 'Boolean': + return GraphQLBoolean; + case 'Array': + return new GraphQLList(defaultGraphQLTypes.ANY); + case 'Object': + return defaultGraphQLTypes.OBJECT; + case 'Date': + return defaultGraphQLTypes.DATE; + case 'Pointer': + if ( + parseClassTypes[targetClass] && + parseClassTypes[targetClass].classGraphQLScalarType + ) { + return parseClassTypes[targetClass].classGraphQLScalarType; + } else { + return defaultGraphQLTypes.OBJECT; + } + case 'Relation': + if ( + parseClassTypes[targetClass] && + parseClassTypes[targetClass].classGraphQLRelationOpType + ) { + return parseClassTypes[targetClass].classGraphQLRelationOpType; + } else { + return defaultGraphQLTypes.OBJECT; + } + case 'File': + return defaultGraphQLTypes.FILE; + case 'GeoPoint': + return defaultGraphQLTypes.GEO_POINT_INPUT; + case 'Polygon': + return defaultGraphQLTypes.POLYGON_INPUT; + case 'Bytes': + return defaultGraphQLTypes.BYTES; + case 'ACL': + return defaultGraphQLTypes.OBJECT; + default: + return undefined; + } +}; + +export { transformInputTypeToGraphQL }; diff --git a/src/GraphQL/transformers/outputType.js b/src/GraphQL/transformers/outputType.js new file mode 100644 index 0000000000..eedebbe7f6 --- /dev/null +++ b/src/GraphQL/transformers/outputType.js @@ -0,0 +1,63 @@ +import * as defaultGraphQLTypes from '../loaders/defaultGraphQLTypes'; +import { + GraphQLString, + GraphQLFloat, + GraphQLBoolean, + GraphQLList, + GraphQLNonNull, +} from 'graphql'; + +const transformOutputTypeToGraphQL = ( + parseType, + targetClass, + parseClassTypes +) => { + switch (parseType) { + case 'String': + return GraphQLString; + case 'Number': + return GraphQLFloat; + case 'Boolean': + return GraphQLBoolean; + case 'Array': + return new GraphQLList(defaultGraphQLTypes.ARRAY_RESULT); + case 'Object': + return defaultGraphQLTypes.OBJECT; + case 'Date': + return defaultGraphQLTypes.DATE; + case 'Pointer': + if ( + parseClassTypes[targetClass] && + parseClassTypes[targetClass].classGraphQLOutputType + ) { + return parseClassTypes[targetClass].classGraphQLOutputType; + } else { + return defaultGraphQLTypes.OBJECT; + } + case 'Relation': + if ( + parseClassTypes[targetClass] && + parseClassTypes[targetClass].classGraphQLFindResultType + ) { + return new GraphQLNonNull( + parseClassTypes[targetClass].classGraphQLFindResultType + ); + } else { + return new GraphQLNonNull(defaultGraphQLTypes.FIND_RESULT); + } + case 'File': + return defaultGraphQLTypes.FILE_INFO; + case 'GeoPoint': + return defaultGraphQLTypes.GEO_POINT; + case 'Polygon': + return defaultGraphQLTypes.POLYGON; + case 'Bytes': + return defaultGraphQLTypes.BYTES; + case 'ACL': + return defaultGraphQLTypes.OBJECT; + default: + return undefined; + } +}; + +export { transformOutputTypeToGraphQL }; From df58387ee8b5894877680a889582e6a41ce39244 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 21 Aug 2019 17:49:56 -0700 Subject: [PATCH 08/60] Fix bug caused by circular dependency --- src/GraphQL/ParseGraphQLSchema.js | 2 ++ src/GraphQL/loaders/defaultGraphQLTypes.js | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index 86d4cf557d..e8da2ffef6 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -14,6 +14,7 @@ import ParseGraphQLController, { import DatabaseController from '../Controllers/DatabaseController'; import { toGraphQLError } from './parseGraphQLUtils'; import * as schemaDirectives from './loaders/schemaDirectives'; +import * as schemaTypes from './loaders/schemaTypes'; const RESERVED_GRAPHQL_TYPE_NAMES = [ 'String', @@ -109,6 +110,7 @@ class ParseGraphQLSchema { ); defaultGraphQLTypes.loadArrayResult(this, parseClasses); + schemaTypes.load(this); defaultGraphQLQueries.load(this); defaultGraphQLMutations.load(this); diff --git a/src/GraphQL/loaders/defaultGraphQLTypes.js b/src/GraphQL/loaders/defaultGraphQLTypes.js index a0df31517e..a7f7f78806 100644 --- a/src/GraphQL/loaders/defaultGraphQLTypes.js +++ b/src/GraphQL/loaders/defaultGraphQLTypes.js @@ -15,7 +15,6 @@ import { GraphQLUnionType, } from 'graphql'; import { GraphQLUpload } from 'graphql-upload'; -import * as schemaTypes from './schemaTypes'; class TypeValidationError extends Error { constructor(value, type) { @@ -1109,8 +1108,6 @@ const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(FIND_RESULT, true); parseGraphQLSchema.addGraphQLType(SIGN_UP_RESULT, true); parseGraphQLSchema.addGraphQLType(ELEMENT, true); - - schemaTypes.load(parseGraphQLSchema); }; export { From 0904762606616d530de968c635f8e37298a6493a Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 21 Aug 2019 18:17:29 -0700 Subject: [PATCH 09/60] Renaming files --- src/GraphQL/ParseGraphQLSchema.js | 5 ++--- .../loaders/{schemaMutations.js => classSchemaMutations.js} | 4 ++-- src/GraphQL/loaders/{schemaTypes.js => classSchemaTypes.js} | 0 src/GraphQL/loaders/defaultGraphQLMutations.js | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) rename src/GraphQL/loaders/{schemaMutations.js => classSchemaMutations.js} (88%) rename src/GraphQL/loaders/{schemaTypes.js => classSchemaTypes.js} (100%) diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index ad72f1d03c..8cf6f30600 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -14,7 +14,7 @@ import ParseGraphQLController, { import DatabaseController from '../Controllers/DatabaseController'; import { toGraphQLError } from './parseGraphQLUtils'; import * as schemaDirectives from './loaders/schemaDirectives'; -import * as schemaTypes from './loaders/schemaTypes'; +import * as classSchemaTypes from './loaders/classSchemaTypes'; const RESERVED_GRAPHQL_TYPE_NAMES = [ 'String', @@ -32,7 +32,6 @@ const RESERVED_GRAPHQL_TYPE_NAMES = [ 'CreateClassSchemaInput', ]; const RESERVED_GRAPHQL_QUERY_NAMES = ['health', 'viewer', 'get', 'find']; - const RESERVED_GRAPHQL_MUTATION_NAMES = [ 'signUp', 'logIn', @@ -111,7 +110,7 @@ class ParseGraphQLSchema { ); defaultGraphQLTypes.loadArrayResult(this, parseClasses); - schemaTypes.load(this); + classSchemaTypes.load(this); defaultGraphQLQueries.load(this); defaultGraphQLMutations.load(this); diff --git a/src/GraphQL/loaders/schemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js similarity index 88% rename from src/GraphQL/loaders/schemaMutations.js rename to src/GraphQL/loaders/classSchemaMutations.js index 075220ec16..4a5587adbd 100644 --- a/src/GraphQL/loaders/schemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -1,6 +1,6 @@ import { GraphQLNonNull, GraphQLInputObjectType, GraphQLList } from 'graphql'; import * as defaultGraphQLTypes from './defaultGraphQLTypes'; -import * as schemaTypes from './schemaTypes'; +import * as classSchemaTypes from './classSchemaTypes'; const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLMutation('createClass', { @@ -19,7 +19,7 @@ const load = parseGraphQLSchema => { description: 'These are the String fields to be added to the new class', type: new GraphQLList( - new GraphQLNonNull(schemaTypes.SCHEMA_STRING_FIELD_INPUT) + new GraphQLNonNull(classSchemaTypes.SCHEMA_STRING_FIELD_INPUT) ), }, }, diff --git a/src/GraphQL/loaders/schemaTypes.js b/src/GraphQL/loaders/classSchemaTypes.js similarity index 100% rename from src/GraphQL/loaders/schemaTypes.js rename to src/GraphQL/loaders/classSchemaTypes.js diff --git a/src/GraphQL/loaders/defaultGraphQLMutations.js b/src/GraphQL/loaders/defaultGraphQLMutations.js index 87fd7135f9..e14e2daa3f 100644 --- a/src/GraphQL/loaders/defaultGraphQLMutations.js +++ b/src/GraphQL/loaders/defaultGraphQLMutations.js @@ -2,14 +2,14 @@ import * as objectsMutations from './objectsMutations'; import * as filesMutations from './filesMutations'; import * as usersMutations from './usersMutations'; import * as functionsMutations from './functionsMutations'; -import * as schemaMutations from './schemaMutations'; +import * as classSchemaMutations from './classSchemaMutations'; const load = parseGraphQLSchema => { objectsMutations.load(parseGraphQLSchema); filesMutations.load(parseGraphQLSchema); usersMutations.load(parseGraphQLSchema); functionsMutations.load(parseGraphQLSchema); - schemaMutations.load(parseGraphQLSchema); + classSchemaMutations.load(parseGraphQLSchema); }; export { load }; From 886458ad7439942ea7d18631e11c235647c2d34e Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 21 Aug 2019 18:24:38 -0700 Subject: [PATCH 10/60] Schema types should be loaded before parse classes --- src/GraphQL/ParseGraphQLSchema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index 8cf6f30600..2c503da440 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -100,6 +100,7 @@ class ParseGraphQLSchema { this.graphQLSchemaDirectives = {}; defaultGraphQLTypes.load(this); + classSchemaTypes.load(this); this._getParseClassesWithConfig(parseClasses, parseGraphQLConfig).forEach( ([parseClass, parseClassConfig]) => { @@ -110,7 +111,6 @@ class ParseGraphQLSchema { ); defaultGraphQLTypes.loadArrayResult(this, parseClasses); - classSchemaTypes.load(this); defaultGraphQLQueries.load(this); defaultGraphQLMutations.load(this); From e7fe2e8aa54e28d6dd3bf5571e5ac9e78407067a Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 23 Aug 2019 14:29:39 -0700 Subject: [PATCH 11/60] Fix tests --- src/GraphQL/loaders/classSchemaTypes.js | 50 ++++++++++++++++++++----- src/GraphQL/loaders/parseClassTypes.js | 4 +- src/GraphQL/transformers/inputType.js | 8 ++-- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/GraphQL/loaders/classSchemaTypes.js b/src/GraphQL/loaders/classSchemaTypes.js index d2533fd9e2..26705ade12 100644 --- a/src/GraphQL/loaders/classSchemaTypes.js +++ b/src/GraphQL/loaders/classSchemaTypes.js @@ -24,7 +24,10 @@ const SCHEMA_STRING_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('String'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('String'), + }, }, }); @@ -35,7 +38,10 @@ const SCHEMA_NUMBER_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('Number'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('Number'), + }, }, }); @@ -46,7 +52,10 @@ const SCHEMA_BOOLEAN_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('Booleam'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('Boolean'), + }, }, }); @@ -57,7 +66,10 @@ const SCHEMA_ARRAY_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('Array'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('Array'), + }, }, }); @@ -68,7 +80,10 @@ const SCHEMA_OBJECT_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('Object'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('Object'), + }, }, }); @@ -79,7 +94,10 @@ const SCHEMA_DATE_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('Date'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('Date'), + }, }, }); @@ -90,7 +108,10 @@ const SCHEMA_FILE_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('File'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('File'), + }, }, }); @@ -101,7 +122,10 @@ const SCHEMA_GEO_POINT_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('GeoPoint'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('GeoPoint'), + }, }, }); @@ -112,7 +136,10 @@ const SCHEMA_POLYGON_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('Polygon'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('Polygon'), + }, }, }); @@ -123,7 +150,10 @@ const SCHEMA_BYTES_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: transformInputTypeToGraphQL('Bytes'), + defaultValue: { + description: 'This is the field default value.', + type: transformInputTypeToGraphQL('Bytes'), + }, }, }); diff --git a/src/GraphQL/loaders/parseClassTypes.js b/src/GraphQL/loaders/parseClassTypes.js index 57aac5970e..226d2ebd9d 100644 --- a/src/GraphQL/loaders/parseClassTypes.js +++ b/src/GraphQL/loaders/parseClassTypes.js @@ -14,8 +14,8 @@ import * as objectsQueries from './objectsQueries'; import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController'; import { transformClassNameToGraphQL } from '../transformers/className'; import { transformInputTypeToGraphQL } from '../transformers/inputType'; -import { transformOutputTypeToGraphQL } from '../transformers/inputType'; -import { transformConstraintTypeToGraphQL } from '../transformers/inputType'; +import { transformOutputTypeToGraphQL } from '../transformers/outputType'; +import { transformConstraintTypeToGraphQL } from '../transformers/constraintType'; import { extractKeysAndInclude, getParseClassMutationConfig, diff --git a/src/GraphQL/transformers/inputType.js b/src/GraphQL/transformers/inputType.js index d94106ecc2..e059c28406 100644 --- a/src/GraphQL/transformers/inputType.js +++ b/src/GraphQL/transformers/inputType.js @@ -27,18 +27,18 @@ const transformInputTypeToGraphQL = ( case 'Pointer': if ( parseClassTypes[targetClass] && - parseClassTypes[targetClass].classGraphQLScalarType + parseClassTypes[targetClass].classGraphQLPointerType ) { - return parseClassTypes[targetClass].classGraphQLScalarType; + return parseClassTypes[targetClass].classGraphQLPointerType; } else { return defaultGraphQLTypes.OBJECT; } case 'Relation': if ( parseClassTypes[targetClass] && - parseClassTypes[targetClass].classGraphQLRelationOpType + parseClassTypes[targetClass].classGraphQLRelationType ) { - return parseClassTypes[targetClass].classGraphQLRelationOpType; + return parseClassTypes[targetClass].classGraphQLRelationType; } else { return defaultGraphQLTypes.OBJECT; } From d948762c250101acd8a1641723c6a6bcc1f898ad Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 23 Aug 2019 16:34:40 -0700 Subject: [PATCH 12/60] Create class mutation boilerplate --- spec/ParseGraphQLServer.spec.js | 20 +++-- src/GraphQL/loaders/classSchemaMutations.js | 86 ++++++++++++++++++++- 2 files changed, 97 insertions(+), 9 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index c6dffacba0..d0cefb900f 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -447,14 +447,18 @@ describe('ParseGraphQLServer', () => { describe('GraphQL', () => { it('should be healthy', async () => { - const health = (await apolloClient.query({ - query: gql` - query Health { - health - } - `, - })).data.health; - expect(health).toBeTruthy(); + try { + const health = (await apolloClient.query({ + query: gql` + query Health { + health + } + `, + })).data.health; + expect(health).toBeTruthy(); + } catch (e) { + fail(e.networkError.result.errors); + } }); it('should be cors enabled', async () => { diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js index ec27bba328..18632bfece 100644 --- a/src/GraphQL/loaders/classSchemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -1,4 +1,9 @@ -import { GraphQLNonNull, GraphQLInputObjectType, GraphQLList } from 'graphql'; +import { + GraphQLNonNull, + GraphQLInputObjectType, + GraphQLList, + GraphQLBoolean, +} from 'graphql'; import * as defaultGraphQLTypes from './defaultGraphQLTypes'; import * as classSchemaTypes from './classSchemaTypes'; @@ -26,6 +31,83 @@ const load = parseGraphQLSchema => { ) ), }, + numberFields: { + description: + 'These are the Number fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull( + classSchemaTypes.SCHEMA_NUMBER_FIELD_INPUT + ) + ), + }, + booleanFields: { + description: + 'These are the Boolean fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull( + classSchemaTypes.SCHEMA_BOOLEAN_FIELD_INPUT + ) + ), + }, + arrayFields: { + description: + 'These are the Array fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull( + classSchemaTypes.SCHEMA_ARRAY_FIELD_INPUT + ) + ), + }, + objectFields: { + description: + 'These are the Object fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull( + classSchemaTypes.SCHEMA_OBJECT_FIELD_INPUT + ) + ), + }, + dateFields: { + description: + 'These are the Date fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull(classSchemaTypes.SCHEMA_DATE_FIELD_INPUT) + ), + }, + fileFields: { + description: + 'These are the File fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull(classSchemaTypes.SCHEMA_FILE_FIELD_INPUT) + ), + }, + geoPointFields: { + description: + 'These are the Geo Point fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull( + classSchemaTypes.SCHEMA_GEO_POINT_FIELD_INPUT + ) + ), + }, + polygonFields: { + description: + 'These are the Polygon fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull( + classSchemaTypes.SCHEMA_POLYGON_FIELD_INPUT + ) + ), + }, + bytesFields: { + description: + 'These are the Bytes fields to be added to the new class', + type: new GraphQLList( + new GraphQLNonNull( + classSchemaTypes.SCHEMA_BYTES_FIELD_INPUT + ) + ), + }, }, }), true, @@ -33,6 +115,8 @@ const load = parseGraphQLSchema => { ), }, }, + type: new GraphQLNonNull(GraphQLBoolean), + resolve: () => true, }, true, true From ab4004decc32e873c3f8c74caf788d14e3cd9f21 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 23 Aug 2019 17:26:31 -0700 Subject: [PATCH 13/60] Improve CreateClassSchemaInput fields names --- src/GraphQL/loaders/classSchemaMutations.js | 49 +++++++++++---------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js index 18632bfece..322043b2ee 100644 --- a/src/GraphQL/loaders/classSchemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -3,8 +3,8 @@ import { GraphQLInputObjectType, GraphQLList, GraphQLBoolean, + GraphQLString, } from 'graphql'; -import * as defaultGraphQLTypes from './defaultGraphQLTypes'; import * as classSchemaTypes from './classSchemaTypes'; const load = parseGraphQLSchema => { @@ -14,94 +14,97 @@ const load = parseGraphQLSchema => { description: 'The createClass mutation can be used to create the schema for a new object class.', args: { - className: defaultGraphQLTypes.CLASS_NAME_ATT, + name: { + description: 'This is the name of the object class.', + type: new GraphQLNonNull(GraphQLString), + }, schema: { - description: 'This is the schema for the class', + description: 'This is the schema of the object class.', type: parseGraphQLSchema.addGraphQLType( new GraphQLInputObjectType({ name: 'CreateClassSchemaInput', description: `The CreateClassSchemaInput type is used to specify the schema for a new object class to be created.`, fields: { - stringFields: { + addStringFields: { description: - 'These are the String fields to be added to the new class', + 'These are the String fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull( classSchemaTypes.SCHEMA_STRING_FIELD_INPUT ) ), }, - numberFields: { + addNumberFields: { description: - 'These are the Number fields to be added to the new class', + 'These are the Number fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull( classSchemaTypes.SCHEMA_NUMBER_FIELD_INPUT ) ), }, - booleanFields: { + addBooleanFields: { description: - 'These are the Boolean fields to be added to the new class', + 'These are the Boolean fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull( classSchemaTypes.SCHEMA_BOOLEAN_FIELD_INPUT ) ), }, - arrayFields: { + addArrayFields: { description: - 'These are the Array fields to be added to the new class', + 'These are the Array fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull( classSchemaTypes.SCHEMA_ARRAY_FIELD_INPUT ) ), }, - objectFields: { + addObjectFields: { description: - 'These are the Object fields to be added to the new class', + 'These are the Object fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull( classSchemaTypes.SCHEMA_OBJECT_FIELD_INPUT ) ), }, - dateFields: { + addDateFields: { description: - 'These are the Date fields to be added to the new class', + 'These are the Date fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull(classSchemaTypes.SCHEMA_DATE_FIELD_INPUT) ), }, - fileFields: { + addFileFields: { description: - 'These are the File fields to be added to the new class', + 'These are the File fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull(classSchemaTypes.SCHEMA_FILE_FIELD_INPUT) ), }, - geoPointFields: { + addGeoPointFields: { description: - 'These are the Geo Point fields to be added to the new class', + 'These are the Geo Point fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull( classSchemaTypes.SCHEMA_GEO_POINT_FIELD_INPUT ) ), }, - polygonFields: { + addPolygonFields: { description: - 'These are the Polygon fields to be added to the new class', + 'These are the Polygon fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull( classSchemaTypes.SCHEMA_POLYGON_FIELD_INPUT ) ), }, - bytesFields: { + addBytesFields: { description: - 'These are the Bytes fields to be added to the new class', + 'These are the Bytes fields to be added to the class schema.', type: new GraphQLList( new GraphQLNonNull( classSchemaTypes.SCHEMA_BYTES_FIELD_INPUT From 4312b2007032109419a2bd3beb5c12126bcae5bd Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Sat, 24 Aug 2019 22:08:44 -0700 Subject: [PATCH 14/60] Remove fields --- src/GraphQL/ParseGraphQLSchema.js | 1 - src/GraphQL/loaders/classSchemaMutations.js | 105 +------------------- src/GraphQL/loaders/classSchemaTypes.js | 73 ++++++++++++++ 3 files changed, 75 insertions(+), 104 deletions(-) diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index 2c503da440..c39c68105e 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -29,7 +29,6 @@ const RESERVED_GRAPHQL_TYPE_NAMES = [ 'Viewer', 'SignUpFieldsInput', 'LogInFieldsInput', - 'CreateClassSchemaInput', ]; const RESERVED_GRAPHQL_QUERY_NAMES = ['health', 'viewer', 'get', 'find']; const RESERVED_GRAPHQL_MUTATION_NAMES = [ diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js index 322043b2ee..f66c53e4c3 100644 --- a/src/GraphQL/loaders/classSchemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -1,10 +1,4 @@ -import { - GraphQLNonNull, - GraphQLInputObjectType, - GraphQLList, - GraphQLBoolean, - GraphQLString, -} from 'graphql'; +import { GraphQLNonNull, GraphQLBoolean, GraphQLString } from 'graphql'; import * as classSchemaTypes from './classSchemaTypes'; const load = parseGraphQLSchema => { @@ -20,102 +14,7 @@ const load = parseGraphQLSchema => { }, schema: { description: 'This is the schema of the object class.', - type: parseGraphQLSchema.addGraphQLType( - new GraphQLInputObjectType({ - name: 'CreateClassSchemaInput', - description: `The CreateClassSchemaInput type is used to specify the schema for a new object class to be created.`, - fields: { - addStringFields: { - description: - 'These are the String fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull( - classSchemaTypes.SCHEMA_STRING_FIELD_INPUT - ) - ), - }, - addNumberFields: { - description: - 'These are the Number fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull( - classSchemaTypes.SCHEMA_NUMBER_FIELD_INPUT - ) - ), - }, - addBooleanFields: { - description: - 'These are the Boolean fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull( - classSchemaTypes.SCHEMA_BOOLEAN_FIELD_INPUT - ) - ), - }, - addArrayFields: { - description: - 'These are the Array fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull( - classSchemaTypes.SCHEMA_ARRAY_FIELD_INPUT - ) - ), - }, - addObjectFields: { - description: - 'These are the Object fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull( - classSchemaTypes.SCHEMA_OBJECT_FIELD_INPUT - ) - ), - }, - addDateFields: { - description: - 'These are the Date fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull(classSchemaTypes.SCHEMA_DATE_FIELD_INPUT) - ), - }, - addFileFields: { - description: - 'These are the File fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull(classSchemaTypes.SCHEMA_FILE_FIELD_INPUT) - ), - }, - addGeoPointFields: { - description: - 'These are the Geo Point fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull( - classSchemaTypes.SCHEMA_GEO_POINT_FIELD_INPUT - ) - ), - }, - addPolygonFields: { - description: - 'These are the Polygon fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull( - classSchemaTypes.SCHEMA_POLYGON_FIELD_INPUT - ) - ), - }, - addBytesFields: { - description: - 'These are the Bytes fields to be added to the class schema.', - type: new GraphQLList( - new GraphQLNonNull( - classSchemaTypes.SCHEMA_BYTES_FIELD_INPUT - ) - ), - }, - }, - }), - true, - true - ), + type: classSchemaTypes.SCHEMA_INPUT, }, }, type: new GraphQLNonNull(GraphQLBoolean), diff --git a/src/GraphQL/loaders/classSchemaTypes.js b/src/GraphQL/loaders/classSchemaTypes.js index 26705ade12..82b2f224f8 100644 --- a/src/GraphQL/loaders/classSchemaTypes.js +++ b/src/GraphQL/loaders/classSchemaTypes.js @@ -3,6 +3,7 @@ import { GraphQLString, GraphQLBoolean, GraphQLInputObjectType, + GraphQLList, } from 'graphql'; import { transformInputTypeToGraphQL } from '../transformers/inputType'; @@ -17,6 +18,15 @@ const SCHEMA_FIELD_IS_REQUIRED_ATT = { type: GraphQLBoolean, }; +const SCHEMA_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'SchemaFieldInput', + description: + 'The SchemaFieldInput is used to specify a field of an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + }, +}); + const SCHEMA_STRING_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaStringFieldInput', description: @@ -157,7 +167,67 @@ const SCHEMA_BYTES_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_INPUT = new GraphQLInputObjectType({ + name: 'SchemaInput', + description: `The CreateClassSchemaInput type is used to specify the schema for a new object class to be created.`, + fields: { + addStringFields: { + description: + 'These are the String fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_STRING_FIELD_INPUT)), + }, + addNumberFields: { + description: + 'These are the Number fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_NUMBER_FIELD_INPUT)), + }, + addBooleanFields: { + description: + 'These are the Boolean fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_BOOLEAN_FIELD_INPUT)), + }, + addArrayFields: { + description: + 'These are the Array fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_ARRAY_FIELD_INPUT)), + }, + addObjectFields: { + description: + 'These are the Object fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_OBJECT_FIELD_INPUT)), + }, + addDateFields: { + description: 'These are the Date fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_DATE_FIELD_INPUT)), + }, + addFileFields: { + description: 'These are the File fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_FILE_FIELD_INPUT)), + }, + addGeoPointFields: { + description: + 'These are the Geo Point fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_GEO_POINT_FIELD_INPUT)), + }, + addPolygonFields: { + description: + 'These are the Polygon fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_POLYGON_FIELD_INPUT)), + }, + addBytesFields: { + description: + 'These are the Bytes fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_BYTES_FIELD_INPUT)), + }, + removeFields: { + description: 'These are the fields to be removed from the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_FIELD_INPUT)), + }, + }, +}); + const load = parseGraphQLSchema => { + parseGraphQLSchema.addGraphQLType(SCHEMA_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_STRING_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_NUMBER_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_BOOLEAN_FIELD_INPUT, true); @@ -168,11 +238,13 @@ const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(SCHEMA_GEO_POINT_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_POLYGON_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_BYTES_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_INPUT, true); }; export { SCHEMA_FIELD_NAME_ATT, SCHEMA_FIELD_IS_REQUIRED_ATT, + SCHEMA_FIELD_INPUT, SCHEMA_STRING_FIELD_INPUT, SCHEMA_NUMBER_FIELD_INPUT, SCHEMA_BOOLEAN_FIELD_INPUT, @@ -183,5 +255,6 @@ export { SCHEMA_GEO_POINT_FIELD_INPUT, SCHEMA_POLYGON_FIELD_INPUT, SCHEMA_BYTES_FIELD_INPUT, + SCHEMA_INPUT, load, }; From cc3665e0f36062097628c3e81ec81142dc1f4cec Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Sat, 24 Aug 2019 22:25:33 -0700 Subject: [PATCH 15/60] Pointer and relation fields --- src/GraphQL/loaders/classSchemaTypes.js | 46 +++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/GraphQL/loaders/classSchemaTypes.js b/src/GraphQL/loaders/classSchemaTypes.js index 82b2f224f8..da4968816d 100644 --- a/src/GraphQL/loaders/classSchemaTypes.js +++ b/src/GraphQL/loaders/classSchemaTypes.js @@ -5,6 +5,7 @@ import { GraphQLInputObjectType, GraphQLList, } from 'graphql'; +import * as defaultGraphQLTypes from './defaultGraphQLTypes'; import { transformInputTypeToGraphQL } from '../transformers/inputType'; const SCHEMA_FIELD_NAME_ATT = { @@ -167,6 +168,36 @@ const SCHEMA_BYTES_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const TARGET_CLASS_ATT = { + description: 'This is the name of the target class for the field.', + type: new GraphQLNonNull(GraphQLString), +}; + +const SCHEMA_POINTER_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'PointerFieldInput', + description: + 'The PointerFieldInput is used to specify a field of type pointer for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + targetClassName: TARGET_CLASS_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: defaultGraphQLTypes.POINTER_INPUT, + }, + }, +}); + +const SCHEMA_RELATION_FIELD_INPUT = new GraphQLInputObjectType({ + name: 'RelationFieldInput', + description: + 'The RelationFieldInput is used to specify a field of type relation for an object class schema.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + targetClassName: TARGET_CLASS_ATT, + }, +}); + const SCHEMA_INPUT = new GraphQLInputObjectType({ name: 'SchemaInput', description: `The CreateClassSchemaInput type is used to specify the schema for a new object class to be created.`, @@ -219,6 +250,16 @@ const SCHEMA_INPUT = new GraphQLInputObjectType({ 'These are the Bytes fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_BYTES_FIELD_INPUT)), }, + addPointerFields: { + description: + 'These are the Pointer fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_POINTER_FIELD_INPUT)), + }, + addRelationFields: { + description: + 'These are the Relation fields to be added to the class schema.', + type: new GraphQLList(new GraphQLNonNull(SCHEMA_RELATION_FIELD_INPUT)), + }, removeFields: { description: 'These are the fields to be removed from the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_FIELD_INPUT)), @@ -238,6 +279,8 @@ const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(SCHEMA_GEO_POINT_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_POLYGON_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_BYTES_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_POINTER_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_RELATION_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_INPUT, true); }; @@ -255,6 +298,9 @@ export { SCHEMA_GEO_POINT_FIELD_INPUT, SCHEMA_POLYGON_FIELD_INPUT, SCHEMA_BYTES_FIELD_INPUT, + TARGET_CLASS_ATT, + SCHEMA_POINTER_FIELD_INPUT, + SCHEMA_RELATION_FIELD_INPUT, SCHEMA_INPUT, load, }; From 7ec5a7d2278e028007dab110f04f10b6ce3b6788 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Sat, 24 Aug 2019 22:33:34 -0700 Subject: [PATCH 16/60] Improve pointer default type --- src/GraphQL/loaders/classSchemaTypes.js | 3 +-- src/GraphQL/transformers/inputType.js | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/GraphQL/loaders/classSchemaTypes.js b/src/GraphQL/loaders/classSchemaTypes.js index da4968816d..df35c07fca 100644 --- a/src/GraphQL/loaders/classSchemaTypes.js +++ b/src/GraphQL/loaders/classSchemaTypes.js @@ -5,7 +5,6 @@ import { GraphQLInputObjectType, GraphQLList, } from 'graphql'; -import * as defaultGraphQLTypes from './defaultGraphQLTypes'; import { transformInputTypeToGraphQL } from '../transformers/inputType'; const SCHEMA_FIELD_NAME_ATT = { @@ -183,7 +182,7 @@ const SCHEMA_POINTER_FIELD_INPUT = new GraphQLInputObjectType({ isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, defaultValue: { description: 'This is the field default value.', - type: defaultGraphQLTypes.POINTER_INPUT, + type: transformInputTypeToGraphQL('Pointer'), }, }, }); diff --git a/src/GraphQL/transformers/inputType.js b/src/GraphQL/transformers/inputType.js index e059c28406..5ea1161261 100644 --- a/src/GraphQL/transformers/inputType.js +++ b/src/GraphQL/transformers/inputType.js @@ -26,6 +26,7 @@ const transformInputTypeToGraphQL = ( return defaultGraphQLTypes.DATE; case 'Pointer': if ( + parseClassTypes && parseClassTypes[targetClass] && parseClassTypes[targetClass].classGraphQLPointerType ) { @@ -35,6 +36,7 @@ const transformInputTypeToGraphQL = ( } case 'Relation': if ( + parseClassTypes && parseClassTypes[targetClass] && parseClassTypes[targetClass].classGraphQLRelationType ) { From 0a51b85f55422494831ddde233b026b56b94c428 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Sun, 25 Aug 2019 23:11:53 -0700 Subject: [PATCH 17/60] Class type --- spec/ParseGraphQLServer.spec.js | 4 +- src/GraphQL/ParseGraphQLSchema.js | 2 + src/GraphQL/loaders/classSchemaMutations.js | 17 +- src/GraphQL/loaders/classSchemaTypes.js | 273 ++++++++++++++++++-- src/GraphQL/loaders/defaultGraphQLTypes.js | 16 +- src/GraphQL/loaders/parseClassTypes.js | 10 +- src/GraphQL/transformers/outputType.js | 2 + 7 files changed, 283 insertions(+), 41 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index d0cefb900f..b176197972 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -633,7 +633,7 @@ describe('ParseGraphQLServer', () => { const classType = (await apolloClient.query({ query: gql` query ClassType { - __type(name: "Class") { + __type(name: "ClassObject") { kind fields { name @@ -726,7 +726,7 @@ describe('ParseGraphQLServer', () => { })).data['__schema'].types.map(type => type.name); const expectedTypes = [ - 'Class', + 'ClassObject', 'CreateResult', 'Date', 'FileInfo', diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index c39c68105e..1747df5472 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -23,6 +23,7 @@ const RESERVED_GRAPHQL_TYPE_NAMES = [ 'Float', 'ID', 'ArrayResult', + 'SchemaArrayField', 'Query', 'Mutation', 'Subscription', @@ -110,6 +111,7 @@ class ParseGraphQLSchema { ); defaultGraphQLTypes.loadArrayResult(this, parseClasses); + classSchemaTypes.loadSchemaArrayField(this); defaultGraphQLQueries.load(this); defaultGraphQLMutations.load(this); diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js index f66c53e4c3..d81d49fb98 100644 --- a/src/GraphQL/loaders/classSchemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -1,4 +1,4 @@ -import { GraphQLNonNull, GraphQLBoolean, GraphQLString } from 'graphql'; +import { GraphQLNonNull } from 'graphql'; import * as classSchemaTypes from './classSchemaTypes'; const load = parseGraphQLSchema => { @@ -8,17 +8,14 @@ const load = parseGraphQLSchema => { description: 'The createClass mutation can be used to create the schema for a new object class.', args: { - name: { - description: 'This is the name of the object class.', - type: new GraphQLNonNull(GraphQLString), - }, - schema: { - description: 'This is the schema of the object class.', - type: classSchemaTypes.SCHEMA_INPUT, + name: classSchemaTypes.CLASS_NAME_ATT, + schemaFields: { + description: "These are the schema's fields of the object class.", + type: classSchemaTypes.SCHEMA_FIELDS_INPUT, }, }, - type: new GraphQLNonNull(GraphQLBoolean), - resolve: () => true, + type: new GraphQLNonNull(classSchemaTypes.CLASS), + resolve: () => ({}), }, true, true diff --git a/src/GraphQL/loaders/classSchemaTypes.js b/src/GraphQL/loaders/classSchemaTypes.js index df35c07fca..d11f833bc2 100644 --- a/src/GraphQL/loaders/classSchemaTypes.js +++ b/src/GraphQL/loaders/classSchemaTypes.js @@ -4,8 +4,11 @@ import { GraphQLBoolean, GraphQLInputObjectType, GraphQLList, + GraphQLObjectType, + GraphQLInterfaceType, } from 'graphql'; import { transformInputTypeToGraphQL } from '../transformers/inputType'; +import { transformOutputTypeToGraphQL } from '../transformers/outputType'; const SCHEMA_FIELD_NAME_ATT = { description: 'This is the field name.', @@ -27,6 +30,15 @@ const SCHEMA_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_FIELD = new GraphQLInterfaceType({ + name: 'SchemaField', + description: + 'The ClassObject interface type is used as a base type for the auto generated class object types.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + }, +}); + const SCHEMA_STRING_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaStringFieldInput', description: @@ -41,6 +53,21 @@ const SCHEMA_STRING_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_STRING_FIELD = new GraphQLObjectType({ + name: 'SchemaStringField', + description: + 'The SchemaStringField is used to return information of a String field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('String'), + }, + }, +}); + const SCHEMA_NUMBER_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaNumberFieldInput', description: @@ -55,6 +82,21 @@ const SCHEMA_NUMBER_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_NUMBER_FIELD = new GraphQLObjectType({ + name: 'SchemaNumberField', + description: + 'The SchemaNumberField is used to return information of a Number field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('Number'), + }, + }, +}); + const SCHEMA_BOOLEAN_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaBooleanFieldInput', description: @@ -69,6 +111,21 @@ const SCHEMA_BOOLEAN_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_BOOLEAN_FIELD = new GraphQLObjectType({ + name: 'SchemaBooleanField', + description: + 'The SchemaBooleanField is used to return information of a Boolean field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('Boolean'), + }, + }, +}); + const SCHEMA_ARRAY_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaArrayFieldInput', description: @@ -97,6 +154,21 @@ const SCHEMA_OBJECT_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_OBJECT_FIELD = new GraphQLObjectType({ + name: 'SchemaObjectField', + description: + 'The SchemaObjectField is used to return information of an Object field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('Object'), + }, + }, +}); + const SCHEMA_DATE_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaDateFieldInput', description: @@ -111,6 +183,21 @@ const SCHEMA_DATE_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_DATE_FIELD = new GraphQLObjectType({ + name: 'SchemaDateField', + description: + 'The SchemaDateField is used to return information of a Date field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('Date'), + }, + }, +}); + const SCHEMA_FILE_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaFileFieldInput', description: @@ -125,6 +212,21 @@ const SCHEMA_FILE_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_FILE_FIELD = new GraphQLObjectType({ + name: 'SchemaFileField', + description: + 'The SchemaFileField is used to return information of a File field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('File'), + }, + }, +}); + const SCHEMA_GEO_POINT_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaGeoPointFieldInput', description: @@ -139,6 +241,21 @@ const SCHEMA_GEO_POINT_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_GEO_POINT_FIELD = new GraphQLObjectType({ + name: 'SchemaGeoPointField', + description: + 'The SchemaGeoPointField is used to return information of a Geo Point field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('GeoPoint'), + }, + }, +}); + const SCHEMA_POLYGON_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaPolygonFieldInput', description: @@ -153,6 +270,21 @@ const SCHEMA_POLYGON_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_POLYGON_FIELD = new GraphQLObjectType({ + name: 'SchemaPolygonField', + description: + 'The SchemaPolygonField is used to return information of a Polygon field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('Polygon'), + }, + }, +}); + const SCHEMA_BYTES_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaBytesFieldInput', description: @@ -167,6 +299,21 @@ const SCHEMA_BYTES_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_BYTES_FIELD = new GraphQLObjectType({ + name: 'SchemaBytesField', + description: + 'The SchemaBytesField is used to return information of a Bytes field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('Bytes'), + }, + }, +}); + const TARGET_CLASS_ATT = { description: 'This is the name of the target class for the field.', type: new GraphQLNonNull(GraphQLString), @@ -187,6 +334,22 @@ const SCHEMA_POINTER_FIELD_INPUT = new GraphQLInputObjectType({ }, }); +const SCHEMA_POINTER_FIELD = new GraphQLObjectType({ + name: 'SchemaPointerField', + description: + 'The SchemaPointerField is used to return information of a Pointer field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + targetClassName: TARGET_CLASS_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('Pointer'), + }, + }, +}); + const SCHEMA_RELATION_FIELD_INPUT = new GraphQLInputObjectType({ name: 'RelationFieldInput', description: @@ -197,90 +360,151 @@ const SCHEMA_RELATION_FIELD_INPUT = new GraphQLInputObjectType({ }, }); -const SCHEMA_INPUT = new GraphQLInputObjectType({ - name: 'SchemaInput', +const SCHEMA_RELATION_FIELD = new GraphQLObjectType({ + name: 'SchemaRelationField', + description: + 'The SchemaRelationField is used to return information of a Relation field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + targetClassName: TARGET_CLASS_ATT, + }, +}); + +const SCHEMA_FIELDS_INPUT = new GraphQLInputObjectType({ + name: 'SchemaFieldsInput', description: `The CreateClassSchemaInput type is used to specify the schema for a new object class to be created.`, fields: { - addStringFields: { + addStrings: { description: 'These are the String fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_STRING_FIELD_INPUT)), }, - addNumberFields: { + addNumbers: { description: 'These are the Number fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_NUMBER_FIELD_INPUT)), }, - addBooleanFields: { + addBooleans: { description: 'These are the Boolean fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_BOOLEAN_FIELD_INPUT)), }, - addArrayFields: { + addArrays: { description: 'These are the Array fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_ARRAY_FIELD_INPUT)), }, - addObjectFields: { + addObjects: { description: 'These are the Object fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_OBJECT_FIELD_INPUT)), }, - addDateFields: { + addDates: { description: 'These are the Date fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_DATE_FIELD_INPUT)), }, - addFileFields: { + addFiles: { description: 'These are the File fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_FILE_FIELD_INPUT)), }, - addGeoPointFields: { + addGeoPoints: { description: 'These are the Geo Point fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_GEO_POINT_FIELD_INPUT)), }, - addPolygonFields: { + addPolygons: { description: 'These are the Polygon fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_POLYGON_FIELD_INPUT)), }, - addBytesFields: { + addBytes: { description: 'These are the Bytes fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_BYTES_FIELD_INPUT)), }, - addPointerFields: { + addPointers: { description: 'These are the Pointer fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_POINTER_FIELD_INPUT)), }, - addRelationFields: { + addRelations: { description: 'These are the Relation fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_RELATION_FIELD_INPUT)), }, - removeFields: { + remove: { description: 'These are the fields to be removed from the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_FIELD_INPUT)), }, }, }); +const CLASS_NAME_ATT = { + description: 'This is the name of the object class.', + type: new GraphQLNonNull(GraphQLString), +}; + +const CLASS = new GraphQLObjectType({ + name: 'Class', + description: `The Class type is used to return the information about an object class.`, + fields: { + name: CLASS_NAME_ATT, + schemaFields: { + description: "These are the schema's fields of the object class.", + type: new GraphQLNonNull( + new GraphQLList(new GraphQLNonNull(SCHEMA_FIELD)) + ), + }, + }, +}); + const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(SCHEMA_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_STRING_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_STRING_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_NUMBER_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_NUMBER_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_BOOLEAN_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_BOOLEAN_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_ARRAY_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_OBJECT_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_OBJECT_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_DATE_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_DATE_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_FILE_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_FILE_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_GEO_POINT_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_GEO_POINT_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_POLYGON_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_POLYGON_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_BYTES_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_BYTES_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_POINTER_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_POINTER_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_RELATION_FIELD_INPUT, true); - parseGraphQLSchema.addGraphQLType(SCHEMA_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_RELATION_FIELD, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_FIELDS_INPUT, true); + parseGraphQLSchema.addGraphQLType(CLASS, true); +}; + +let SCHEMA_ARRAY_FIELD; + +const loadSchemaArrayField = parseGraphQLSchema => { + SCHEMA_ARRAY_FIELD = new GraphQLObjectType({ + name: 'SchemaArrayField', + description: + 'The SchemaArrayField is used to return information of an Array field.', + fields: { + name: SCHEMA_FIELD_NAME_ATT, + isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, + defaultValue: { + description: 'This is the field default value.', + type: transformOutputTypeToGraphQL('Array'), + }, + }, + }); + parseGraphQLSchema.addGraphQLType(SCHEMA_ARRAY_FIELD, true, true); }; export { @@ -288,18 +512,33 @@ export { SCHEMA_FIELD_IS_REQUIRED_ATT, SCHEMA_FIELD_INPUT, SCHEMA_STRING_FIELD_INPUT, + SCHEMA_STRING_FIELD, SCHEMA_NUMBER_FIELD_INPUT, + SCHEMA_NUMBER_FIELD, SCHEMA_BOOLEAN_FIELD_INPUT, + SCHEMA_BOOLEAN_FIELD, SCHEMA_ARRAY_FIELD_INPUT, SCHEMA_OBJECT_FIELD_INPUT, + SCHEMA_OBJECT_FIELD, SCHEMA_DATE_FIELD_INPUT, + SCHEMA_DATE_FIELD, SCHEMA_FILE_FIELD_INPUT, + SCHEMA_FILE_FIELD, SCHEMA_GEO_POINT_FIELD_INPUT, + SCHEMA_GEO_POINT_FIELD, SCHEMA_POLYGON_FIELD_INPUT, + SCHEMA_POLYGON_FIELD, SCHEMA_BYTES_FIELD_INPUT, + SCHEMA_BYTES_FIELD, TARGET_CLASS_ATT, SCHEMA_POINTER_FIELD_INPUT, + SCHEMA_POINTER_FIELD, SCHEMA_RELATION_FIELD_INPUT, - SCHEMA_INPUT, + SCHEMA_RELATION_FIELD, + SCHEMA_FIELDS_INPUT, + CLASS_NAME_ATT, + CLASS, load, + SCHEMA_ARRAY_FIELD, + loadSchemaArrayField, }; diff --git a/src/GraphQL/loaders/defaultGraphQLTypes.js b/src/GraphQL/loaders/defaultGraphQLTypes.js index fa917d24fa..edbee7b972 100644 --- a/src/GraphQL/loaders/defaultGraphQLTypes.js +++ b/src/GraphQL/loaders/defaultGraphQLTypes.js @@ -463,17 +463,17 @@ const UPDATE_RESULT = new GraphQLObjectType({ fields: UPDATE_RESULT_FIELDS, }); -const CLASS_FIELDS = { +const CLASS_OBJECT_FIELDS = { ...CREATE_RESULT_FIELDS, ...UPDATE_RESULT_FIELDS, ...INPUT_FIELDS, }; -const CLASS = new GraphQLInterfaceType({ - name: 'Class', +const CLASS_OBJECT = new GraphQLInterfaceType({ + name: 'ClassObject', description: - 'The Class interface type is used as a base type for the auto generated class types.', - fields: CLASS_FIELDS, + 'The ClassObject interface type is used as a base type for the auto generated class object types.', + fields: CLASS_OBJECT_FIELDS, }); const SESSION_TOKEN_ATT = { @@ -1093,7 +1093,7 @@ const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(GEO_POINT, true); parseGraphQLSchema.addGraphQLType(CREATE_RESULT, true); parseGraphQLSchema.addGraphQLType(UPDATE_RESULT, true); - parseGraphQLSchema.addGraphQLType(CLASS, true); + parseGraphQLSchema.addGraphQLType(CLASS_OBJECT, true); parseGraphQLSchema.addGraphQLType(READ_PREFERENCE, true); parseGraphQLSchema.addGraphQLType(SUBQUERY_INPUT, true); parseGraphQLSchema.addGraphQLType(SELECT_INPUT, true); @@ -1156,8 +1156,8 @@ export { CREATE_RESULT, UPDATE_RESULT_FIELDS, UPDATE_RESULT, - CLASS_FIELDS, - CLASS, + CLASS_OBJECT_FIELDS, + CLASS_OBJECT, SESSION_TOKEN_ATT, KEYS_ATT, INCLUDE_ATT, diff --git a/src/GraphQL/loaders/parseClassTypes.js b/src/GraphQL/loaders/parseClassTypes.js index 226d2ebd9d..7cd3e5368a 100644 --- a/src/GraphQL/loaders/parseClassTypes.js +++ b/src/GraphQL/loaders/parseClassTypes.js @@ -47,7 +47,9 @@ const getInputFieldsAndConstraints = function( // All allowed customs fields const classCustomFields = classFields.filter(field => { - return !Object.keys(defaultGraphQLTypes.CLASS_FIELDS).includes(field); + return !Object.keys(defaultGraphQLTypes.CLASS_OBJECT_FIELDS).includes( + field + ); }); if (allowedInputFields && allowedInputFields.create) { @@ -570,12 +572,12 @@ const load = ( } else { return fields; } - }, defaultGraphQLTypes.CLASS_FIELDS); + }, defaultGraphQLTypes.CLASS_OBJECT_FIELDS); }; let classGraphQLOutputType = new GraphQLObjectType({ name: classGraphQLOutputTypeName, description: `The ${classGraphQLOutputTypeName} object type is used in operations that involve outputting objects of ${graphQLClassName} class.`, - interfaces: [defaultGraphQLTypes.CLASS], + interfaces: [defaultGraphQLTypes.CLASS_OBJECT], fields: outputFields, }); classGraphQLOutputType = parseGraphQLSchema.addGraphQLType( @@ -626,7 +628,7 @@ const load = ( const viewerType = new GraphQLObjectType({ name: 'Viewer', description: `The Viewer object type is used in operations that involve outputting the current user data.`, - interfaces: [defaultGraphQLTypes.CLASS], + interfaces: [defaultGraphQLTypes.CLASS_OBJECT], fields: () => ({ ...outputFields(), sessionToken: defaultGraphQLTypes.SESSION_TOKEN_ATT, diff --git a/src/GraphQL/transformers/outputType.js b/src/GraphQL/transformers/outputType.js index eedebbe7f6..b8382cc1f2 100644 --- a/src/GraphQL/transformers/outputType.js +++ b/src/GraphQL/transformers/outputType.js @@ -27,6 +27,7 @@ const transformOutputTypeToGraphQL = ( return defaultGraphQLTypes.DATE; case 'Pointer': if ( + parseClassTypes && parseClassTypes[targetClass] && parseClassTypes[targetClass].classGraphQLOutputType ) { @@ -36,6 +37,7 @@ const transformOutputTypeToGraphQL = ( } case 'Relation': if ( + parseClassTypes && parseClassTypes[targetClass] && parseClassTypes[targetClass].classGraphQLFindResultType ) { From 830cc597c474145edc52f6d6c7f600c8d8297337 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Sun, 25 Aug 2019 23:28:32 -0700 Subject: [PATCH 18/60] Create class mutation resolver --- src/GraphQL/loaders/classSchemaMutations.js | 29 ++++++++++++++++++++- src/GraphQL/transformers/schemaFields.js | 9 +++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/GraphQL/transformers/schemaFields.js diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js index d81d49fb98..ff106b1985 100644 --- a/src/GraphQL/loaders/classSchemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -1,5 +1,10 @@ +import Parse from 'parse/node'; import { GraphQLNonNull } from 'graphql'; import * as classSchemaTypes from './classSchemaTypes'; +import { + transformToParse, + transformToGraphQL, +} from '../transformers/schemaFields'; const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLMutation( @@ -15,7 +20,29 @@ const load = parseGraphQLSchema => { }, }, type: new GraphQLNonNull(classSchemaTypes.CLASS), - resolve: () => ({}), + resolve: async (_source, args, context) => { + try { + const { name, schemaFields } = args; + const { config, auth } = context; + + 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 }); + return transformToGraphQL( + await schema.addClassIfNotExists( + name, + transformToParse(schemaFields) + ) + ); + } catch (e) { + parseGraphQLSchema.handleError(e); + } + }, }, true, true diff --git a/src/GraphQL/transformers/schemaFields.js b/src/GraphQL/transformers/schemaFields.js new file mode 100644 index 0000000000..cd15b12bec --- /dev/null +++ b/src/GraphQL/transformers/schemaFields.js @@ -0,0 +1,9 @@ +const transformToParse = graphQLSchemaFields => { + return graphQLSchemaFields; +}; + +const transformToGraphQL = parseSchemaFields => { + return parseSchemaFields; +}; + +export { transformToParse, transformToGraphQL }; From 76224e1c21828605468f3cf8d337609a3a52850a Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 00:15:36 -0700 Subject: [PATCH 19/60] Schema field transformers --- src/GraphQL/loaders/classSchemaTypes.js | 15 +++ src/GraphQL/transformers/schemaFields.js | 124 ++++++++++++++++++++++- 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/src/GraphQL/loaders/classSchemaTypes.js b/src/GraphQL/loaders/classSchemaTypes.js index d11f833bc2..a2a0da6020 100644 --- a/src/GraphQL/loaders/classSchemaTypes.js +++ b/src/GraphQL/loaders/classSchemaTypes.js @@ -37,6 +37,21 @@ const SCHEMA_FIELD = new GraphQLInterfaceType({ fields: { name: SCHEMA_FIELD_NAME_ATT, }, + resolveType: value => + ({ + String: SCHEMA_STRING_FIELD, + Number: SCHEMA_NUMBER_FIELD, + Boolean: SCHEMA_BOOLEAN_FIELD, + Array: SCHEMA_ARRAY_FIELD, + Object: SCHEMA_OBJECT_FIELD, + Date: SCHEMA_DATE_FIELD, + File: SCHEMA_FILE_FIELD, + GeoPoint: SCHEMA_GEO_POINT_FIELD, + Polygon: SCHEMA_POLYGON_FIELD, + Bytes: SCHEMA_BYTES_FIELD, + Pointer: SCHEMA_POINTER_FIELD, + Relation: SCHEMA_RELATION_FIELD, + }[value.type]), }); const SCHEMA_STRING_FIELD_INPUT = new GraphQLInputObjectType({ diff --git a/src/GraphQL/transformers/schemaFields.js b/src/GraphQL/transformers/schemaFields.js index cd15b12bec..9de8b5732a 100644 --- a/src/GraphQL/transformers/schemaFields.js +++ b/src/GraphQL/transformers/schemaFields.js @@ -1,9 +1,129 @@ const transformToParse = graphQLSchemaFields => { - return graphQLSchemaFields; + let parseSchemaFields = {}; + + const reducerFabric = type => (parseSchemaFields, field) => { + if ( + graphQLSchemaFields.remove && + graphQLSchemaFields.remove.find( + removeField => removeField.name === field.name + ) + ) { + return parseSchemaFields; + } + if (type === 'Relation') { + return { + ...parseSchemaFields, + [field.name]: { + type, + targetClass: field.targetClassName, + }, + }; + } + if (type === 'Pointer') { + return { + ...parseSchemaFields, + [field.name]: { + type, + targetClass: field.targetClassName, + isRequired: field.isRequired, + defaultValue: field.defaultValue, + }, + }; + } + return { + ...parseSchemaFields, + [field.name]: { + type, + isRequired: field.isRequired, + defaultValue: field.defaultValue, + }, + }; + }; + + if (graphQLSchemaFields.addStrings) { + parseSchemaFields = graphQLSchemaFields.addStrings.reduce( + reducerFabric('String'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addNumbers) { + parseSchemaFields = graphQLSchemaFields.addNumbers.reduce( + reducerFabric('Number'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addBooleans) { + parseSchemaFields = graphQLSchemaFields.addBooleans.reduce( + reducerFabric('Boolean'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addArrays) { + parseSchemaFields = graphQLSchemaFields.addArrays.reduce( + reducerFabric('Array'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addObjects) { + parseSchemaFields = graphQLSchemaFields.addObjects.reduce( + reducerFabric('Object'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addDates) { + parseSchemaFields = graphQLSchemaFields.addDates.reduce( + reducerFabric('Date'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addFiles) { + parseSchemaFields = graphQLSchemaFields.addFiles.reduce( + reducerFabric('File'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addGeoPoints) { + parseSchemaFields = graphQLSchemaFields.addGeoPoints.reduce( + reducerFabric('GeoPoint'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addPolygons) { + parseSchemaFields = graphQLSchemaFields.addPolygons.reduce( + reducerFabric('Polygon'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addBytes) { + parseSchemaFields = graphQLSchemaFields.addBytes.reduce( + reducerFabric('Byte'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addPointers) { + parseSchemaFields = graphQLSchemaFields.addPointers.reduce( + reducerFabric('Pointer'), + parseSchemaFields + ); + } + if (graphQLSchemaFields.addRelations) { + parseSchemaFields = graphQLSchemaFields.addRelations.reduce( + reducerFabric('Relation'), + parseSchemaFields + ); + } + + return parseSchemaFields; }; const transformToGraphQL = parseSchemaFields => { - return parseSchemaFields; + return Object.keys(parseSchemaFields).map(name => ({ + name, + type: parseSchemaFields[name].type, + targetClass: parseSchemaFields[name].targetClass, + isRequired: parseSchemaFields[name].isRequired, + defaultValue: parseSchemaFields[name].defaultValue, + })); }; export { transformToParse, transformToGraphQL }; From 9858eb901cdae05fae8c5f951e3b89f00ef8f16f Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 00:28:26 -0700 Subject: [PATCH 20/60] Class types transformations --- src/GraphQL/loaders/classSchemaMutations.js | 12 +++++++----- src/GraphQL/loaders/classSchemaTypes.js | 13 +++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js index ff106b1985..aac0375d33 100644 --- a/src/GraphQL/loaders/classSchemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -33,12 +33,14 @@ const load = parseGraphQLSchema => { } const schema = await config.database.loadSchema({ clearCache: true }); - return transformToGraphQL( - await schema.addClassIfNotExists( - name, - transformToParse(schemaFields) - ) + const parseClass = await schema.addClassIfNotExists( + name, + transformToParse(schemaFields) ); + return { + name: parseClass.className, + schemaFields: transformToGraphQL(parseClass.fields), + }; } catch (e) { parseGraphQLSchema.handleError(e); } diff --git a/src/GraphQL/loaders/classSchemaTypes.js b/src/GraphQL/loaders/classSchemaTypes.js index a2a0da6020..42eb3ec8e4 100644 --- a/src/GraphQL/loaders/classSchemaTypes.js +++ b/src/GraphQL/loaders/classSchemaTypes.js @@ -51,6 +51,7 @@ const SCHEMA_FIELD = new GraphQLInterfaceType({ Bytes: SCHEMA_BYTES_FIELD, Pointer: SCHEMA_POINTER_FIELD, Relation: SCHEMA_RELATION_FIELD, + ACL: SCHEMA_ACL_FIELD, }[value.type]), }); @@ -386,6 +387,16 @@ const SCHEMA_RELATION_FIELD = new GraphQLObjectType({ }, }); +const SCHEMA_ACL_FIELD = new GraphQLObjectType({ + name: 'SchemaACLField', + description: + 'The SchemaACLField is used to return information of an ACL field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, + }, +}); + const SCHEMA_FIELDS_INPUT = new GraphQLInputObjectType({ name: 'SchemaFieldsInput', description: `The CreateClassSchemaInput type is used to specify the schema for a new object class to be created.`, @@ -499,6 +510,7 @@ const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(SCHEMA_POINTER_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_RELATION_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_RELATION_FIELD, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_ACL_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_FIELDS_INPUT, true); parseGraphQLSchema.addGraphQLType(CLASS, true); }; @@ -550,6 +562,7 @@ export { SCHEMA_POINTER_FIELD, SCHEMA_RELATION_FIELD_INPUT, SCHEMA_RELATION_FIELD, + SCHEMA_ACL_FIELD, SCHEMA_FIELDS_INPUT, CLASS_NAME_ATT, CLASS, From a1a49865c5273575e6b31c47e6202dcbaa9f882c Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 09:08:47 -0700 Subject: [PATCH 21/60] First test --- spec/ParseGraphQLServer.spec.js | 109 +++++++++++++---------- src/GraphQL/transformers/schemaFields.js | 4 + 2 files changed, 67 insertions(+), 46 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index b176197972..31a393b277 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -18,6 +18,19 @@ const { ParseServer } = require('../'); const { ParseGraphQLServer } = require('../lib/GraphQL/ParseGraphQLServer'); const ReadPreference = require('mongodb').ReadPreference; +function handleError(e) { + if ( + e && + e.networkError && + e.networkError.result && + e.networkError.result.errors + ) { + fail(e.networkError.result.errors); + } else { + fail(e); + } +} + describe('ParseGraphQLServer', () => { let parseServer; let parseGraphQLServer; @@ -457,7 +470,7 @@ describe('ParseGraphQLServer', () => { })).data.health; expect(health).toBeTruthy(); } catch (e) { - fail(e.networkError.result.errors); + handleError(e); } }); @@ -4546,63 +4559,67 @@ describe('ParseGraphQLServer', () => { describe('Data Types', () => { it('should support String', async () => { - const someFieldValue = 'some string'; + try { + const someFieldValue = 'some string'; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + schemaFields: { + addStrings: [{ name: 'someField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someField.type).toEqual('String'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someField.type).toEqual('String'); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - createSomeClass(fields: $fields) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + fields: { + someField: someFieldValue, + }, }, - }, - }); + }); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!, $someFieldValue: String) { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _eq: $someFieldValue } }) { - results { - someField + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!, $someFieldValue: String) { + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _eq: $someFieldValue } }) { + results { + someField + } } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - someFieldValue, - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + someFieldValue, + }, + }); - expect(typeof getResult.data.get.someField).toEqual('string'); - expect(getResult.data.get.someField).toEqual(someFieldValue); - expect(getResult.data.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someField).toEqual('string'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(1); + } catch (e) { + handleError(e); + } }); it('should support Int numbers', async () => { diff --git a/src/GraphQL/transformers/schemaFields.js b/src/GraphQL/transformers/schemaFields.js index 9de8b5732a..2f3b9c798f 100644 --- a/src/GraphQL/transformers/schemaFields.js +++ b/src/GraphQL/transformers/schemaFields.js @@ -1,4 +1,8 @@ const transformToParse = graphQLSchemaFields => { + if (!graphQLSchemaFields) { + return {}; + } + let parseSchemaFields = {}; const reducerFabric = type => (parseSchemaFields, field) => { From 4705684eb39b23cc7d32b8d2edcc60a74be546d2 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 09:12:33 -0700 Subject: [PATCH 22/60] Numbers test --- spec/ParseGraphQLServer.spec.js | 188 +++++++++++++++++--------------- 1 file changed, 98 insertions(+), 90 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 31a393b277..c7739fc264 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -4623,123 +4623,131 @@ describe('ParseGraphQLServer', () => { }); it('should support Int numbers', async () => { - const someFieldValue = 123; + try { + const someFieldValue = 123; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + schemaFields: { + addNumbers: [{ name: 'someField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - createSomeClass(fields: $fields) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + fields: { + someField: someFieldValue, + }, }, - }, - }); + }); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someField.type).toEqual('Number'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someField.type).toEqual('Number'); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!, $someFieldValue: Float) { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _eq: $someFieldValue } }) { - results { - someField + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!, $someFieldValue: Float) { + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _eq: $someFieldValue } }) { + results { + someField + } } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - someFieldValue, - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + someFieldValue, + }, + }); - expect(typeof getResult.data.get.someField).toEqual('number'); - expect(getResult.data.get.someField).toEqual(someFieldValue); - expect(getResult.data.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someField).toEqual('number'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(1); + } catch (e) { + handleError(e); + } }); it('should support Float numbers', async () => { - const someFieldValue = 123.4; + try { + const someFieldValue = 123.4; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + schemaFields: { + addNumbers: [{ name: 'someField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someField.type).toEqual('Number'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someField.type).toEqual('Number'); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - createSomeClass(fields: $fields) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + fields: { + someField: someFieldValue, + }, }, - }, - }); + }); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!, $someFieldValue: Float) { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _eq: $someFieldValue } }) { - results { - someField + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!, $someFieldValue: Float) { + get(className: "SomeClass", objectId: $objectId) + someClasses(where: { someField: { _eq: $someFieldValue } }) { + results { + someField + } } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - someFieldValue, - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + someFieldValue, + }, + }); - expect(typeof getResult.data.get.someField).toEqual('number'); - expect(getResult.data.get.someField).toEqual(someFieldValue); - expect(getResult.data.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someField).toEqual('number'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(1); + } catch (e) { + handleError(e); + } }); it('should support Boolean', async () => { From 990ed5b889954eed569f0c79631149a624cae13e Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 09:28:11 -0700 Subject: [PATCH 23/60] Boolean tests --- spec/ParseGraphQLServer.spec.js | 126 +++++++++++++++++--------------- 1 file changed, 66 insertions(+), 60 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index c7739fc264..6356eb3442 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -4751,79 +4751,85 @@ describe('ParseGraphQLServer', () => { }); it('should support Boolean', async () => { - const someFieldValueTrue = true; - const someFieldValueFalse = false; + try { + const someFieldValueTrue = true; + const someFieldValueFalse = false; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someFieldTrue: someFieldValueTrue, - someFieldFalse: someFieldValueFalse, + `, + variables: { + schemaFields: { + addBooleans: [ + { name: 'someFieldTrue' }, + { name: 'someFieldFalse' }, + ], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someFieldTrue.type).toEqual('Boolean'); - expect(schema.fields.someFieldFalse.type).toEqual('Boolean'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someFieldTrue.type).toEqual('Boolean'); + expect(schema.fields.someFieldFalse.type).toEqual('Boolean'); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - createSomeClass(fields: $fields) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } } - } - `, - variables: { - fields: { - someFieldTrue: someFieldValueTrue, - someFieldFalse: someFieldValueFalse, + `, + variables: { + fields: { + someFieldTrue: someFieldValueTrue, + someFieldFalse: someFieldValueFalse, + }, }, - }, - }); + }); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject( - $objectId: ID! - $someFieldValueTrue: Boolean - $someFieldValueFalse: Boolean - ) { - get(className: "SomeClass", objectId: $objectId) - someClasses( - where: { - someFieldTrue: { _eq: $someFieldValueTrue } - someFieldFalse: { _eq: $someFieldValueFalse } - } + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject( + $objectId: ID! + $someFieldValueTrue: Boolean + $someFieldValueFalse: Boolean ) { - results { - objectId + get(className: "SomeClass", objectId: $objectId) + someClasses( + where: { + someFieldTrue: { _eq: $someFieldValueTrue } + someFieldFalse: { _eq: $someFieldValueFalse } + } + ) { + results { + objectId + } } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - someFieldValueTrue, - someFieldValueFalse, - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + someFieldValueTrue, + someFieldValueFalse, + }, + }); - expect(typeof getResult.data.get.someFieldTrue).toEqual('boolean'); - expect(typeof getResult.data.get.someFieldFalse).toEqual('boolean'); - expect(getResult.data.get.someFieldTrue).toEqual(true); - expect(getResult.data.get.someFieldFalse).toEqual(false); - expect(getResult.data.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.get.someFieldTrue).toEqual('boolean'); + expect(typeof getResult.data.get.someFieldFalse).toEqual('boolean'); + expect(getResult.data.get.someFieldTrue).toEqual(true); + expect(getResult.data.get.someFieldFalse).toEqual(false); + expect(getResult.data.someClasses.results.length).toEqual(1); + } catch (e) { + handleError(e); + } }); it('should support Date', async () => { From 6ac2cbe3ebf38efc71bfaa12da310764be332b98 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 09:47:40 -0700 Subject: [PATCH 24/60] Date test --- spec/ParseGraphQLServer.spec.js | 98 +++++++++++++++++---------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 6356eb3442..2b358e5981 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -4833,65 +4833,69 @@ describe('ParseGraphQLServer', () => { }); it('should support Date', async () => { - const someFieldValue = { - __type: 'Date', - iso: new Date().toISOString(), - }; + try { + const someFieldValue = new Date(); - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + schemaFields: { + addDates: [{ name: 'someField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someField.type).toEqual('Date'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someField.type).toEqual('Date'); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - createSomeClass(fields: $fields) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + fields: { + someField: someFieldValue, + }, }, - }, - }); + }); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _exists: true } }) { - results { - objectId + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!) { + someClass(objectId: $objectId) { + someField + } + someClasses(where: { someField: { _exists: true } }) { + results { + objectId + } } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + }, + }); - expect(typeof getResult.data.get.someField).toEqual('object'); - expect(getResult.data.get.someField).toEqual(someFieldValue); - expect(getResult.data.someClasses.results.length).toEqual(2); + expect(new Date(getResult.data.someClass.someField)).toEqual( + someFieldValue + ); + expect(getResult.data.someClasses.results.length).toEqual(1); + } catch (e) { + handleError(e); + } }); it('should support createdAt', async () => { From 01b4b52a15e2ee834ef896634298ef7365e2ff08 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 09:52:38 -0700 Subject: [PATCH 25/60] Fix some get tests --- spec/ParseGraphQLServer.spec.js | 41 ++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 2b358e5981..e950eb69b9 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -4600,7 +4600,9 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!, $someFieldValue: String) { - get(className: "SomeClass", objectId: $objectId) + someClass(objectId: $objectId) { + someField + } someClasses(where: { someField: { _eq: $someFieldValue } }) { results { someField @@ -4614,8 +4616,8 @@ describe('ParseGraphQLServer', () => { }, }); - expect(typeof getResult.data.get.someField).toEqual('string'); - expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(typeof getResult.data.someClass.someField).toEqual('string'); + expect(getResult.data.someClass.someField).toEqual(someFieldValue); expect(getResult.data.someClasses.results.length).toEqual(1); } catch (e) { handleError(e); @@ -4664,7 +4666,9 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!, $someFieldValue: Float) { - get(className: "SomeClass", objectId: $objectId) + someClass(objectId: $objectId) { + someField + } someClasses(where: { someField: { _eq: $someFieldValue } }) { results { someField @@ -4678,8 +4682,8 @@ describe('ParseGraphQLServer', () => { }, }); - expect(typeof getResult.data.get.someField).toEqual('number'); - expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(typeof getResult.data.someClass.someField).toEqual('number'); + expect(getResult.data.someClass.someField).toEqual(someFieldValue); expect(getResult.data.someClasses.results.length).toEqual(1); } catch (e) { handleError(e); @@ -4728,7 +4732,9 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!, $someFieldValue: Float) { - get(className: "SomeClass", objectId: $objectId) + someClass(objectId: $objectId) { + someField + } someClasses(where: { someField: { _eq: $someFieldValue } }) { results { someField @@ -4742,8 +4748,8 @@ describe('ParseGraphQLServer', () => { }, }); - expect(typeof getResult.data.get.someField).toEqual('number'); - expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(typeof getResult.data.someClass.someField).toEqual('number'); + expect(getResult.data.someClass.someField).toEqual(someFieldValue); expect(getResult.data.someClasses.results.length).toEqual(1); } catch (e) { handleError(e); @@ -4802,7 +4808,10 @@ describe('ParseGraphQLServer', () => { $someFieldValueTrue: Boolean $someFieldValueFalse: Boolean ) { - get(className: "SomeClass", objectId: $objectId) + someClass(objectId: $objectId) { + someFieldTrue + someFieldFalse + } someClasses( where: { someFieldTrue: { _eq: $someFieldValueTrue } @@ -4822,10 +4831,14 @@ describe('ParseGraphQLServer', () => { }, }); - expect(typeof getResult.data.get.someFieldTrue).toEqual('boolean'); - expect(typeof getResult.data.get.someFieldFalse).toEqual('boolean'); - expect(getResult.data.get.someFieldTrue).toEqual(true); - expect(getResult.data.get.someFieldFalse).toEqual(false); + expect(typeof getResult.data.someClass.someFieldTrue).toEqual( + 'boolean' + ); + expect(typeof getResult.data.someClass.someFieldFalse).toEqual( + 'boolean' + ); + expect(getResult.data.someClass.someFieldTrue).toEqual(true); + expect(getResult.data.someClass.someFieldFalse).toEqual(false); expect(getResult.data.someClasses.results.length).toEqual(1); } catch (e) { handleError(e); From a3a7b7b1a5918d25bc515a484c6af43de8aaf459 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 10:03:13 -0700 Subject: [PATCH 26/60] Test for created at and updated at --- spec/ParseGraphQLServer.spec.js | 41 ++++----------------------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index e950eb69b9..5fc4eee34b 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -4911,12 +4911,12 @@ describe('ParseGraphQLServer', () => { } }); - it('should support createdAt', async () => { - const createResult = await apolloClient.mutate({ + it('should support createdAt and updatedAt', async () => { + await apolloClient.mutate({ mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - createdAt + mutation CreateClass { + createClass(name: "SomeClass") { + name } } `, @@ -4924,38 +4924,7 @@ describe('ParseGraphQLServer', () => { const schema = await new Parse.Schema('SomeClass').get(); expect(schema.fields.createdAt.type).toEqual('Date'); - - const { createdAt } = createResult.data.create; - expect(Date.parse(createdAt)).not.toEqual(NaN); - }); - - it('should support updatedAt', async () => { - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId - } - } - `, - }); - - const schema = await new Parse.Schema('SomeClass').get(); expect(schema.fields.updatedAt.type).toEqual('Date'); - - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "SomeClass", objectId: $objectId) - } - `, - variables: { - objectId: createResult.data.create.objectId, - }, - }); - - expect(typeof getResult.data.get.updatedAt).toEqual('string'); - expect(Date.parse(getResult.data.get.updatedAt)).not.toEqual(NaN); }); it('should support pointer on create', async () => { From e949c2e848585c2345b0616fece67df3b712e2b9 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 14:35:46 -0700 Subject: [PATCH 27/60] File tests --- spec/ParseGraphQLServer.spec.js | 224 ++++++++++++++++---------------- 1 file changed, 114 insertions(+), 110 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 5fc4eee34b..030368e66a 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -5466,140 +5466,144 @@ describe('ParseGraphQLServer', () => { }); it('should support files', async () => { - parseServer = await global.reconfigureServer({ - publicServerURL: 'http://localhost:13377/parse', - }); + try { + parseServer = await global.reconfigureServer({ + publicServerURL: 'http://localhost:13377/parse', + }); - const body = new FormData(); - body.append( - 'operations', - JSON.stringify({ - query: ` - mutation CreateFile($upload: Upload!) { - createFile(upload: $upload) { - name - url + const body = new FormData(); + body.append( + 'operations', + JSON.stringify({ + query: ` + mutation CreateFile($upload: Upload!) { + createFile(upload: $upload) { + name + url + } } - } - `, - variables: { - upload: null, - }, - }) - ); - body.append('map', JSON.stringify({ 1: ['variables.upload'] })); - body.append('1', 'My File Content', { - filename: 'myFileName.txt', - contentType: 'text/plain', - }); + `, + variables: { + upload: null, + }, + }) + ); + body.append('map', JSON.stringify({ 1: ['variables.upload'] })); + body.append('1', 'My File Content', { + filename: 'myFileName.txt', + contentType: 'text/plain', + }); - let res = await fetch('http://localhost:13377/graphql', { - method: 'POST', - headers, - body, - }); + let res = await fetch('http://localhost:13377/graphql', { + method: 'POST', + headers, + body, + }); - expect(res.status).toEqual(200); + expect(res.status).toEqual(200); - const result = JSON.parse(await res.text()); + const result = JSON.parse(await res.text()); - expect(result.data.createFile.name).toEqual( - jasmine.stringMatching(/_myFileName.txt$/) - ); - expect(result.data.createFile.url).toEqual( - jasmine.stringMatching(/_myFileName.txt$/) - ); + expect(result.data.createFile.name).toEqual( + jasmine.stringMatching(/_myFileName.txt$/) + ); + expect(result.data.createFile.url).toEqual( + jasmine.stringMatching(/_myFileName.txt$/) + ); - const someFieldValue = { - __type: 'File', - name: result.data.createFile.name, - url: result.data.createFile.url, - }; + const someFieldValue = { + __type: 'File', + name: result.data.createFile.name, + url: result.data.createFile.url, + }; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreaClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + schemaFields: { + addFiles: [{ name: 'someField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject( - $fields1: CreateSomeClassFieldsInput - $fields2: CreateSomeClassFieldsInput - ) { - createSomeClass1: createSomeClass(fields: $fields1) { - objectId - } - createSomeClass2: createSomeClass(fields: $fields2) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject( + $fields1: CreateSomeClassFieldsInput + $fields2: CreateSomeClassFieldsInput + ) { + createSomeClass1: createSomeClass(fields: $fields1) { + objectId + } + createSomeClass2: createSomeClass(fields: $fields2) { + objectId + } } - } - `, - variables: { - fields1: { - someField: someFieldValue, - }, - fields2: { - someField: someFieldValue.name, + `, + variables: { + fields1: { + someField: someFieldValue, + }, + fields2: { + someField: someFieldValue.name, + }, }, - }, - }); + }); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someField.type).toEqual('File'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someField.type).toEqual('File'); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "SomeClass", objectId: $objectId) - findSomeClass1: someClasses( - where: { someField: { _exists: true } } - ) { - results { - someField { - name - url + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!) { + get(className: "SomeClass", objectId: $objectId) + findSomeClass1: someClasses( + where: { someField: { _exists: true } } + ) { + results { + someField { + name + url + } } } - } - findSomeClass2: someClasses( - where: { someField: { _exists: true } } - ) { - results { - someField { - name - url + findSomeClass2: someClasses( + where: { someField: { _exists: true } } + ) { + results { + someField { + name + url + } } } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass1.objectId, + }, + }); - expect(typeof getResult.data.get.someField).toEqual('object'); - expect(getResult.data.get.someField).toEqual(someFieldValue); - expect(getResult.data.findSomeClass1.results.length).toEqual(3); - expect(getResult.data.findSomeClass2.results.length).toEqual(3); + expect(typeof getResult.data.get.someField).toEqual('object'); + expect(getResult.data.get.someField).toEqual(someFieldValue); + expect(getResult.data.findSomeClass1.results.length).toEqual(2); + expect(getResult.data.findSomeClass2.results.length).toEqual(2); - res = await fetch(getResult.data.get.someField.url); + res = await fetch(getResult.data.get.someField.url); - expect(res.status).toEqual(200); - expect(await res.text()).toEqual('My File Content'); + expect(res.status).toEqual(200); + expect(await res.text()).toEqual('My File Content'); + } catch (e) { + handleError(e); + } }); it('should support object values', async () => { From 080c65677b50b944b1118ff692cadafd320ab2db Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 17:18:31 -0700 Subject: [PATCH 28/60] Test for objects --- spec/ParseGraphQLServer.spec.js | 150 ++++++++++++++++---------------- 1 file changed, 76 insertions(+), 74 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 030368e66a..6531f36d53 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -5607,95 +5607,97 @@ describe('ParseGraphQLServer', () => { }); it('should support object values', async () => { - const someFieldValue = { - foo: { bar: 'baz' }, - number: 10, - }; + try { + const someFieldValue = { + foo: { bar: 'baz' }, + number: 10, + }; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + schemaFields: { + addObjects: [{ name: 'someField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someField.type).toEqual('Object'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someField.type).toEqual('Object'); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - createSomeClass(fields: $fields) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + fields: { + someField: someFieldValue, + }, }, - }, - }); + }); - const where = { - someField: { - _eq: { _key: 'foo.bar', _value: 'baz' }, - _ne: { _key: 'foo.bar', _value: 'bat' }, - _gt: { _key: 'number', _value: 9 }, - _lt: { _key: 'number', _value: 11 }, - }, - }; - const queryResult = await apolloClient.query({ - query: gql` - query GetSomeObject( - $objectId: ID! - $where: SomeClassWhereInput - $genericWhere: Object - ) { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: $where) { - results { - objectId - someField + const where = { + someField: { + _eq: { _key: 'foo.bar', _value: 'baz' }, + _ne: { _key: 'foo.bar', _value: 'bat' }, + _gt: { _key: 'number', _value: 9 }, + _lt: { _key: 'number', _value: 11 }, + }, + }; + const queryResult = await apolloClient.query({ + query: gql` + query GetSomeObject( + $objectId: ID! + $where: SomeClassWhereInput + $genericWhere: Object + ) { + get(className: "SomeClass", objectId: $objectId) + someClasses(where: $where) { + results { + objectId + someField + } + } + find(className: "SomeClass", where: $genericWhere) { + results } } - find(className: "SomeClass", where: $genericWhere) { - results - } - } - `, - variables: { - objectId: createResult.data.create.objectId, - where, - genericWhere: where, // where and genericWhere types are different - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + where, + genericWhere: where, // where and genericWhere types are different + }, + }); - const { get: getResult, someClasses, find } = queryResult.data; + const { get: getResult, someClasses, find } = queryResult.data; - const { someField } = getResult; - expect(typeof someField).toEqual('object'); - expect(someField).toEqual(someFieldValue); + const { someField } = getResult; + expect(typeof someField).toEqual('object'); + expect(someField).toEqual(someFieldValue); - // Checks class query results - expect(someClasses.results.length).toEqual(2); - expect(someClasses.results[0].someField).toEqual(someFieldValue); - expect(someClasses.results[1].someField).toEqual(someFieldValue); + // Checks class query results + expect(someClasses.results.length).toEqual(1); + expect(someClasses.results[0].someField).toEqual(someFieldValue); - // Checks generic query results - expect(find.results.length).toEqual(2); - expect(find.results[0].someField).toEqual(someFieldValue); - expect(find.results[1].someField).toEqual(someFieldValue); + // Checks generic query results + expect(find.results.length).toEqual(1); + expect(find.results[0].someField).toEqual(someFieldValue); + } catch (e) { + handleError(e); + } }); it('should support object composed queries', async () => { From cd2f17126fd02b65aae54f3a05b4b120f70a1870 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 17:24:50 -0700 Subject: [PATCH 29/60] Renaming reducerFabric to reducerGenerator --- src/GraphQL/transformers/schemaFields.js | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/GraphQL/transformers/schemaFields.js b/src/GraphQL/transformers/schemaFields.js index 2f3b9c798f..72a73c0754 100644 --- a/src/GraphQL/transformers/schemaFields.js +++ b/src/GraphQL/transformers/schemaFields.js @@ -5,7 +5,7 @@ const transformToParse = graphQLSchemaFields => { let parseSchemaFields = {}; - const reducerFabric = type => (parseSchemaFields, field) => { + const reducerGenerator = type => (parseSchemaFields, field) => { if ( graphQLSchemaFields.remove && graphQLSchemaFields.remove.find( @@ -46,73 +46,73 @@ const transformToParse = graphQLSchemaFields => { if (graphQLSchemaFields.addStrings) { parseSchemaFields = graphQLSchemaFields.addStrings.reduce( - reducerFabric('String'), + reducerGenerator('String'), parseSchemaFields ); } if (graphQLSchemaFields.addNumbers) { parseSchemaFields = graphQLSchemaFields.addNumbers.reduce( - reducerFabric('Number'), + reducerGenerator('Number'), parseSchemaFields ); } if (graphQLSchemaFields.addBooleans) { parseSchemaFields = graphQLSchemaFields.addBooleans.reduce( - reducerFabric('Boolean'), + reducerGenerator('Boolean'), parseSchemaFields ); } if (graphQLSchemaFields.addArrays) { parseSchemaFields = graphQLSchemaFields.addArrays.reduce( - reducerFabric('Array'), + reducerGenerator('Array'), parseSchemaFields ); } if (graphQLSchemaFields.addObjects) { parseSchemaFields = graphQLSchemaFields.addObjects.reduce( - reducerFabric('Object'), + reducerGenerator('Object'), parseSchemaFields ); } if (graphQLSchemaFields.addDates) { parseSchemaFields = graphQLSchemaFields.addDates.reduce( - reducerFabric('Date'), + reducerGenerator('Date'), parseSchemaFields ); } if (graphQLSchemaFields.addFiles) { parseSchemaFields = graphQLSchemaFields.addFiles.reduce( - reducerFabric('File'), + reducerGenerator('File'), parseSchemaFields ); } if (graphQLSchemaFields.addGeoPoints) { parseSchemaFields = graphQLSchemaFields.addGeoPoints.reduce( - reducerFabric('GeoPoint'), + reducerGenerator('GeoPoint'), parseSchemaFields ); } if (graphQLSchemaFields.addPolygons) { parseSchemaFields = graphQLSchemaFields.addPolygons.reduce( - reducerFabric('Polygon'), + reducerGenerator('Polygon'), parseSchemaFields ); } if (graphQLSchemaFields.addBytes) { parseSchemaFields = graphQLSchemaFields.addBytes.reduce( - reducerFabric('Byte'), + reducerGenerator('Byte'), parseSchemaFields ); } if (graphQLSchemaFields.addPointers) { parseSchemaFields = graphQLSchemaFields.addPointers.reduce( - reducerFabric('Pointer'), + reducerGenerator('Pointer'), parseSchemaFields ); } if (graphQLSchemaFields.addRelations) { parseSchemaFields = graphQLSchemaFields.addRelations.reduce( - reducerFabric('Relation'), + reducerGenerator('Relation'), parseSchemaFields ); } From a728860dbde4df90860c4ca649672cb8dba74caf Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Mon, 26 Aug 2019 17:48:20 -0700 Subject: [PATCH 30/60] Changing get tests for file and object --- spec/ParseGraphQLServer.spec.js | 39 ++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 6531f36d53..74d7efa29d 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -5511,11 +5511,7 @@ describe('ParseGraphQLServer', () => { jasmine.stringMatching(/_myFileName.txt$/) ); - const someFieldValue = { - __type: 'File', - name: result.data.createFile.name, - url: result.data.createFile.url, - }; + const someFieldValue = result.data.createFile.name; await apolloClient.mutate({ mutation: gql` @@ -5564,7 +5560,12 @@ describe('ParseGraphQLServer', () => { const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get(className: "SomeClass", objectId: $objectId) + someClass(objectId: $objectId) { + someField { + name + url + } + } findSomeClass1: someClasses( where: { someField: { _exists: true } } ) { @@ -5592,12 +5593,17 @@ describe('ParseGraphQLServer', () => { }, }); - expect(typeof getResult.data.get.someField).toEqual('object'); - expect(getResult.data.get.someField).toEqual(someFieldValue); - expect(getResult.data.findSomeClass1.results.length).toEqual(2); - expect(getResult.data.findSomeClass2.results.length).toEqual(2); + expect(typeof getResult.data.someClass.someField).toEqual('object'); + expect(getResult.data.someClass.someField.name).toEqual( + result.data.createFile.name + ); + expect(getResult.data.someClass.someField.url).toEqual( + result.data.createFile.url + ); + expect(getResult.data.findSomeClass1.results.length).toEqual(1); + expect(getResult.data.findSomeClass2.results.length).toEqual(1); - res = await fetch(getResult.data.get.someField.url); + res = await fetch(getResult.data.someClass.someField.url); expect(res.status).toEqual(200); expect(await res.text()).toEqual('My File Content'); @@ -5663,7 +5669,10 @@ describe('ParseGraphQLServer', () => { $where: SomeClassWhereInput $genericWhere: Object ) { - get(className: "SomeClass", objectId: $objectId) + someClass(objectId: $objectId) { + objectId + someField + } someClasses(where: $where) { results { objectId @@ -5682,7 +5691,11 @@ describe('ParseGraphQLServer', () => { }, }); - const { get: getResult, someClasses, find } = queryResult.data; + const { + someClass: getResult, + someClasses, + find, + } = queryResult.data; const { someField } = getResult; expect(typeof someField).toEqual('object'); From 8ec3d85cb385b562592aadbc88e45d60cd6f8a0d Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 00:52:57 -0700 Subject: [PATCH 31/60] Object composed queries test --- spec/ParseGraphQLServer.spec.js | 216 ++++++++++++++++++-------------- 1 file changed, 119 insertions(+), 97 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 74d7efa29d..38ae92add3 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -5714,117 +5714,139 @@ describe('ParseGraphQLServer', () => { }); it('should support object composed queries', async () => { - const someFieldValue = { - lorem: 'ipsum', - number: 10, - }; - const someFieldValue2 = { - foo: { - test: 'bar', - }, - number: 10, - }; + try { + const someFieldValue = { + lorem: 'ipsum', + number: 10, + }; + const someFieldValue2 = { + foo: { + test: 'bar', + }, + number: 10, + }; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields1: Object, $fields2: Object) { - create1: create(className: "SomeClass", fields: $fields1) { - objectId - } - create2: create(className: "SomeClass", fields: $fields2) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass { + createClass( + name: "SomeClass" + schemaFields: { addObjects: [{ name: "someField" }] } + ) { + name + } } - } - `, - variables: { - fields1: { - someField: someFieldValue, - }, - fields2: { - someField: someFieldValue2, - }, - }, - }); + `, + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const where = { - _and: [ - { - someField: { - _gt: { _key: 'number', _value: 9 }, + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject( + $fields1: CreateSomeClassFieldsInput + $fields2: CreateSomeClassFieldsInput + ) { + create1: createSomeClass(fields: $fields1) { + objectId + } + create2: createSomeClass(fields: $fields2) { + objectId + } + } + `, + variables: { + fields1: { + someField: someFieldValue, }, - }, - { - someField: { - _lt: { _key: 'number', _value: 11 }, + fields2: { + someField: someFieldValue2, }, }, - { - _or: [ - { - someField: { - _eq: { _key: 'lorem', _value: 'ipsum' }, - }, + }); + + const where = { + _and: [ + { + someField: { + _gt: { _key: 'number', _value: 9 }, }, - { - someField: { - _eq: { _key: 'foo.test', _value: 'bar' }, - }, + }, + { + someField: { + _lt: { _key: 'number', _value: 11 }, }, - ], - }, - ], - }; - const findResult = await apolloClient.query({ - query: gql` - query FindSomeObject( - $where: SomeClassWhereInput - $genericWhere: Object - ) { - someClasses(where: $where) { - results { - objectId - someField + }, + { + _or: [ + { + someField: { + _eq: { _key: 'lorem', _value: 'ipsum' }, + }, + }, + { + someField: { + _eq: { _key: 'foo.test', _value: 'bar' }, + }, + }, + ], + }, + ], + }; + const findResult = await apolloClient.query({ + query: gql` + query FindSomeObject( + $where: SomeClassWhereInput + $genericWhere: Object + ) { + someClasses(where: $where) { + results { + objectId + someField + } + } + find(className: "SomeClass", where: $genericWhere) { + results } } - find(className: "SomeClass", where: $genericWhere) { - results - } - } - `, - variables: { - where, - genericWhere: where, // where and genericWhere types are different - }, - }); + `, + variables: { + where, + genericWhere: where, // where and genericWhere types are different + }, + }); - const { create1, create2 } = createResult.data; - const { someClasses, find } = findResult.data; + const { create1, create2 } = createResult.data; + const { someClasses, find } = findResult.data; - // Checks class query results - const { results } = someClasses; - expect(results.length).toEqual(2); - expect( - results.find(result => result.objectId === create1.objectId) - .someField - ).toEqual(someFieldValue); - expect( - results.find(result => result.objectId === create2.objectId) - .someField - ).toEqual(someFieldValue2); + // Checks class query results + const { results } = someClasses; + expect(results.length).toEqual(2); + expect( + results.find(result => result.objectId === create1.objectId) + .someField + ).toEqual(someFieldValue); + expect( + results.find(result => result.objectId === create2.objectId) + .someField + ).toEqual(someFieldValue2); - // Checks generic query results - const { results: genericResults } = find; - expect(genericResults.length).toEqual(2); - expect( - genericResults.find(result => result.objectId === create1.objectId) - .someField - ).toEqual(someFieldValue); - expect( - genericResults.find(result => result.objectId === create2.objectId) - .someField - ).toEqual(someFieldValue2); + // Checks generic query results + const { results: genericResults } = find; + expect(genericResults.length).toEqual(2); + expect( + genericResults.find( + result => result.objectId === create1.objectId + ).someField + ).toEqual(someFieldValue); + expect( + genericResults.find( + result => result.objectId === create2.objectId + ).someField + ).toEqual(someFieldValue2); + } catch (e) { + handleError(e); + } }); it('should support array values', async () => { From 7d124bde6b7ba458b70b0ee797a6bcfa00d84c3d Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 01:01:03 -0700 Subject: [PATCH 32/60] Array test --- spec/ParseGraphQLServer.spec.js | 108 +++++++++++++++++++------------- 1 file changed, 63 insertions(+), 45 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 38ae92add3..d55840e1fa 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -5850,68 +5850,86 @@ describe('ParseGraphQLServer', () => { }); it('should support array values', async () => { - const someFieldValue = [1, 'foo', ['bar'], { lorem: 'ipsum' }, true]; + try { + const someFieldValue = [ + 1, + 'foo', + ['bar'], + { lorem: 'ipsum' }, + true, + ]; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + schemaFields: { + addArrays: [{ name: 'someField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someField.type).toEqual('Array'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someField.type).toEqual('Array'); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - createSomeClass(fields: $fields) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + fields: { + someField: someFieldValue, + }, }, - }, - }); + }); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _exists: true } }) { - results { - objectId + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!) { + someClass(objectId: $objectId) { someField { ... on Element { value } } } + someClasses(where: { someField: { _exists: true } }) { + results { + objectId + someField { + ... on Element { + value + } + } + } + } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + }, + }); - const { someField } = getResult.data.get; - expect(Array.isArray(someField)).toBeTruthy(); - expect(someField).toEqual(someFieldValue); - expect(getResult.data.someClasses.results.length).toEqual(2); + const { someField } = getResult.data.someClass; + expect(Array.isArray(someField)).toBeTruthy(); + expect(someField.map(element => element.value)).toEqual( + someFieldValue + ); + expect(getResult.data.someClasses.results.length).toEqual(1); + } catch (e) { + handleError(e); + } }); it('should support undefined array', async () => { From 53dbd1b13c66b5ce62ce885c3eb4ee801014aa1d Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 01:13:05 -0700 Subject: [PATCH 33/60] Null field test --- spec/ParseGraphQLServer.spec.js | 138 ++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 53 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index d55840e1fa..dacf30bdb4 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -5963,67 +5963,99 @@ describe('ParseGraphQLServer', () => { }); it('should support null values', async () => { - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + try { + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass { + createClass( + name: "SomeClass" + schemaFields: { + addStrings: [ + { name: "someStringField" } + { name: "someNullField" } + ] + addNumbers: [{ name: "someNumberField" }] + addBooleans: [{ name: "someBooleanField" }] + addObjects: [{ name: "someObjectField" }] + } + ) { + name + } } - } - `, - variables: { - fields: { - someStringField: 'some string', - someNumberField: 123, - someBooleanField: true, - someObjectField: { someField: 'some value' }, - someNullField: null, + `, + }); + + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } + } + `, + variables: { + fields: { + someStringField: 'some string', + someNumberField: 123, + someBooleanField: true, + someObjectField: { someField: 'some value' }, + someNullField: null, + }, }, - }, - }); + }); - await apolloClient.mutate({ - mutation: gql` - mutation UpdateSomeObject($objectId: ID!, $fields: Object) { - update( - className: "SomeClass" - objectId: $objectId - fields: $fields + await apolloClient.mutate({ + mutation: gql` + mutation UpdateSomeObject( + $objectId: ID! + $fields: UpdateSomeClassFieldsInput ) { - updatedAt + updateSomeClass(objectId: $objectId, fields: $fields) { + updatedAt + } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - fields: { - someStringField: null, - someNumberField: null, - someBooleanField: null, - someObjectField: null, - someNullField: 'now it has a string', + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + fields: { + someStringField: null, + someNumberField: null, + someBooleanField: null, + someObjectField: null, + someNullField: 'now it has a string', + }, }, - }, - }); + }); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "SomeClass", objectId: $objectId) - } - `, - variables: { - objectId: createResult.data.create.objectId, - }, - }); + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!) { + someClass(objectId: $objectId) { + someStringField + someNumberField + someBooleanField + someObjectField + someNullField + } + } + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + }, + }); - expect(getResult.data.get.someStringField).toBeFalsy(); - expect(getResult.data.get.someNumberField).toBeFalsy(); - expect(getResult.data.get.someBooleanField).toBeFalsy(); - expect(getResult.data.get.someObjectField).toBeFalsy(); - expect(getResult.data.get.someNullField).toEqual( - 'now it has a string' - ); + expect(getResult.data.someClass.someStringField).toBeFalsy(); + expect(getResult.data.someClass.someNumberField).toBeFalsy(); + expect(getResult.data.someClass.someBooleanField).toBeFalsy(); + expect(getResult.data.someClass.someObjectField).toBeFalsy(); + expect(getResult.data.someClass.someNullField).toEqual( + 'now it has a string' + ); + } catch (e) { + handleError(e); + } }); it('should support Bytes', async () => { From 495c718a62f4ad2dc7fa4fa10ac936f2e53e2ea6 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 01:20:50 -0700 Subject: [PATCH 34/60] Bytes test --- spec/ParseGraphQLServer.spec.js | 117 ++++++++++++----------- src/GraphQL/transformers/schemaFields.js | 2 +- 2 files changed, 61 insertions(+), 58 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index dacf30bdb4..d297d276c2 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -6059,76 +6059,79 @@ describe('ParseGraphQLServer', () => { }); it('should support Bytes', async () => { - const someFieldValue = { - __type: 'Bytes', - base64: 'aGVsbG8gd29ybGQ=', - }; + try { + const someFieldValue = 'aGVsbG8gd29ybGQ='; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + schemaFields: { + addBytes: [{ name: 'someField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someField.type).toEqual('Bytes'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someField.type).toEqual('Bytes'); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject( - $fields1: CreateSomeClassFieldsInput - $fields2: CreateSomeClassFieldsInput - ) { - createSomeClass1: createSomeClass(fields: $fields1) { - objectId - } - createSomeClass2: createSomeClass(fields: $fields2) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject( + $fields1: CreateSomeClassFieldsInput + $fields2: CreateSomeClassFieldsInput + ) { + createSomeClass1: createSomeClass(fields: $fields1) { + objectId + } + createSomeClass2: createSomeClass(fields: $fields2) { + objectId + } } - } - `, - variables: { - fields1: { - someField: someFieldValue, - }, - fields2: { - someField: someFieldValue.base64, + `, + variables: { + fields1: { + someField: someFieldValue, + }, + fields2: { + someField: someFieldValue, + }, }, - }, - }); + }); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!, $someFieldValue: Bytes) { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _eq: $someFieldValue } }) { - results { - objectId + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!, $someFieldValue: Bytes) { + someClass(objectId: $objectId) { someField } + someClasses(where: { someField: { _eq: $someFieldValue } }) { + results { + objectId + someField + } + } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - someFieldValue, - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass1.objectId, + someFieldValue, + }, + }); - expect(typeof getResult.data.get.someField).toEqual('object'); - expect(getResult.data.get.someField).toEqual(someFieldValue); - expect(getResult.data.someClasses.results.length).toEqual(3); + expect(typeof getResult.data.someClass.someField).toEqual('string'); + expect(getResult.data.someClass.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(2); + } catch (e) { + handleError(e); + } }); it('should support Geo Points', async () => { diff --git a/src/GraphQL/transformers/schemaFields.js b/src/GraphQL/transformers/schemaFields.js index 72a73c0754..5a7d5cae27 100644 --- a/src/GraphQL/transformers/schemaFields.js +++ b/src/GraphQL/transformers/schemaFields.js @@ -100,7 +100,7 @@ const transformToParse = graphQLSchemaFields => { } if (graphQLSchemaFields.addBytes) { parseSchemaFields = graphQLSchemaFields.addBytes.reduce( - reducerGenerator('Byte'), + reducerGenerator('Bytes'), parseSchemaFields ); } From f20287da80b235c927b7369e12ef3f04e57db616 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 09:23:50 -0700 Subject: [PATCH 35/60] Geo Point test --- spec/ParseGraphQLServer.spec.js | 109 +++++++++++++++++--------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index d297d276c2..c2fee0424c 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -6135,73 +6135,82 @@ describe('ParseGraphQLServer', () => { }); it('should support Geo Points', async () => { - const someFieldValue = { - __type: 'GeoPoint', - latitude: 45, - longitude: 45, - }; + try { + const someFieldValue = { + __typename: 'GeoPoint', + latitude: 45, + longitude: 45, + }; - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - someField: someFieldValue, + `, + variables: { + schemaFields: { + addGeoPoints: [{ name: 'someField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.someField.type).toEqual('GeoPoint'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.someField.type).toEqual('GeoPoint'); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - createSomeClass(fields: $fields) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } } - } - `, - variables: { - fields: { - someField: { - latitude: someFieldValue.latitude, - longitude: someFieldValue.longitude, + `, + variables: { + fields: { + someField: { + latitude: someFieldValue.latitude, + longitude: someFieldValue.longitude, + }, }, }, - }, - }); + }); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { someField: { _exists: true } }) { - results { - objectId + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!) { + someClass(objectId: $objectId) { someField { latitude longitude } } + someClasses(where: { someField: { _exists: true } }) { + results { + objectId + someField { + latitude + longitude + } + } + } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - }, - }); + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + }, + }); - expect(typeof getResult.data.get.someField).toEqual('object'); - expect(getResult.data.get.someField).toEqual(someFieldValue); - expect(getResult.data.someClasses.results.length).toEqual(2); + expect(typeof getResult.data.someClass.someField).toEqual('object'); + expect(getResult.data.someClass.someField).toEqual(someFieldValue); + expect(getResult.data.someClasses.results.length).toEqual(1); + } catch (e) { + handleError(e); + } }); it('should support Polygons', async () => { From f79ea0b10b286568a9beeda1a95119f166ae8a54 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 09:32:09 -0700 Subject: [PATCH 36/60] Polygons tests --- spec/ParseGraphQLServer.spec.js | 166 +++++++++++++------------------- 1 file changed, 67 insertions(+), 99 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index c2fee0424c..351df30f37 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -6214,122 +6214,90 @@ describe('ParseGraphQLServer', () => { }); it('should support Polygons', async () => { - const someFieldValue = { - __type: 'Polygon', - coordinates: [[44, 45], [46, 47], [48, 49], [44, 45]], - }; + try { + const somePolygonFieldValue = [ + [44, 45], + [46, 47], + [48, 49], + [44, 45], + ].map(point => ({ + latitude: point[0], + longitude: point[1], + })); - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId + await apolloClient.mutate({ + mutation: gql` + mutation CreateClass($schemaFields: SchemaFieldsInput) { + createClass(name: "SomeClass", schemaFields: $schemaFields) { + name + } } - } - `, - variables: { - fields: { - somePolygonField: someFieldValue, + `, + variables: { + schemaFields: { + addPolygons: [{ name: 'somePolygonField' }], + }, }, - }, - }); + }); - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.somePolygonField.type).toEqual('Polygon'); + const schema = await new Parse.Schema('SomeClass').get(); + expect(schema.fields.somePolygonField.type).toEqual('Polygon'); - await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { - createSomeClass(fields: $fields) { - objectId + const createResult = await apolloClient.mutate({ + mutation: gql` + mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { + createSomeClass(fields: $fields) { + objectId + } } - } - `, - variables: { - fields: { - somePolygonField: someFieldValue.coordinates.map(point => ({ - latitude: point[0], - longitude: point[1], - })), + `, + variables: { + fields: { + somePolygonField: somePolygonFieldValue, + }, }, - }, - }); + }); - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "SomeClass", objectId: $objectId) - someClasses(where: { somePolygonField: { _exists: true } }) { - results { - objectId + const getResult = await apolloClient.query({ + query: gql` + query GetSomeObject($objectId: ID!) { + someClass(objectId: $objectId) { somePolygonField { latitude longitude } } - } - } - `, - variables: { - objectId: createResult.data.create.objectId, - }, - }); - - expect(typeof getResult.data.get.somePolygonField).toEqual('object'); - expect(getResult.data.get.somePolygonField).toEqual(someFieldValue); - expect(getResult.data.someClasses.results.length).toEqual(2); - }); - - it('should support polygon values', async () => { - const someFieldValue = { - __type: 'Polygon', - coordinates: [[1.0, 2.1], [3.2, 4.3], [5.4, 6.5], [1.0, 2.1]], - }; - - const createResult = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId - } - } - `, - variables: { - fields: { - somePolygonField: someFieldValue, - }, - }, - }); - - await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); - - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - someClass(objectId: $objectId) { - somePolygonField { - latitude - longitude + someClasses(where: { somePolygonField: { _exists: true } }) { + results { + objectId + somePolygonField { + latitude + longitude + } + } } } - } - `, - variables: { - objectId: createResult.data.create.objectId, - }, - }); - - const schema = await new Parse.Schema('SomeClass').get(); - expect(schema.fields.somePolygonField.type).toEqual('Polygon'); + `, + variables: { + objectId: createResult.data.createSomeClass.objectId, + }, + }); - const { somePolygonField } = getResult.data.someClass; - expect(Array.isArray(somePolygonField)).toBeTruthy(); - somePolygonField.forEach((coord, i) => { - expect(coord.latitude).toEqual(someFieldValue.coordinates[i][0]); - expect(coord.longitude).toEqual(someFieldValue.coordinates[i][1]); - }); + expect(typeof getResult.data.someClass.somePolygonField).toEqual( + 'object' + ); + expect(getResult.data.someClass.somePolygonField).toEqual( + somePolygonFieldValue.map(geoPoint => ({ + ...geoPoint, + __typename: 'GeoPoint', + })) + ); + expect(getResult.data.someClasses.results.length).toEqual(1); + } catch (e) { + handleError(e); + } }); it_only_db('mongo')('should support bytes values', async () => { From 51a2f10021c12a84e3101c22e6d18e81e5b4fdcf Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 09:40:39 -0700 Subject: [PATCH 37/60] Remove create generic mutation --- src/GraphQL/ParseGraphQLSchema.js | 1 - src/GraphQL/loaders/objectsMutations.js | 25 ------------------------- 2 files changed, 26 deletions(-) diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index 1747df5472..c31945394f 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -39,7 +39,6 @@ const RESERVED_GRAPHQL_MUTATION_NAMES = [ 'createFile', 'callCloudCode', 'createClass', - 'create', 'update', 'delete', ]; diff --git a/src/GraphQL/loaders/objectsMutations.js b/src/GraphQL/loaders/objectsMutations.js index 208420c212..9e96bb16c8 100644 --- a/src/GraphQL/loaders/objectsMutations.js +++ b/src/GraphQL/loaders/objectsMutations.js @@ -39,31 +39,6 @@ const deleteObject = async (className, objectId, config, auth, info) => { }; const load = parseGraphQLSchema => { - parseGraphQLSchema.addGraphQLMutation( - 'create', - { - description: - 'The create mutation can be used to create a new object of a certain class.', - args: { - className: defaultGraphQLTypes.CLASS_NAME_ATT, - fields: defaultGraphQLTypes.FIELDS_ATT, - }, - type: new GraphQLNonNull(defaultGraphQLTypes.CREATE_RESULT), - async resolve(_source, args, context) { - try { - const { className, fields } = args; - const { config, auth, info } = context; - - return await createObject(className, fields, config, auth, info); - } catch (e) { - parseGraphQLSchema.handleError(e); - } - }, - }, - true, - true - ); - parseGraphQLSchema.addGraphQLMutation( 'update', { From 34d5679569b7ac26ac5d54ce19f4597098922df6 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 09:52:37 -0700 Subject: [PATCH 38/60] Fix tests --- spec/ParseGraphQLSchema.spec.js | 4 ++-- spec/ParseGraphQLServer.spec.js | 42 +-------------------------------- 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/spec/ParseGraphQLSchema.spec.js b/spec/ParseGraphQLSchema.spec.js index 80cd93e3a3..0957ea6941 100644 --- a/spec/ParseGraphQLSchema.spec.js +++ b/spec/ParseGraphQLSchema.spec.js @@ -363,14 +363,14 @@ describe('ParseGraphQLSchema', () => { warn: message => { logged = true; expect(message).toEqual( - 'Mutation create could not be added to the auto schema because it collided with an existing field.' + 'Mutation signUp could not be added to the auto schema because it collided with an existing field.' ); }, }, }); await parseGraphQLSchema.load(); expect( - parseGraphQLSchema.addGraphQLMutation('create', {}) + parseGraphQLSchema.addGraphQLMutation('signUp', {}) ).toBeUndefined(); expect(logged).toBeTruthy(); }); diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 351df30f37..bccabc1cad 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -3219,35 +3219,6 @@ describe('ParseGraphQLServer', () => { describe('Objects Mutations', () => { describe('Create', () => { - it('should return CreateResult object using generic mutation', async () => { - const result = await apolloClient.mutate({ - mutation: gql` - mutation CreateSomeObject($fields: Object) { - create(className: "SomeClass", fields: $fields) { - objectId - createdAt - } - } - `, - variables: { - fields: { - someField: 'someValue', - }, - }, - }); - - expect(result.data.create.objectId).toBeDefined(); - - const obj = await new Parse.Query('SomeClass').get( - result.data.create.objectId - ); - - expect(obj.createdAt).toEqual( - new Date(result.data.create.createdAt) - ); - expect(obj.get('someField')).toEqual('someValue'); - }); - it('should return specific type object using class specific mutation', async () => { const customerSchema = new Parse.Schema('Customer'); customerSchema.addString('someField'); @@ -3293,29 +3264,18 @@ describe('ParseGraphQLServer', () => { async function createObject(className, headers) { const result = await apolloClient.mutate({ mutation: gql` - mutation CreateSomeObject($className: String!) { - create(className: $className) { - objectId - createdAt - } + mutation CreateSomeObject { create${className} { objectId createdAt } } `, - variables: { - className, - }, context: { headers, }, }); - const { create } = result.data; - expect(create.objectId).toBeDefined(); - expect(create.createdAt).toBeDefined(); - const specificCreate = result.data[`create${className}`]; expect(specificCreate.objectId).toBeDefined(); expect(specificCreate.createdAt).toBeDefined(); From 798d5342d3bee17eb71715f7926dc228dda21251 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 19:08:59 -0700 Subject: [PATCH 39/60] Create class test - isRequired and defaultValue will be added back later --- spec/ParseGraphQLServer.spec.js | 291 ++++++++++++++++++++++- src/GraphQL/ParseGraphQLSchema.js | 2 - src/GraphQL/loaders/classSchemaTypes.js | 154 ++---------- src/GraphQL/transformers/schemaFields.js | 29 +-- 4 files changed, 316 insertions(+), 160 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index bccabc1cad..04bbefd2c7 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -1592,6 +1592,295 @@ describe('ParseGraphQLServer', () => { }); }); + describe('Class Schema Mutations', () => { + it('should create a new class', async () => { + try { + const result = await apolloClient.mutate({ + mutation: gql` + mutation { + class1: createClass(name: "Class1") { + name + schemaFields { + name + __typename + } + } + class2: createClass(name: "Class2", schemaFields: null) { + name + schemaFields { + name + __typename + } + } + class3: createClass(name: "Class3", schemaFields: {}) { + name + schemaFields { + name + __typename + } + } + class4: createClass( + name: "Class4" + schemaFields: { + addStrings: null + addNumbers: null + addBooleans: null + addArrays: null + addObjects: null + addDates: null + addFiles: null + addGeoPoint: null + addPolygons: null + addBytes: null + addPointers: null + addRelations: null + } + ) { + name + schemaFields { + name + __typename + } + } + class5: createClass( + name: "Class5" + schemaFields: { + addStrings: [] + addNumbers: [] + addBooleans: [] + addArrays: [] + addObjects: [] + addDates: [] + addFiles: [] + addPolygons: [] + addBytes: [] + addPointers: [] + addRelations: [] + } + ) { + name + schemaFields { + name + __typename + } + } + class6: createClass( + name: "Class6" + schemaFields: { + addStrings: [ + { name: "stringField1" } + { name: "stringField2" } + { name: "stringField3" } + ] + addNumbers: [ + { name: "numberField1" } + { name: "numberField2" } + { name: "numberField3" } + ] + addBooleans: [ + { name: "booleanField1" } + { name: "booleanField2" } + { name: "booleanField3" } + ] + addArrays: [ + { name: "arrayField1" } + { name: "arrayField2" } + { name: "arrayField3" } + ] + addObjects: [ + { name: "objectField1" } + { name: "objectField2" } + { name: "objectField3" } + ] + addDates: [ + { name: "dateField1" } + { name: "dateField2" } + { name: "dateField3" } + ] + addFiles: [ + { name: "fileField1" } + { name: "fileField2" } + { name: "fileField3" } + ] + addGeoPoint: { name: "geoPointField" } + addPolygons: [ + { name: "polygonField1" } + { name: "polygonField2" } + { name: "polygonField3" } + ] + addBytes: [ + { name: "bytesField1" } + { name: "bytesField2" } + { name: "bytesField3" } + ] + addPointers: [ + { name: "pointerField1", targetClassName: "Class1" } + { name: "pointerField2", targetClassName: "Class6" } + { name: "pointerField3", targetClassName: "Class2" } + ] + addRelations: [ + { name: "relationField1", targetClassName: "Class1" } + { name: "relationField2", targetClassName: "Class6" } + { name: "relationField3", targetClassName: "Class2" } + ] + remove: [ + { name: "stringField3" } + { name: "numberField3" } + { name: "booleanField3" } + { name: "arrayField3" } + { name: "objectField3" } + { name: "dateField3" } + { name: "fileField3" } + { name: "polygonField3" } + { name: "bytesField3" } + { name: "pointerField3" } + { name: "relationField3" } + ] + } + ) { + name + schemaFields { + name + __typename + ... on SchemaPointerField { + targetClassName + } + ... on SchemaRelationField { + targetClassName + } + } + } + } + `, + }); + expect(result).toEqual({ + data: { + class1: { + name: 'Class1', + schemaFields: [ + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'ACL', __typename: 'SchemaACLField' }, + ], + __typename: 'Class', + }, + class2: { + name: 'Class2', + schemaFields: [ + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'ACL', __typename: 'SchemaACLField' }, + ], + __typename: 'Class', + }, + class3: { + name: 'Class3', + schemaFields: [ + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'ACL', __typename: 'SchemaACLField' }, + ], + __typename: 'Class', + }, + class4: { + name: 'Class4', + schemaFields: [ + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'ACL', __typename: 'SchemaACLField' }, + ], + __typename: 'Class', + }, + class5: { + name: 'Class5', + schemaFields: [ + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'ACL', __typename: 'SchemaACLField' }, + ], + __typename: 'Class', + }, + class6: { + name: 'Class6', + schemaFields: [ + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'stringField1', __typename: 'SchemaStringField' }, + { name: 'stringField2', __typename: 'SchemaStringField' }, + { name: 'numberField1', __typename: 'SchemaNumberField' }, + { name: 'numberField2', __typename: 'SchemaNumberField' }, + { name: 'booleanField1', __typename: 'SchemaBooleanField' }, + { name: 'booleanField2', __typename: 'SchemaBooleanField' }, + { name: 'arrayField1', __typename: 'SchemaArrayField' }, + { name: 'arrayField2', __typename: 'SchemaArrayField' }, + { name: 'objectField1', __typename: 'SchemaObjectField' }, + { name: 'objectField2', __typename: 'SchemaObjectField' }, + { name: 'dateField1', __typename: 'SchemaDateField' }, + { name: 'dateField2', __typename: 'SchemaDateField' }, + { name: 'fileField1', __typename: 'SchemaFileField' }, + { name: 'fileField2', __typename: 'SchemaFileField' }, + { + name: 'geoPointField', + __typename: 'SchemaGeoPointField', + }, + { name: 'polygonField1', __typename: 'SchemaPolygonField' }, + { name: 'polygonField2', __typename: 'SchemaPolygonField' }, + { name: 'bytesField1', __typename: 'SchemaBytesField' }, + { name: 'bytesField2', __typename: 'SchemaBytesField' }, + { + name: 'pointerField1', + __typename: 'SchemaPointerField', + targetClassName: 'Class1', + }, + { + name: 'pointerField2', + __typename: 'SchemaPointerField', + targetClassName: 'Class6', + }, + { + name: 'relationField1', + __typename: 'SchemaRelationField', + targetClassName: 'Class1', + }, + { + name: 'relationField2', + __typename: 'SchemaRelationField', + targetClassName: 'Class6', + }, + { name: 'ACL', __typename: 'SchemaACLField' }, + ], + __typename: 'Class', + }, + }, + }); + } catch (e) { + handleError(e); + } + }); + + it('should require master key to create a new class', async () => { + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + createClass(name: "SomeClass") { + name + } + } + `, + }); + } catch (e) { + handleError(e); + } + }); + }); + describe('Objects Queries', () => { describe('Get', () => { it('should return a class object using generic query', async () => { @@ -6112,7 +6401,7 @@ describe('ParseGraphQLServer', () => { `, variables: { schemaFields: { - addGeoPoints: [{ name: 'someField' }], + addGeoPoint: { name: 'someField' }, }, }, }); diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index c31945394f..00deb76f85 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -23,7 +23,6 @@ const RESERVED_GRAPHQL_TYPE_NAMES = [ 'Float', 'ID', 'ArrayResult', - 'SchemaArrayField', 'Query', 'Mutation', 'Subscription', @@ -110,7 +109,6 @@ class ParseGraphQLSchema { ); defaultGraphQLTypes.loadArrayResult(this, parseClasses); - classSchemaTypes.loadSchemaArrayField(this); defaultGraphQLQueries.load(this); defaultGraphQLMutations.load(this); diff --git a/src/GraphQL/loaders/classSchemaTypes.js b/src/GraphQL/loaders/classSchemaTypes.js index 42eb3ec8e4..76b9dcea88 100644 --- a/src/GraphQL/loaders/classSchemaTypes.js +++ b/src/GraphQL/loaders/classSchemaTypes.js @@ -1,26 +1,17 @@ import { GraphQLNonNull, GraphQLString, - GraphQLBoolean, GraphQLInputObjectType, GraphQLList, GraphQLObjectType, GraphQLInterfaceType, } from 'graphql'; -import { transformInputTypeToGraphQL } from '../transformers/inputType'; -import { transformOutputTypeToGraphQL } from '../transformers/outputType'; const SCHEMA_FIELD_NAME_ATT = { description: 'This is the field name.', type: new GraphQLNonNull(GraphQLString), }; -const SCHEMA_FIELD_IS_REQUIRED_ATT = { - description: - 'This is the flag to specify whether the field is required or not.', - type: GraphQLBoolean, -}; - const SCHEMA_FIELD_INPUT = new GraphQLInputObjectType({ name: 'SchemaFieldInput', description: @@ -61,11 +52,6 @@ const SCHEMA_STRING_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaStringFieldInput is used to specify a field of type string for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('String'), - }, }, }); @@ -76,11 +62,6 @@ const SCHEMA_STRING_FIELD = new GraphQLObjectType({ interfaces: [SCHEMA_FIELD], fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('String'), - }, }, }); @@ -90,11 +71,6 @@ const SCHEMA_NUMBER_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaNumberFieldInput is used to specify a field of type number for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('Number'), - }, }, }); @@ -105,11 +81,6 @@ const SCHEMA_NUMBER_FIELD = new GraphQLObjectType({ interfaces: [SCHEMA_FIELD], fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('Number'), - }, }, }); @@ -119,11 +90,6 @@ const SCHEMA_BOOLEAN_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaBooleanFieldInput is used to specify a field of type boolean for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('Boolean'), - }, }, }); @@ -134,11 +100,6 @@ const SCHEMA_BOOLEAN_FIELD = new GraphQLObjectType({ interfaces: [SCHEMA_FIELD], fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('Boolean'), - }, }, }); @@ -148,11 +109,16 @@ const SCHEMA_ARRAY_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaArrayFieldInput is used to specify a field of type array for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('Array'), - }, + }, +}); + +const SCHEMA_ARRAY_FIELD = new GraphQLObjectType({ + name: 'SchemaArrayField', + description: + 'The SchemaArrayField is used to return information of an Array field.', + interfaces: [SCHEMA_FIELD], + fields: { + name: SCHEMA_FIELD_NAME_ATT, }, }); @@ -162,11 +128,6 @@ const SCHEMA_OBJECT_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaObjectFieldInput is used to specify a field of type object for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('Object'), - }, }, }); @@ -177,11 +138,6 @@ const SCHEMA_OBJECT_FIELD = new GraphQLObjectType({ interfaces: [SCHEMA_FIELD], fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('Object'), - }, }, }); @@ -191,11 +147,6 @@ const SCHEMA_DATE_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaDateFieldInput is used to specify a field of type date for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('Date'), - }, }, }); @@ -206,11 +157,6 @@ const SCHEMA_DATE_FIELD = new GraphQLObjectType({ interfaces: [SCHEMA_FIELD], fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('Date'), - }, }, }); @@ -220,11 +166,6 @@ const SCHEMA_FILE_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaFileFieldInput is used to specify a field of type file for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('File'), - }, }, }); @@ -235,11 +176,6 @@ const SCHEMA_FILE_FIELD = new GraphQLObjectType({ interfaces: [SCHEMA_FIELD], fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('File'), - }, }, }); @@ -249,11 +185,6 @@ const SCHEMA_GEO_POINT_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaGeoPointFieldInput is used to specify a field of type geo point for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('GeoPoint'), - }, }, }); @@ -264,11 +195,6 @@ const SCHEMA_GEO_POINT_FIELD = new GraphQLObjectType({ interfaces: [SCHEMA_FIELD], fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('GeoPoint'), - }, }, }); @@ -278,11 +204,6 @@ const SCHEMA_POLYGON_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaPolygonFieldInput is used to specify a field of type polygon for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('Polygon'), - }, }, }); @@ -293,11 +214,6 @@ const SCHEMA_POLYGON_FIELD = new GraphQLObjectType({ interfaces: [SCHEMA_FIELD], fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('Polygon'), - }, }, }); @@ -307,11 +223,6 @@ const SCHEMA_BYTES_FIELD_INPUT = new GraphQLInputObjectType({ 'The SchemaBytesFieldInput is used to specify a field of type bytes for an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('Bytes'), - }, }, }); @@ -322,11 +233,6 @@ const SCHEMA_BYTES_FIELD = new GraphQLObjectType({ interfaces: [SCHEMA_FIELD], fields: { name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('Bytes'), - }, }, }); @@ -342,11 +248,6 @@ const SCHEMA_POINTER_FIELD_INPUT = new GraphQLInputObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, targetClassName: TARGET_CLASS_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformInputTypeToGraphQL('Pointer'), - }, }, }); @@ -358,11 +259,6 @@ const SCHEMA_POINTER_FIELD = new GraphQLObjectType({ fields: { name: SCHEMA_FIELD_NAME_ATT, targetClassName: TARGET_CLASS_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('Pointer'), - }, }, }); @@ -434,10 +330,10 @@ const SCHEMA_FIELDS_INPUT = new GraphQLInputObjectType({ description: 'These are the File fields to be added to the class schema.', type: new GraphQLList(new GraphQLNonNull(SCHEMA_FILE_FIELD_INPUT)), }, - addGeoPoints: { + addGeoPoint: { description: - 'These are the Geo Point fields to be added to the class schema.', - type: new GraphQLList(new GraphQLNonNull(SCHEMA_GEO_POINT_FIELD_INPUT)), + 'This is the Geo Point field to be added to the class schema. Currently it is supported only one GeoPoint field per Class.', + type: SCHEMA_GEO_POINT_FIELD_INPUT, }, addPolygons: { description: @@ -494,6 +390,7 @@ const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(SCHEMA_BOOLEAN_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_BOOLEAN_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_ARRAY_FIELD_INPUT, true); + parseGraphQLSchema.addGraphQLType(SCHEMA_ARRAY_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_OBJECT_FIELD_INPUT, true); parseGraphQLSchema.addGraphQLType(SCHEMA_OBJECT_FIELD, true); parseGraphQLSchema.addGraphQLType(SCHEMA_DATE_FIELD_INPUT, true); @@ -515,28 +412,8 @@ const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(CLASS, true); }; -let SCHEMA_ARRAY_FIELD; - -const loadSchemaArrayField = parseGraphQLSchema => { - SCHEMA_ARRAY_FIELD = new GraphQLObjectType({ - name: 'SchemaArrayField', - description: - 'The SchemaArrayField is used to return information of an Array field.', - fields: { - name: SCHEMA_FIELD_NAME_ATT, - isRequired: SCHEMA_FIELD_IS_REQUIRED_ATT, - defaultValue: { - description: 'This is the field default value.', - type: transformOutputTypeToGraphQL('Array'), - }, - }, - }); - parseGraphQLSchema.addGraphQLType(SCHEMA_ARRAY_FIELD, true, true); -}; - export { SCHEMA_FIELD_NAME_ATT, - SCHEMA_FIELD_IS_REQUIRED_ATT, SCHEMA_FIELD_INPUT, SCHEMA_STRING_FIELD_INPUT, SCHEMA_STRING_FIELD, @@ -545,6 +422,7 @@ export { SCHEMA_BOOLEAN_FIELD_INPUT, SCHEMA_BOOLEAN_FIELD, SCHEMA_ARRAY_FIELD_INPUT, + SCHEMA_ARRAY_FIELD, SCHEMA_OBJECT_FIELD_INPUT, SCHEMA_OBJECT_FIELD, SCHEMA_DATE_FIELD_INPUT, @@ -567,6 +445,4 @@ export { CLASS_NAME_ATT, CLASS, load, - SCHEMA_ARRAY_FIELD, - loadSchemaArrayField, }; diff --git a/src/GraphQL/transformers/schemaFields.js b/src/GraphQL/transformers/schemaFields.js index 5a7d5cae27..06d22cacfd 100644 --- a/src/GraphQL/transformers/schemaFields.js +++ b/src/GraphQL/transformers/schemaFields.js @@ -1,3 +1,5 @@ +import Parse from 'parse/node'; + const transformToParse = graphQLSchemaFields => { if (!graphQLSchemaFields) { return {}; @@ -14,23 +16,18 @@ const transformToParse = graphQLSchemaFields => { ) { return parseSchemaFields; } - if (type === 'Relation') { - return { - ...parseSchemaFields, - [field.name]: { - type, - targetClass: field.targetClassName, - }, - }; + if (parseSchemaFields[field.name]) { + throw new Parse.Error( + Parse.Error.InvalidFieldName, + `Duplicated field name: ${field.name}` + ); } - if (type === 'Pointer') { + if (type === 'Relation' || type === 'Pointer') { return { ...parseSchemaFields, [field.name]: { type, targetClass: field.targetClassName, - isRequired: field.isRequired, - defaultValue: field.defaultValue, }, }; } @@ -38,8 +35,6 @@ const transformToParse = graphQLSchemaFields => { ...parseSchemaFields, [field.name]: { type, - isRequired: field.isRequired, - defaultValue: field.defaultValue, }, }; }; @@ -86,8 +81,8 @@ const transformToParse = graphQLSchemaFields => { parseSchemaFields ); } - if (graphQLSchemaFields.addGeoPoints) { - parseSchemaFields = graphQLSchemaFields.addGeoPoints.reduce( + if (graphQLSchemaFields.addGeoPoint) { + parseSchemaFields = [graphQLSchemaFields.addGeoPoint].reduce( reducerGenerator('GeoPoint'), parseSchemaFields ); @@ -124,9 +119,7 @@ const transformToGraphQL = parseSchemaFields => { return Object.keys(parseSchemaFields).map(name => ({ name, type: parseSchemaFields[name].type, - targetClass: parseSchemaFields[name].targetClass, - isRequired: parseSchemaFields[name].isRequired, - defaultValue: parseSchemaFields[name].defaultValue, + targetClassName: parseSchemaFields[name].targetClass, })); }; From 4423c9ba3611f68baa0c5d0cce6238dadc1e7979 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 20:05:59 -0700 Subject: [PATCH 40/60] Enforce master key --- spec/ParseGraphQLServer.spec.js | 8 +++++++- src/GraphQL/loaders/classSchemaMutations.js | 3 +++ src/GraphQL/parseGraphQLUtils.js | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 04bbefd2c7..456d38a129 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -1875,8 +1875,14 @@ describe('ParseGraphQLServer', () => { } `, }); + fail('should fail'); } catch (e) { - handleError(e); + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.OPERATION_FORBIDDEN + ); + expect(e.graphQLErrors[0].message).toEqual( + 'unauthorized: master key is required' + ); } }); }); diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js index aac0375d33..d9431b3bbf 100644 --- a/src/GraphQL/loaders/classSchemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -5,6 +5,7 @@ import { transformToParse, transformToGraphQL, } from '../transformers/schemaFields'; +import { enforceMasterKeyAccess } from '../parseGraphQLUtils'; const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLMutation( @@ -25,6 +26,8 @@ const load = parseGraphQLSchema => { const { name, schemaFields } = args; const { config, auth } = context; + enforceMasterKeyAccess(auth); + if (auth.isReadOnly) { throw new Parse.Error( Parse.Error.OPERATION_FORBIDDEN, diff --git a/src/GraphQL/parseGraphQLUtils.js b/src/GraphQL/parseGraphQLUtils.js index 9d75fb3e7a..fea4fb478a 100644 --- a/src/GraphQL/parseGraphQLUtils.js +++ b/src/GraphQL/parseGraphQLUtils.js @@ -1,6 +1,15 @@ import Parse from 'parse/node'; import { ApolloError } from 'apollo-server-core'; +export function enforceMasterKeyAccess(auth) { + if (!auth.isMaster) { + throw new Parse.Error( + Parse.Error.OPERATION_FORBIDDEN, + 'unauthorized: master key is required' + ); + } +} + export function toGraphQLError(error) { let code, message; if (error instanceof Parse.Error) { From 496eb342f45aaad8cf456f319ef54b694614e2ff Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 20:10:47 -0700 Subject: [PATCH 41/60] Fix tests --- spec/ParseGraphQLServer.spec.js | 75 +++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 456d38a129..5b728b4dd0 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -1752,6 +1752,11 @@ describe('ParseGraphQLServer', () => { } } `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); expect(result).toEqual({ data: { @@ -4830,6 +4835,11 @@ describe('ParseGraphQLServer', () => { addStrings: [{ name: 'someField' }], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -4896,6 +4906,11 @@ describe('ParseGraphQLServer', () => { addNumbers: [{ name: 'someField' }], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -4962,6 +4977,11 @@ describe('ParseGraphQLServer', () => { addNumbers: [{ name: 'someField' }], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -5032,6 +5052,11 @@ describe('ParseGraphQLServer', () => { ], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -5117,6 +5142,11 @@ describe('ParseGraphQLServer', () => { addDates: [{ name: 'someField' }], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -5175,6 +5205,11 @@ describe('ParseGraphQLServer', () => { } } `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); const schema = await new Parse.Schema('SomeClass').get(); @@ -5781,6 +5816,11 @@ describe('ParseGraphQLServer', () => { addFiles: [{ name: 'someField' }], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -5887,6 +5927,11 @@ describe('ParseGraphQLServer', () => { addObjects: [{ name: 'someField' }], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -5992,6 +6037,11 @@ describe('ParseGraphQLServer', () => { } } `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -6127,6 +6177,11 @@ describe('ParseGraphQLServer', () => { addArrays: [{ name: 'someField' }], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -6238,6 +6293,11 @@ describe('ParseGraphQLServer', () => { } } `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -6330,6 +6390,11 @@ describe('ParseGraphQLServer', () => { addBytes: [{ name: 'someField' }], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -6410,6 +6475,11 @@ describe('ParseGraphQLServer', () => { addGeoPoint: { name: 'someField' }, }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); @@ -6493,6 +6563,11 @@ describe('ParseGraphQLServer', () => { addPolygons: [{ name: 'somePolygonField' }], }, }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, }); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); From 98763e21670002505577b648d7ded5e535279467 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 27 Aug 2019 20:21:40 -0700 Subject: [PATCH 42/60] Duplicated field test --- spec/ParseGraphQLServer.spec.js | 33 ++++++++++++++++++++++++ src/GraphQL/transformers/schemaFields.js | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 5b728b4dd0..dbf4ec2547 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -1890,6 +1890,39 @@ describe('ParseGraphQLServer', () => { ); } }); + + it('should not allow duplicated field names', async () => { + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + createClass( + name: "SomeClass" + schemaFields: { + addStrings: [{ name: "someField" }] + addNumbers: [{ name: "someField" }] + } + ) { + name + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + fail('should fail'); + } catch (e) { + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.INVALID_KEY_NAME + ); + expect(e.graphQLErrors[0].message).toEqual( + 'Duplicated field name: someField' + ); + } + }); }); describe('Objects Queries', () => { diff --git a/src/GraphQL/transformers/schemaFields.js b/src/GraphQL/transformers/schemaFields.js index 06d22cacfd..1bfb0086ab 100644 --- a/src/GraphQL/transformers/schemaFields.js +++ b/src/GraphQL/transformers/schemaFields.js @@ -18,7 +18,7 @@ const transformToParse = graphQLSchemaFields => { } if (parseSchemaFields[field.name]) { throw new Parse.Error( - Parse.Error.InvalidFieldName, + Parse.Error.INVALID_KEY_NAME, `Duplicated field name: ${field.name}` ); } From c15260e33b0d080df8f38d21a9de4e9aede180df Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 00:00:58 -0700 Subject: [PATCH 43/60] updateClass mutation --- spec/ParseGraphQLServer.spec.js | 312 +++++++++++++++++++- src/GraphQL/ParseGraphQLSchema.js | 1 + src/GraphQL/loaders/classSchemaMutations.js | 50 ++++ src/GraphQL/loaders/classSchemaQueries.js | 21 ++ src/GraphQL/transformers/schemaFields.js | 25 +- 5 files changed, 406 insertions(+), 3 deletions(-) create mode 100644 src/GraphQL/loaders/classSchemaQueries.js diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index dbf4ec2547..6b9101a7c1 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -1735,6 +1735,7 @@ describe('ParseGraphQLServer', () => { { name: "bytesField3" } { name: "pointerField3" } { name: "relationField3" } + { name: "doesNotExist" } ] } ) { @@ -1891,7 +1892,7 @@ describe('ParseGraphQLServer', () => { } }); - it('should not allow duplicated field names', async () => { + it('should not allow duplicated field names when creating', async () => { try { await apolloClient.mutate({ mutation: gql` @@ -1923,6 +1924,315 @@ describe('ParseGraphQLServer', () => { ); } }); + + it('should update an existing class', async () => { + try { + const result = await apolloClient.mutate({ + mutation: gql` + mutation { + createClass( + name: "MyNewClass" + schemaFields: { addStrings: [{ name: "willBeRemoved" }] } + ) { + name + schemaFields { + name + __typename + } + } + updateClass( + name: "MyNewClass" + schemaFields: { + addStrings: [ + { name: "stringField1" } + { name: "stringField2" } + { name: "stringField3" } + ] + addNumbers: [ + { name: "numberField1" } + { name: "numberField2" } + { name: "numberField3" } + ] + addBooleans: [ + { name: "booleanField1" } + { name: "booleanField2" } + { name: "booleanField3" } + ] + addArrays: [ + { name: "arrayField1" } + { name: "arrayField2" } + { name: "arrayField3" } + ] + addObjects: [ + { name: "objectField1" } + { name: "objectField2" } + { name: "objectField3" } + ] + addDates: [ + { name: "dateField1" } + { name: "dateField2" } + { name: "dateField3" } + ] + addFiles: [ + { name: "fileField1" } + { name: "fileField2" } + { name: "fileField3" } + ] + addGeoPoint: { name: "geoPointField" } + addPolygons: [ + { name: "polygonField1" } + { name: "polygonField2" } + { name: "polygonField3" } + ] + addBytes: [ + { name: "bytesField1" } + { name: "bytesField2" } + { name: "bytesField3" } + ] + addPointers: [ + { name: "pointerField1", targetClassName: "Class1" } + { name: "pointerField2", targetClassName: "Class6" } + { name: "pointerField3", targetClassName: "Class2" } + ] + addRelations: [ + { name: "relationField1", targetClassName: "Class1" } + { name: "relationField2", targetClassName: "Class6" } + { name: "relationField3", targetClassName: "Class2" } + ] + remove: [ + { name: "willBeRemoved" } + { name: "stringField3" } + { name: "numberField3" } + { name: "booleanField3" } + { name: "arrayField3" } + { name: "objectField3" } + { name: "dateField3" } + { name: "fileField3" } + { name: "polygonField3" } + { name: "bytesField3" } + { name: "pointerField3" } + { name: "relationField3" } + { name: "doesNotExist" } + ] + } + ) { + name + schemaFields { + name + __typename + ... on SchemaPointerField { + targetClassName + } + ... on SchemaRelationField { + targetClassName + } + } + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + result.data.updateClass.schemaFields = result.data.updateClass.schemaFields.sort( + (a, b) => (a.name > b.name ? 1 : -1) + ); + expect(result).toEqual({ + data: { + createClass: { + name: 'MyNewClass', + schemaFields: [ + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'willBeRemoved', __typename: 'SchemaStringField' }, + { name: 'ACL', __typename: 'SchemaACLField' }, + ], + __typename: 'Class', + }, + updateClass: { + name: 'MyNewClass', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'arrayField1', __typename: 'SchemaArrayField' }, + { name: 'arrayField2', __typename: 'SchemaArrayField' }, + { name: 'booleanField1', __typename: 'SchemaBooleanField' }, + { name: 'booleanField2', __typename: 'SchemaBooleanField' }, + { name: 'bytesField1', __typename: 'SchemaBytesField' }, + { name: 'bytesField2', __typename: 'SchemaBytesField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'dateField1', __typename: 'SchemaDateField' }, + { name: 'dateField2', __typename: 'SchemaDateField' }, + { name: 'fileField1', __typename: 'SchemaFileField' }, + { name: 'fileField2', __typename: 'SchemaFileField' }, + { + name: 'geoPointField', + __typename: 'SchemaGeoPointField', + }, + { name: 'numberField1', __typename: 'SchemaNumberField' }, + { name: 'numberField2', __typename: 'SchemaNumberField' }, + { name: 'objectField1', __typename: 'SchemaObjectField' }, + { name: 'objectField2', __typename: 'SchemaObjectField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { + name: 'pointerField1', + __typename: 'SchemaPointerField', + targetClassName: 'Class1', + }, + { + name: 'pointerField2', + __typename: 'SchemaPointerField', + targetClassName: 'Class6', + }, + { name: 'polygonField1', __typename: 'SchemaPolygonField' }, + { name: 'polygonField2', __typename: 'SchemaPolygonField' }, + { + name: 'relationField1', + __typename: 'SchemaRelationField', + targetClassName: 'Class1', + }, + { + name: 'relationField2', + __typename: 'SchemaRelationField', + targetClassName: 'Class6', + }, + { name: 'stringField1', __typename: 'SchemaStringField' }, + { name: 'stringField2', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + }, + }); + } catch (e) { + handleError(e); + } + }); + + it('should require master key to update an existing class', async () => { + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + createClass(name: "SomeClass") { + name + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + } catch (e) { + handleError(e); + } + + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + updateClass(name: "SomeClass") { + name + } + } + `, + }); + fail('should fail'); + } catch (e) { + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.OPERATION_FORBIDDEN + ); + expect(e.graphQLErrors[0].message).toEqual( + 'unauthorized: master key is required' + ); + } + }); + + it('should not allow duplicated field names when updating', async () => { + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + createClass( + name: "SomeClass" + schemaFields: { addStrings: [{ name: "someField" }] } + ) { + name + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + } catch (e) { + handleError(e); + } + + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + updateClass( + name: "SomeClass" + schemaFields: { addNumbers: [{ name: "someField" }] } + ) { + name + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + fail('should fail'); + } catch (e) { + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.INVALID_KEY_NAME + ); + expect(e.graphQLErrors[0].message).toEqual( + 'Duplicated field name: someField' + ); + } + }); + + it('should fail if updating an inexistent class', async () => { + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + updateClass( + name: "SomeInexistentClass" + schemaFields: { addNumbers: [{ name: "someField" }] } + ) { + name + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + fail('should fail'); + } catch (e) { + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.INVALID_CLASS_NAME + ); + expect(e.graphQLErrors[0].message).toEqual( + 'Class SomeInexistentClass does not exist.' + ); + } + }); }); describe('Objects Queries', () => { diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index 00deb76f85..de0b1c9311 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -38,6 +38,7 @@ const RESERVED_GRAPHQL_MUTATION_NAMES = [ 'createFile', 'callCloudCode', 'createClass', + 'updateClass', 'update', 'delete', ]; diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js index d9431b3bbf..8f47a73695 100644 --- a/src/GraphQL/loaders/classSchemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -6,6 +6,7 @@ import { transformToGraphQL, } from '../transformers/schemaFields'; import { enforceMasterKeyAccess } from '../parseGraphQLUtils'; +import { getClass } from './classSchemaQueries'; const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLMutation( @@ -52,6 +53,55 @@ const load = parseGraphQLSchema => { true, true ); + + parseGraphQLSchema.addGraphQLMutation( + 'updateClass', + { + description: + 'The updateClass mutation can be used to update the schema for an existing object class.', + args: { + name: classSchemaTypes.CLASS_NAME_ATT, + schemaFields: { + description: "These are the schema's fields of the object class.", + type: classSchemaTypes.SCHEMA_FIELDS_INPUT, + }, + }, + type: new GraphQLNonNull(classSchemaTypes.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); + } + }, + }, + true, + true + ); }; export { load }; diff --git a/src/GraphQL/loaders/classSchemaQueries.js b/src/GraphQL/loaders/classSchemaQueries.js new file mode 100644 index 0000000000..28d5a80755 --- /dev/null +++ b/src/GraphQL/loaders/classSchemaQueries.js @@ -0,0 +1,21 @@ +import Parse from 'parse/node'; + +const getClass = async (name, schema) => { + try { + return await schema.getOneSchema(name, true); + } catch (e) { + if (e === undefined) { + throw new Parse.Error( + Parse.Error.INVALID_CLASS_NAME, + `Class ${name} does not exist.` + ); + } else { + throw new Parse.Error( + Parse.Error.INTERNAL_SERVER_ERROR, + 'Database adapter error.' + ); + } + } +}; + +export { getClass }; diff --git a/src/GraphQL/transformers/schemaFields.js b/src/GraphQL/transformers/schemaFields.js index 1bfb0086ab..9d94e6f80e 100644 --- a/src/GraphQL/transformers/schemaFields.js +++ b/src/GraphQL/transformers/schemaFields.js @@ -1,6 +1,6 @@ import Parse from 'parse/node'; -const transformToParse = graphQLSchemaFields => { +const transformToParse = (graphQLSchemaFields, existingFields) => { if (!graphQLSchemaFields) { return {}; } @@ -8,6 +8,18 @@ const transformToParse = graphQLSchemaFields => { let parseSchemaFields = {}; const reducerGenerator = type => (parseSchemaFields, field) => { + if (type === 'Remove') { + if (existingFields[field.name]) { + return { + ...parseSchemaFields, + [field.name]: { + __op: 'Delete', + }, + }; + } else { + return parseSchemaFields; + } + } if ( graphQLSchemaFields.remove && graphQLSchemaFields.remove.find( @@ -16,7 +28,10 @@ const transformToParse = graphQLSchemaFields => { ) { return parseSchemaFields; } - if (parseSchemaFields[field.name]) { + if ( + parseSchemaFields[field.name] || + (existingFields && existingFields[field.name]) + ) { throw new Parse.Error( Parse.Error.INVALID_KEY_NAME, `Duplicated field name: ${field.name}` @@ -111,6 +126,12 @@ const transformToParse = graphQLSchemaFields => { parseSchemaFields ); } + if (existingFields && graphQLSchemaFields.remove) { + parseSchemaFields = graphQLSchemaFields.remove.reduce( + reducerGenerator('Remove'), + parseSchemaFields + ); + } return parseSchemaFields; }; From 2e081e5186fc5323dc17e1fc4444566997118e6b Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 00:13:01 -0700 Subject: [PATCH 44/60] Remove update generic mutation tests --- spec/ParseGraphQLServer.spec.js | 47 +++++---------------------------- 1 file changed, 6 insertions(+), 41 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 6b9101a7c1..61938a52d7 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -3976,40 +3976,6 @@ describe('ParseGraphQLServer', () => { }); describe('Update', () => { - it('should return UpdateResult object using generic mutation', async () => { - const obj = new Parse.Object('SomeClass'); - obj.set('someField1', 'someField1Value1'); - obj.set('someField2', 'someField2Value1'); - await obj.save(); - - const result = await apolloClient.mutate({ - mutation: gql` - mutation UpdateSomeObject($objectId: ID!, $fields: Object) { - update( - className: "SomeClass" - objectId: $objectId - fields: $fields - ) { - updatedAt - } - } - `, - variables: { - objectId: obj.id, - fields: { - someField1: 'someField1Value2', - }, - }, - }); - - expect(result.data.update.updatedAt).toBeDefined(); - - await obj.fetch(); - - expect(obj.get('someField1')).toEqual('someField1Value2'); - expect(obj.get('someField2')).toEqual('someField2Value1'); - }); - it('should return specific type object using class specific mutation', async () => { const obj = new Parse.Object('Customer'); obj.set('someField1', 'someField1Value1'); @@ -4091,16 +4057,16 @@ describe('ParseGraphQLServer', () => { it('should respect level permissions', async () => { await prepareData(); - function updateObject(className, objectId, fields, headers) { - return apolloClient.mutate({ + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + + async function updateObject(className, objectId, fields, headers) { + return await apolloClient.mutate({ mutation: gql` mutation UpdateSomeObject( - $className: String! $objectId: ID! - $fields: Object + $fields: Update${className}FieldsInput ) { - update( - className: $className + update: update${className}( objectId: $objectId fields: $fields ) { @@ -4109,7 +4075,6 @@ describe('ParseGraphQLServer', () => { } `, variables: { - className, objectId, fields, }, From d508528d8e89b98a8bc984b9df2e2d0f047aa4e7 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 00:15:14 -0700 Subject: [PATCH 45/60] Remove update generic mutation --- src/GraphQL/ParseGraphQLSchema.js | 1 - src/GraphQL/loaders/objectsMutations.js | 33 ------------------------- 2 files changed, 34 deletions(-) diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index de0b1c9311..661f5718a1 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -39,7 +39,6 @@ const RESERVED_GRAPHQL_MUTATION_NAMES = [ 'callCloudCode', 'createClass', 'updateClass', - 'update', 'delete', ]; diff --git a/src/GraphQL/loaders/objectsMutations.js b/src/GraphQL/loaders/objectsMutations.js index 9e96bb16c8..6f523deb37 100644 --- a/src/GraphQL/loaders/objectsMutations.js +++ b/src/GraphQL/loaders/objectsMutations.js @@ -39,39 +39,6 @@ const deleteObject = async (className, objectId, config, auth, info) => { }; const load = parseGraphQLSchema => { - parseGraphQLSchema.addGraphQLMutation( - 'update', - { - description: - 'The update mutation can be used to update an object of a certain class.', - args: { - className: defaultGraphQLTypes.CLASS_NAME_ATT, - objectId: defaultGraphQLTypes.OBJECT_ID_ATT, - fields: defaultGraphQLTypes.FIELDS_ATT, - }, - type: new GraphQLNonNull(defaultGraphQLTypes.UPDATE_RESULT), - async resolve(_source, args, context) { - try { - const { className, objectId, fields } = args; - const { config, auth, info } = context; - - return await updateObject( - className, - objectId, - fields, - config, - auth, - info - ); - } catch (e) { - parseGraphQLSchema.handleError(e); - } - }, - }, - true, - true - ); - parseGraphQLSchema.addGraphQLMutation( 'delete', { From b73662e6d4604179039246a9d4d24ce2eebe9a00 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 01:03:56 -0700 Subject: [PATCH 46/60] deleteClass mutation --- spec/ParseGraphQLServer.spec.js | 131 ++++++++++++++++++++ src/GraphQL/ParseGraphQLSchema.js | 1 + src/GraphQL/loaders/classSchemaMutations.js | 39 ++++++ 3 files changed, 171 insertions(+) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 61938a52d7..a574dd47ac 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -2233,6 +2233,137 @@ describe('ParseGraphQLServer', () => { ); } }); + + it('should delete an existing class', async () => { + try { + const result = await apolloClient.mutate({ + mutation: gql` + mutation { + createClass( + name: "MyNewClass" + schemaFields: { addStrings: [{ name: "willBeRemoved" }] } + ) { + name + schemaFields { + name + __typename + } + } + deleteClass(name: "MyNewClass") { + name + schemaFields { + name + } + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + result.data.deleteClass.schemaFields = result.data.deleteClass.schemaFields.sort( + (a, b) => (a.name > b.name ? 1 : -1) + ); + expect(result).toEqual({ + data: { + createClass: { + name: 'MyNewClass', + schemaFields: [ + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'willBeRemoved', __typename: 'SchemaStringField' }, + { name: 'ACL', __typename: 'SchemaACLField' }, + ], + __typename: 'Class', + }, + deleteClass: { + name: 'MyNewClass', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + { name: 'willBeRemoved', __typename: 'SchemaStringField' }, + ], + __typename: 'Class', + }, + }, + }); + } catch (e) { + handleError(e); + } + }); + + it('should require master key to delete an existing class', async () => { + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + createClass(name: "SomeClass") { + name + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + } catch (e) { + handleError(e); + } + + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + deleteClass(name: "SomeClass") { + name + } + } + `, + }); + fail('should fail'); + } catch (e) { + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.OPERATION_FORBIDDEN + ); + expect(e.graphQLErrors[0].message).toEqual( + 'unauthorized: master key is required' + ); + } + }); + + it('should fail if deleting an inexistent class', async () => { + try { + await apolloClient.mutate({ + mutation: gql` + mutation { + deleteClass(name: "SomeInexistentClass") { + name + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + fail('should fail'); + } catch (e) { + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.INVALID_CLASS_NAME + ); + expect(e.graphQLErrors[0].message).toEqual( + 'Class SomeInexistentClass does not exist.' + ); + } + }); }); describe('Objects Queries', () => { diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index 661f5718a1..50886fdc75 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -39,6 +39,7 @@ const RESERVED_GRAPHQL_MUTATION_NAMES = [ 'callCloudCode', 'createClass', 'updateClass', + 'deleteClass', 'delete', ]; diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/classSchemaMutations.js index 8f47a73695..10bd882881 100644 --- a/src/GraphQL/loaders/classSchemaMutations.js +++ b/src/GraphQL/loaders/classSchemaMutations.js @@ -102,6 +102,45 @@ const load = parseGraphQLSchema => { true, true ); + + parseGraphQLSchema.addGraphQLMutation( + 'deleteClass', + { + description: + 'The deleteClass mutation can be used to delete an existing object class.', + args: { + name: classSchemaTypes.CLASS_NAME_ATT, + }, + type: new GraphQLNonNull(classSchemaTypes.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); + } + }, + }, + true, + true + ); }; export { load }; From edf8067c48633428bb3aaf70f5e74663a9501750 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 01:11:45 -0700 Subject: [PATCH 47/60] Remove delete generic mutation tests --- spec/ParseGraphQLServer.spec.js | 38 ++++++++------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index a574dd47ac..5bd73af485 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -4543,28 +4543,6 @@ describe('ParseGraphQLServer', () => { }); describe('Delete', () => { - it('should return a boolean confirmation using generic mutation', async () => { - const obj = new Parse.Object('SomeClass'); - await obj.save(); - - const result = await apolloClient.mutate({ - mutation: gql` - mutation DeleteSomeObject($objectId: ID!) { - delete(className: "SomeClass", objectId: $objectId) - } - `, - variables: { - objectId: obj.id, - }, - }); - - expect(result.data.delete).toEqual(true); - - await expectAsync( - obj.fetch({ useMasterKey: true }) - ).toBeRejectedWith(jasmine.stringMatching('Object not found')); - }); - it('should return a specific type using class specific mutation', async () => { const obj = new Parse.Object('Customer'); obj.set('someField1', 'someField1Value1'); @@ -4604,18 +4582,20 @@ describe('ParseGraphQLServer', () => { it('should respect level permissions', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + function deleteObject(className, objectId, headers) { return apolloClient.mutate({ mutation: gql` mutation DeleteSomeObject( - $className: String! $objectId: ID! ) { - delete(className: $className, objectId: $objectId) + delete: delete${className}(objectId: $objectId) { + objectId + } } `, variables: { - className, objectId, }, context: { @@ -4648,7 +4628,7 @@ describe('ParseGraphQLServer', () => { ); expect( (await deleteObject(object4.className, object4.id)).data.delete - ).toEqual(true); + ).toEqual({ objectId: object4.id, __typename: 'PublicClass' }); await expectAsync( object4.fetch({ useMasterKey: true }) ).toBeRejectedWith(jasmine.stringMatching('Object not found')); @@ -4656,7 +4636,7 @@ describe('ParseGraphQLServer', () => { (await deleteObject(object1.className, object1.id, { 'X-Parse-Master-Key': 'test', })).data.delete - ).toEqual(true); + ).toEqual({ objectId: object1.id, __typename: 'GraphQLClass' }); await expectAsync( object1.fetch({ useMasterKey: true }) ).toBeRejectedWith(jasmine.stringMatching('Object not found')); @@ -4664,7 +4644,7 @@ describe('ParseGraphQLServer', () => { (await deleteObject(object2.className, object2.id, { 'X-Parse-Session-Token': user2.getSessionToken(), })).data.delete - ).toEqual(true); + ).toEqual({ objectId: object2.id, __typename: 'GraphQLClass' }); await expectAsync( object2.fetch({ useMasterKey: true }) ).toBeRejectedWith(jasmine.stringMatching('Object not found')); @@ -4672,7 +4652,7 @@ describe('ParseGraphQLServer', () => { (await deleteObject(object3.className, object3.id, { 'X-Parse-Session-Token': user5.getSessionToken(), })).data.delete - ).toEqual(true); + ).toEqual({ objectId: object3.id, __typename: 'GraphQLClass' }); await expectAsync( object3.fetch({ useMasterKey: true }) ).toBeRejectedWith(jasmine.stringMatching('Object not found')); From 2df2db0879fe73a01a5b76d28aeeec1492c29297 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 01:15:19 -0700 Subject: [PATCH 48/60] Remove delete generic mutation --- src/GraphQL/ParseGraphQLSchema.js | 1 - .../loaders/defaultGraphQLMutations.js | 2 -- src/GraphQL/loaders/objectsMutations.js | 31 +------------------ 3 files changed, 1 insertion(+), 33 deletions(-) diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index 50886fdc75..eec9fbeef8 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -40,7 +40,6 @@ const RESERVED_GRAPHQL_MUTATION_NAMES = [ 'createClass', 'updateClass', 'deleteClass', - 'delete', ]; class ParseGraphQLSchema { diff --git a/src/GraphQL/loaders/defaultGraphQLMutations.js b/src/GraphQL/loaders/defaultGraphQLMutations.js index e14e2daa3f..a437d9ac53 100644 --- a/src/GraphQL/loaders/defaultGraphQLMutations.js +++ b/src/GraphQL/loaders/defaultGraphQLMutations.js @@ -1,11 +1,9 @@ -import * as objectsMutations from './objectsMutations'; import * as filesMutations from './filesMutations'; import * as usersMutations from './usersMutations'; import * as functionsMutations from './functionsMutations'; import * as classSchemaMutations from './classSchemaMutations'; const load = parseGraphQLSchema => { - objectsMutations.load(parseGraphQLSchema); filesMutations.load(parseGraphQLSchema); usersMutations.load(parseGraphQLSchema); functionsMutations.load(parseGraphQLSchema); diff --git a/src/GraphQL/loaders/objectsMutations.js b/src/GraphQL/loaders/objectsMutations.js index 6f523deb37..aa74e1c8f8 100644 --- a/src/GraphQL/loaders/objectsMutations.js +++ b/src/GraphQL/loaders/objectsMutations.js @@ -1,5 +1,3 @@ -import { GraphQLNonNull, GraphQLBoolean } from 'graphql'; -import * as defaultGraphQLTypes from './defaultGraphQLTypes'; import rest from '../../rest'; const createObject = async (className, fields, config, auth, info) => { @@ -38,31 +36,4 @@ const deleteObject = async (className, objectId, config, auth, info) => { return true; }; -const load = parseGraphQLSchema => { - parseGraphQLSchema.addGraphQLMutation( - 'delete', - { - description: - 'The delete mutation can be used to delete an object of a certain class.', - args: { - className: defaultGraphQLTypes.CLASS_NAME_ATT, - objectId: defaultGraphQLTypes.OBJECT_ID_ATT, - }, - type: new GraphQLNonNull(GraphQLBoolean), - async resolve(_source, args, context) { - try { - const { className, objectId } = args; - const { config, auth, info } = context; - - return await deleteObject(className, objectId, config, auth, info); - } catch (e) { - parseGraphQLSchema.handleError(e); - } - }, - }, - true, - true - ); -}; - -export { createObject, updateObject, deleteObject, load }; +export { createObject, updateObject, deleteObject }; From bb758a32f6ae0fa6eea75e980c1cd8cde034f66c Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 10:15:34 -0700 Subject: [PATCH 49/60] class query --- spec/ParseGraphQLServer.spec.js | 129 +++++++++++++++++++ src/GraphQL/ParseGraphQLSchema.js | 2 +- src/GraphQL/loaders/classSchemaQueries.js | 39 +++++- src/GraphQL/loaders/defaultGraphQLQueries.js | 2 + 4 files changed, 170 insertions(+), 2 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 5bd73af485..3f66428a99 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -2106,6 +2106,88 @@ describe('ParseGraphQLServer', () => { }, }, }); + + const getResult = await apolloClient.query({ + query: gql` + query { + class(name: "MyNewClass") { + name + schemaFields { + name + __typename + ... on SchemaPointerField { + targetClassName + } + ... on SchemaRelationField { + targetClassName + } + } + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + getResult.data.class.schemaFields = getResult.data.class.schemaFields.sort( + (a, b) => (a.name > b.name ? 1 : -1) + ); + expect(getResult.data).toEqual({ + class: { + name: 'MyNewClass', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'arrayField1', __typename: 'SchemaArrayField' }, + { name: 'arrayField2', __typename: 'SchemaArrayField' }, + { name: 'booleanField1', __typename: 'SchemaBooleanField' }, + { name: 'booleanField2', __typename: 'SchemaBooleanField' }, + { name: 'bytesField1', __typename: 'SchemaBytesField' }, + { name: 'bytesField2', __typename: 'SchemaBytesField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'dateField1', __typename: 'SchemaDateField' }, + { name: 'dateField2', __typename: 'SchemaDateField' }, + { name: 'fileField1', __typename: 'SchemaFileField' }, + { name: 'fileField2', __typename: 'SchemaFileField' }, + { + name: 'geoPointField', + __typename: 'SchemaGeoPointField', + }, + { name: 'numberField1', __typename: 'SchemaNumberField' }, + { name: 'numberField2', __typename: 'SchemaNumberField' }, + { name: 'objectField1', __typename: 'SchemaObjectField' }, + { name: 'objectField2', __typename: 'SchemaObjectField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { + name: 'pointerField1', + __typename: 'SchemaPointerField', + targetClassName: 'Class1', + }, + { + name: 'pointerField2', + __typename: 'SchemaPointerField', + targetClassName: 'Class6', + }, + { name: 'polygonField1', __typename: 'SchemaPolygonField' }, + { name: 'polygonField2', __typename: 'SchemaPolygonField' }, + { + name: 'relationField1', + __typename: 'SchemaRelationField', + targetClassName: 'Class1', + }, + { + name: 'relationField2', + __typename: 'SchemaRelationField', + targetClassName: 'Class6', + }, + { name: 'stringField1', __typename: 'SchemaStringField' }, + { name: 'stringField2', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + }); } catch (e) { handleError(e); } @@ -2292,6 +2374,31 @@ describe('ParseGraphQLServer', () => { }, }, }); + + try { + await apolloClient.query({ + query: gql` + query { + class(name: "MyNewClass") { + name + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + fail('should fail'); + } catch (e) { + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.INVALID_CLASS_NAME + ); + expect(e.graphQLErrors[0].message).toEqual( + 'Class MyNewClass does not exist.' + ); + } } catch (e) { handleError(e); } @@ -2364,6 +2471,28 @@ describe('ParseGraphQLServer', () => { ); } }); + + it('should require master key to get an existing class', async () => { + try { + await apolloClient.query({ + query: gql` + query { + class(name: "_User") { + name + } + } + `, + }); + fail('should fail'); + } catch (e) { + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.OPERATION_FORBIDDEN + ); + expect(e.graphQLErrors[0].message).toEqual( + 'unauthorized: master key is required' + ); + } + }); }); describe('Objects Queries', () => { diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index eec9fbeef8..1f55fbfd91 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -30,7 +30,7 @@ const RESERVED_GRAPHQL_TYPE_NAMES = [ 'SignUpFieldsInput', 'LogInFieldsInput', ]; -const RESERVED_GRAPHQL_QUERY_NAMES = ['health', 'viewer', 'get', 'find']; +const RESERVED_GRAPHQL_QUERY_NAMES = ['health', 'viewer', 'class', 'classes']; const RESERVED_GRAPHQL_MUTATION_NAMES = [ 'signUp', 'logIn', diff --git a/src/GraphQL/loaders/classSchemaQueries.js b/src/GraphQL/loaders/classSchemaQueries.js index 28d5a80755..daf844a98e 100644 --- a/src/GraphQL/loaders/classSchemaQueries.js +++ b/src/GraphQL/loaders/classSchemaQueries.js @@ -1,4 +1,8 @@ import Parse from 'parse/node'; +import { GraphQLNonNull } from 'graphql'; +import { transformToGraphQL } from '../transformers/schemaFields'; +import * as classSchemaTypes from './classSchemaTypes'; +import { enforceMasterKeyAccess } from '../parseGraphQLUtils'; const getClass = async (name, schema) => { try { @@ -18,4 +22,37 @@ const getClass = async (name, schema) => { } }; -export { getClass }; +const load = parseGraphQLSchema => { + parseGraphQLSchema.addGraphQLQuery( + 'class', + { + description: + 'The class query can be used to retrieve an existing object class.', + args: { + name: classSchemaTypes.CLASS_NAME_ATT, + }, + type: new GraphQLNonNull(classSchemaTypes.CLASS), + resolve: async (_source, args, context) => { + try { + const { name } = args; + const { config, auth } = context; + + enforceMasterKeyAccess(auth); + + const schema = await config.database.loadSchema({ clearCache: true }); + const parseClass = await getClass(name, schema); + return { + name: parseClass.className, + schemaFields: transformToGraphQL(parseClass.fields), + }; + } catch (e) { + parseGraphQLSchema.handleError(e); + } + }, + }, + true, + true + ); +}; + +export { getClass, load }; diff --git a/src/GraphQL/loaders/defaultGraphQLQueries.js b/src/GraphQL/loaders/defaultGraphQLQueries.js index 07edc21f1e..990b15a67a 100644 --- a/src/GraphQL/loaders/defaultGraphQLQueries.js +++ b/src/GraphQL/loaders/defaultGraphQLQueries.js @@ -1,6 +1,7 @@ import { GraphQLNonNull, GraphQLBoolean } from 'graphql'; import * as objectsQueries from './objectsQueries'; import * as usersQueries from './usersQueries'; +import * as classSchemaQueries from './classSchemaQueries'; const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLQuery( @@ -17,6 +18,7 @@ const load = parseGraphQLSchema => { objectsQueries.load(parseGraphQLSchema); usersQueries.load(parseGraphQLSchema); + classSchemaQueries.load(parseGraphQLSchema); }; export { load }; From bb5e400649ba08a7686b5896bd484727aefe6fb0 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 10:39:41 -0700 Subject: [PATCH 50/60] Classes query --- spec/ParseGraphQLServer.spec.js | 160 ++++++++++++++++++++++ src/GraphQL/loaders/classSchemaQueries.js | 30 +++- 2 files changed, 189 insertions(+), 1 deletion(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 3f66428a99..8c336c6832 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -1865,6 +1865,144 @@ describe('ParseGraphQLServer', () => { }, }, }); + + const findResult = await apolloClient.query({ + query: gql` + query { + classes { + name + schemaFields { + name + __typename + ... on SchemaPointerField { + targetClassName + } + ... on SchemaRelationField { + targetClassName + } + } + } + } + `, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + console.log(findResult.data); + findResult.data.classes = findResult.data.classes + .filter(schemaClass => !schemaClass.name.startsWith('_')) + .sort((a, b) => (a.name > b.name ? 1 : -1)); + findResult.data.classes.forEach(schemaClass => { + schemaClass.schemaFields = schemaClass.schemaFields.sort((a, b) => + a.name > b.name ? 1 : -1 + ); + }); + expect(findResult.data.classes).toEqual([ + { + name: 'Class1', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + { + name: 'Class2', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + { + name: 'Class3', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + { + name: 'Class4', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + { + name: 'Class5', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + { + name: 'Class6', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'arrayField1', __typename: 'SchemaArrayField' }, + { name: 'arrayField2', __typename: 'SchemaArrayField' }, + { name: 'booleanField1', __typename: 'SchemaBooleanField' }, + { name: 'booleanField2', __typename: 'SchemaBooleanField' }, + { name: 'bytesField1', __typename: 'SchemaBytesField' }, + { name: 'bytesField2', __typename: 'SchemaBytesField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'dateField1', __typename: 'SchemaDateField' }, + { name: 'dateField2', __typename: 'SchemaDateField' }, + { name: 'fileField1', __typename: 'SchemaFileField' }, + { name: 'fileField2', __typename: 'SchemaFileField' }, + { + name: 'geoPointField', + __typename: 'SchemaGeoPointField', + }, + { name: 'numberField1', __typename: 'SchemaNumberField' }, + { name: 'numberField2', __typename: 'SchemaNumberField' }, + { name: 'objectField1', __typename: 'SchemaObjectField' }, + { name: 'objectField2', __typename: 'SchemaObjectField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { + name: 'pointerField1', + __typename: 'SchemaPointerField', + targetClassName: 'Class1', + }, + { + name: 'pointerField2', + __typename: 'SchemaPointerField', + targetClassName: 'Class6', + }, + { name: 'polygonField1', __typename: 'SchemaPolygonField' }, + { name: 'polygonField2', __typename: 'SchemaPolygonField' }, + { + name: 'relationField1', + __typename: 'SchemaRelationField', + targetClassName: 'Class1', + }, + { + name: 'relationField2', + __typename: 'SchemaRelationField', + targetClassName: 'Class6', + }, + { name: 'stringField1', __typename: 'SchemaStringField' }, + { name: 'stringField2', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + ]); } catch (e) { handleError(e); } @@ -2493,6 +2631,28 @@ describe('ParseGraphQLServer', () => { ); } }); + + it('should require master key to find the existing classes', async () => { + try { + await apolloClient.query({ + query: gql` + query { + classes { + name + } + } + `, + }); + fail('should fail'); + } catch (e) { + expect(e.graphQLErrors[0].extensions.code).toEqual( + Parse.Error.OPERATION_FORBIDDEN + ); + expect(e.graphQLErrors[0].message).toEqual( + 'unauthorized: master key is required' + ); + } + }); }); describe('Objects Queries', () => { diff --git a/src/GraphQL/loaders/classSchemaQueries.js b/src/GraphQL/loaders/classSchemaQueries.js index daf844a98e..2b0632ccfb 100644 --- a/src/GraphQL/loaders/classSchemaQueries.js +++ b/src/GraphQL/loaders/classSchemaQueries.js @@ -1,5 +1,5 @@ import Parse from 'parse/node'; -import { GraphQLNonNull } from 'graphql'; +import { GraphQLNonNull, GraphQLList } from 'graphql'; import { transformToGraphQL } from '../transformers/schemaFields'; import * as classSchemaTypes from './classSchemaTypes'; import { enforceMasterKeyAccess } from '../parseGraphQLUtils'; @@ -53,6 +53,34 @@ const load = parseGraphQLSchema => { true, true ); + + parseGraphQLSchema.addGraphQLQuery( + 'classes', + { + description: + 'The classes query can be used to retrieve the existing object classes.', + type: new GraphQLNonNull( + new GraphQLList(new GraphQLNonNull(classSchemaTypes.CLASS)) + ), + resolve: async (_source, _args, context) => { + try { + const { config, auth } = context; + + enforceMasterKeyAccess(auth); + + const schema = await config.database.loadSchema({ clearCache: true }); + return (await schema.getAllClasses(true)).map(parseClass => ({ + name: parseClass.className, + schemaFields: transformToGraphQL(parseClass.fields), + })); + } catch (e) { + parseGraphQLSchema.handleError(e); + } + }, + }, + true, + true + ); }; export { getClass, load }; From 72c80e2ab1cce348a4521b09733c43db6c39e5cf Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 11:22:05 -0700 Subject: [PATCH 51/60] Remove get generic query from tests --- spec/ParseGraphQLServer.spec.js | 272 +++++++------------------------- 1 file changed, 59 insertions(+), 213 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 8c336c6832..321349abfa 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -2657,28 +2657,6 @@ describe('ParseGraphQLServer', () => { describe('Objects Queries', () => { describe('Get', () => { - it('should return a class object using generic query', async () => { - const obj = new Parse.Object('SomeClass'); - obj.set('someField', 'someValue'); - await obj.save(); - - const result = (await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "SomeClass", objectId: $objectId) - } - `, - variables: { - objectId: obj.id, - }, - })).data.get; - - expect(result.objectId).toEqual(obj.id); - expect(result.someField).toEqual('someValue'); - expect(new Date(result.createdAt)).toEqual(obj.createdAt); - expect(new Date(result.updatedAt)).toEqual(obj.updatedAt); - }); - it('should return a class object using class specific query', async () => { const obj = new Parse.Object('Customer'); obj.set('someField', 'someValue'); @@ -2905,10 +2883,11 @@ describe('ParseGraphQLServer', () => { const specificQueryResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - ${className.charAt(0).toLowerCase() + + get: ${className.charAt(0).toLowerCase() + className.slice(1)}(objectId: $objectId) { objectId createdAt + someField } } `, @@ -2920,28 +2899,7 @@ describe('ParseGraphQLServer', () => { }, }); - const genericQueryResult = await apolloClient.query({ - query: gql` - query GetSomeObject($className: String!, $objectId: ID!) { - get(className: $className, objectId: $objectId) - } - `, - variables: { - className, - objectId, - }, - context: { - headers, - }, - }); - - expect(genericQueryResult.objectId).toEqual( - specificQueryResult.objectId - ); - expect(genericQueryResult.createdAt).toEqual( - specificQueryResult.createdAt - ); - return genericQueryResult; + return specificQueryResult; } await Promise.all( @@ -3033,59 +2991,15 @@ describe('ParseGraphQLServer', () => { ).toEqual('someValue4'); }); - it('should not bring session token of another user', async () => { - await prepareData(); - - const result = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "_User", objectId: $objectId) - } - `, - variables: { - objectId: user2.id, - }, - context: { - headers: { - 'X-Parse-Session-Token': user1.getSessionToken(), - }, - }, - }); - expect(result.data.get.sessionToken).toBeUndefined(); - }); - - it('should not bring session token of current user', async () => { - await prepareData(); - - const result = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "_User", objectId: $objectId) - } - `, - variables: { - objectId: user1.id, - }, - context: { - headers: { - 'X-Parse-Session-Token': user1.getSessionToken(), - }, - }, - }); - expect(result.data.get.sessionToken).toBeUndefined(); - }); - it('should support keys argument', async () => { await prepareData(); const result1 = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get( - className: "GraphQLClass" - objectId: $objectId - keys: "someField" - ) + get: graphQLClass(objectId: $objectId) { + someField + } } `, variables: { @@ -3101,11 +3015,12 @@ describe('ParseGraphQLServer', () => { const result2 = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get( - className: "GraphQLClass" - objectId: $objectId - keys: "someField,pointerToUser" - ) + get: graphQLClass(objectId: $objectId) { + someField + pointerToUser { + objectId + } + } } `, variables: { @@ -3132,7 +3047,11 @@ describe('ParseGraphQLServer', () => { const result1 = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get(className: "GraphQLClass", objectId: $objectId) + get: graphQLClass(objectId: $objectId) { + pointerToUser { + objectId + } + } } `, variables: { @@ -3148,11 +3067,6 @@ describe('ParseGraphQLServer', () => { const result2 = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get( - className: "GraphQLClass" - objectId: $objectId - include: "pointerToUser" - ) graphQLClass(objectId: $objectId) { pointerToUser { username @@ -3171,7 +3085,6 @@ describe('ParseGraphQLServer', () => { }); expect(result1.data.get.pointerToUser.username).toBeUndefined(); - expect(result2.data.get.pointerToUser.username).toBeDefined(); expect( result2.data.graphQLClass.pointerToUser.username ).toBeDefined(); @@ -3191,11 +3104,11 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get( - className: "GraphQLClass" - objectId: $objectId - include: "pointerToUser" - ) + graphQLClass(objectId: $objectId) { + pointerToUser { + username + } + } } `, variables: { @@ -3243,12 +3156,14 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get( - className: "GraphQLClass" + graphQLClass( objectId: $objectId - include: "pointerToUser" readPreference: SECONDARY - ) + ) { + pointerToUser { + username + } + } } `, variables: { @@ -3296,13 +3211,15 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get( - className: "GraphQLClass" + graphQLClass( objectId: $objectId - include: "pointerToUser" readPreference: SECONDARY includeReadPreference: NEAREST - ) + ) { + pointerToUser { + username + } + } } `, variables: { @@ -7448,10 +7365,14 @@ describe('ParseGraphQLServer', () => { user.setPassword('user1'); await user.signUp(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get(className: "_User", objectId: $objectId) + get: user(objectId: $objectId) { + objectId + } } `, variables: { @@ -7468,10 +7389,14 @@ describe('ParseGraphQLServer', () => { deviceType: 'foo', }); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get(className: "_Installation", objectId: $objectId) + get: installation(objectId: $objectId) { + objectId + } } `, variables: { @@ -7488,10 +7413,14 @@ describe('ParseGraphQLServer', () => { const role = new Parse.Role('MyRole', roleACL); await role.save(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get(className: "_Role", objectId: $objectId) + get: role(objectId: $objectId) { + objectId + } } `, variables: { @@ -7508,11 +7437,15 @@ describe('ParseGraphQLServer', () => { user.setPassword('user1'); await user.signUp(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const session = await Parse.Session.current(); const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get(className: "_Session", objectId: $objectId) + get: session(objectId: $objectId) { + objectId + } } `, variables: { @@ -7542,10 +7475,14 @@ describe('ParseGraphQLServer', () => { { useMasterKey: true } ); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const getResult = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { - get(className: "_Product", objectId: $objectId) + get: product(objectId: $objectId) { + objectId + } } `, variables: { @@ -7561,78 +7498,6 @@ describe('ParseGraphQLServer', () => { expect(getResult.data.get.objectId).toEqual(product.id); }); - it('should support PushStatus class', async () => { - const PushStatus = Parse.Object.extend('_PushStatus'); - const pushStatus = new PushStatus(); - await pushStatus.save(undefined, { useMasterKey: true }); - - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "_PushStatus", objectId: $objectId) - } - `, - variables: { - objectId: pushStatus.id, - }, - context: { - headers: { - 'X-Parse-Master-Key': 'test', - }, - }, - }); - - expect(getResult.data.get.objectId).toEqual(pushStatus.id); - }); - - it('should support JobStatus class', async () => { - const JobStatus = Parse.Object.extend('_JobStatus'); - const jobStatus = new JobStatus(); - await jobStatus.save(undefined, { useMasterKey: true }); - - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "_JobStatus", objectId: $objectId) - } - `, - variables: { - objectId: jobStatus.id, - }, - context: { - headers: { - 'X-Parse-Master-Key': 'test', - }, - }, - }); - - expect(getResult.data.get.objectId).toEqual(jobStatus.id); - }); - - it('should support JobSchedule class', async () => { - const JobSchedule = Parse.Object.extend('_JobSchedule'); - const jobSchedule = new JobSchedule(); - await jobSchedule.save(undefined, { useMasterKey: true }); - - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "_JobSchedule", objectId: $objectId) - } - `, - variables: { - objectId: jobSchedule.id, - }, - context: { - headers: { - 'X-Parse-Master-Key': 'test', - }, - }, - }); - - expect(getResult.data.get.objectId).toEqual(jobSchedule.id); - }); - it('should support Hooks class', async () => { const functionName = 'fooHook'; await parseServer.config.hooksController.saveHook({ @@ -7659,25 +7524,6 @@ describe('ParseGraphQLServer', () => { expect(results.length).toEqual(1); expect(results[0].functionName).toEqual(functionName); }); - - it('should support Audience class', async () => { - const Audience = Parse.Object.extend('_Audience'); - const audience = new Audience(); - await audience.save(); - - const getResult = await apolloClient.query({ - query: gql` - query GetSomeObject($objectId: ID!) { - get(className: "_Audience", objectId: $objectId) - } - `, - variables: { - objectId: audience.id, - }, - }); - - expect(getResult.data.get.objectId).toEqual(audience.id); - }); }); }); }); From 0c6eede388b81630fd616b376226d73746057a0d Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 17:09:59 -0700 Subject: [PATCH 52/60] Remove remaining generic operations and fix tests --- spec/ParseGraphQLSchema.spec.js | 20 +- spec/ParseGraphQLServer.spec.js | 508 +++++-------------- src/GraphQL/loaders/defaultGraphQLQueries.js | 2 - src/GraphQL/loaders/objectsQueries.js | 126 +---- 4 files changed, 146 insertions(+), 510 deletions(-) diff --git a/spec/ParseGraphQLSchema.spec.js b/spec/ParseGraphQLSchema.spec.js index 0957ea6941..56683d69c3 100644 --- a/spec/ParseGraphQLSchema.spec.js +++ b/spec/ParseGraphQLSchema.spec.js @@ -270,13 +270,13 @@ describe('ParseGraphQLSchema', () => { warn: message => { logged = true; expect(message).toEqual( - 'Query get could not be added to the auto schema because it collided with an existing field.' + 'Query viewer could not be added to the auto schema because it collided with an existing field.' ); }, }, }); await parseGraphQLSchema.load(); - expect(parseGraphQLSchema.addGraphQLQuery('get', {})).toBeUndefined(); + expect(parseGraphQLSchema.addGraphQLQuery('viewer', {})).toBeUndefined(); expect(logged).toBeTruthy(); }); @@ -291,12 +291,12 @@ describe('ParseGraphQLSchema', () => { }, }); await parseGraphQLSchema.load(); - delete parseGraphQLSchema.graphQLQueries.get; + delete parseGraphQLSchema.graphQLQueries.viewer; const field = {}; - expect(parseGraphQLSchema.addGraphQLQuery('get', field, true, true)).toBe( - field - ); - expect(parseGraphQLSchema.graphQLQueries['get']).toBe(field); + expect( + parseGraphQLSchema.addGraphQLQuery('viewer', field, true, true) + ).toBe(field); + expect(parseGraphQLSchema.graphQLQueries['viewer']).toBe(field); }); }); @@ -386,12 +386,12 @@ describe('ParseGraphQLSchema', () => { }, }); await parseGraphQLSchema.load(); - delete parseGraphQLSchema.graphQLMutations.create; + delete parseGraphQLSchema.graphQLMutations.signUp; const field = {}; expect( - parseGraphQLSchema.addGraphQLMutation('create', field, true, true) + parseGraphQLSchema.addGraphQLMutation('signUp', field, true, true) ).toBe(field); - expect(parseGraphQLSchema.graphQLMutations['create']).toBe(field); + expect(parseGraphQLSchema.graphQLMutations['signUp']).toBe(field); }); }); diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 321349abfa..3b785264a7 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -2994,6 +2994,8 @@ describe('ParseGraphQLServer', () => { it('should support keys argument', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const result1 = await apolloClient.query({ query: gql` query GetSomeObject($objectId: ID!) { @@ -3257,35 +3259,6 @@ describe('ParseGraphQLServer', () => { }); describe('Find', () => { - it('should return class objects using generic query', async () => { - const obj1 = new Parse.Object('SomeClass'); - obj1.set('someField', 'someValue1'); - await obj1.save(); - const obj2 = new Parse.Object('SomeClass'); - obj2.set('someField', 'someValue1'); - await obj2.save(); - - const result = await apolloClient.query({ - query: gql` - query FindSomeObjects { - find(className: "SomeClass") { - results - } - } - `, - }); - - expect(result.data.find.results.length).toEqual(2); - - result.data.find.results.forEach(resultObj => { - const obj = resultObj.objectId === obj1.id ? obj1 : obj2; - expect(resultObj.objectId).toEqual(obj.id); - expect(resultObj.someField).toEqual(obj.get('someField')); - expect(new Date(resultObj.createdAt)).toEqual(obj.createdAt); - expect(new Date(resultObj.updatedAt)).toEqual(obj.updatedAt); - }); - }); - it('should return class objects using class specific query', async () => { const obj1 = new Parse.Object('Customer'); obj1.set('someField', 'someValue1'); @@ -3326,17 +3299,15 @@ describe('ParseGraphQLServer', () => { await prepareData(); await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + async function findObjects(className, headers) { const graphqlClassName = pluralize( className.charAt(0).toLowerCase() + className.slice(1) ); const result = await apolloClient.query({ query: gql` - query FindSomeObjects($className: String!) { - find(className: $className) { - results - } - ${graphqlClassName} { + query FindSomeObjects { + find: ${graphqlClassName} { results { objectId someField @@ -3344,28 +3315,11 @@ describe('ParseGraphQLServer', () => { } } `, - variables: { - className, - }, context: { headers, }, }); - const genericFindResults = result.data.find.results; - const specificFindResults = result.data[graphqlClassName].results; - genericFindResults.forEach(({ objectId, someField }) => { - expect( - specificFindResults.some( - ({ - objectId: specificObjectId, - someField: specificSomeField, - }) => - objectId === specificObjectId && - someField === specificSomeField - ) - ); - }); return result; } @@ -3429,48 +3383,6 @@ describe('ParseGraphQLServer', () => { ).toEqual(['someValue3']); }); - it('should support where argument using generic query', async () => { - await prepareData(); - - const result = await apolloClient.query({ - query: gql` - query FindSomeObjects($where: Object) { - find(className: "GraphQLClass", where: $where) { - results - } - } - `, - variables: { - where: { - someField: { - $in: ['someValue1', 'someValue2', 'someValue3'], - }, - $or: [ - { - pointerToUser: { - __type: 'Pointer', - className: '_User', - objectId: user5.id, - }, - }, - { - objectId: object1.id, - }, - ], - }, - }, - context: { - headers: { - 'X-Parse-Master-Key': 'test', - }, - }, - }); - - expect( - result.data.find.results.map(object => object.someField).sort() - ).toEqual(['someValue1', 'someValue3']); - }); - it('should support where argument using class specific query', async () => { await prepareData(); @@ -3574,28 +3486,16 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query FindSomeObjects( - $className: String! - $where: Object - $whereCustom: SomeClassWhereInput - $order: String - $orderCustom: [SomeClassOrder!] + $where: SomeClassWhereInput + $order: [SomeClassOrder!] $skip: Int $limit: Int ) { - find( - className: $className + find: someClasses( where: $where order: $order skip: $skip limit: $limit - ) { - results - } - someClasses( - where: $whereCustom - order: $orderCustom - skip: $skip - limit: $limit ) { results { someField @@ -3604,19 +3504,12 @@ describe('ParseGraphQLServer', () => { } `, variables: { - className: 'SomeClass', where: { - someField: { - $regex: '^someValue', - }, - }, - whereCustom: { someField: { _regex: '^someValue', }, }, - order: '-numberField,someField', - orderCustom: ['numberField_DESC', 'someField_ASC'], + order: ['numberField_DESC', 'someField_ASC'], skip: 4, limit: 2, }, @@ -3626,9 +3519,6 @@ describe('ParseGraphQLServer', () => { 'someValue14', 'someValue17', ]); - expect( - result.data.someClasses.results.map(obj => obj.someField) - ).toEqual(['someValue14', 'someValue17']); }); it('should support count', async () => { @@ -3661,19 +3551,10 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query FindSomeObjects( - $where1: Object - $where2: GraphQLClassWhereInput + $where: GraphQLClassWhereInput $limit: Int ) { - find( - className: "GraphQLClass" - where: $where1 - limit: $limit - ) { - results - count - } - graphQLClasses(where: $where2, limit: $limit) { + find: graphQLClasses(where: $where, limit: $limit) { results { objectId } @@ -3682,8 +3563,7 @@ describe('ParseGraphQLServer', () => { } `, variables: { - where1: where, - where2: where, + where, limit: 0, }, context: { @@ -3695,8 +3575,6 @@ describe('ParseGraphQLServer', () => { expect(result.data.find.results).toEqual([]); expect(result.data.find.count).toEqual(2); - expect(result.data.graphQLClasses.results).toEqual([]); - expect(result.data.graphQLClasses.count).toEqual(2); }); it('should only count', async () => { @@ -3728,21 +3606,14 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` - query FindSomeObjects( - $where1: Object - $where2: GraphQLClassWhereInput - ) { - find(className: "GraphQLClass", where: $where1) { - count - } - graphQLClasses(where: $where2) { + query FindSomeObjects($where: GraphQLClassWhereInput) { + find: graphQLClasses(where: $where) { count } } `, variables: { - where1: where, - where2: where, + where, }, context: { headers: { @@ -3753,8 +3624,6 @@ describe('ParseGraphQLServer', () => { expect(result.data.find.results).toBeUndefined(); expect(result.data.find.count).toEqual(2); - expect(result.data.graphQLClasses.results).toBeUndefined(); - expect(result.data.graphQLClasses.count).toEqual(2); }); it('should respect max limit', async () => { @@ -3774,15 +3643,7 @@ describe('ParseGraphQLServer', () => { const result = await apolloClient.query({ query: gql` query FindSomeObjects($limit: Int) { - find( - className: "SomeClass" - where: { objectId: { _exists: true } } - limit: $limit - ) { - results - count - } - someClasses( + find: someClasses( where: { objectId: { _exists: true } } limit: $limit ) { @@ -3805,28 +3666,26 @@ describe('ParseGraphQLServer', () => { expect(result.data.find.results.length).toEqual(10); expect(result.data.find.count).toEqual(100); - expect(result.data.someClasses.results.length).toEqual(10); - expect(result.data.someClasses.count).toEqual(100); }); it('should support keys argument', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const result1 = await apolloClient.query({ query: gql` - query FindSomeObject($where: Object) { - find( - className: "GraphQLClass" - where: $where - keys: "someField" - ) { - results + query FindSomeObject($where: GraphQLClassWhereInput) { + find: graphQLClasses(where: $where) { + results { + someField + } } } `, variables: { where: { - objectId: object3.id, + objectId: { _eq: object3.id }, }, }, context: { @@ -3838,19 +3697,20 @@ describe('ParseGraphQLServer', () => { const result2 = await apolloClient.query({ query: gql` - query FindSomeObject($where: Object) { - find( - className: "GraphQLClass" - where: $where - keys: "someField,pointerToUser" - ) { - results + query FindSomeObject($where: GraphQLClassWhereInput) { + find: graphQLClasses(where: $where) { + results { + someField + pointerToUser { + username + } + } } } `, variables: { where: { - objectId: object3.id, + objectId: { _eq: object3.id }, }, }, context: { @@ -3871,18 +3731,26 @@ describe('ParseGraphQLServer', () => { await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const where = { + objectId: { + _eq: object3.id, + }, + }; + const result1 = await apolloClient.query({ query: gql` - query FindSomeObject($where: Object) { - find(className: "GraphQLClass", where: $where) { - results + query FindSomeObject($where: GraphQLClassWhereInput) { + find: graphQLClasses(where: $where) { + results { + pointerToUser { + objectId + } + } } } `, variables: { - where: { - objectId: object3.id, - }, + where, }, context: { headers: { @@ -3891,26 +3759,10 @@ describe('ParseGraphQLServer', () => { }, }); - const where = { - objectId: { - _eq: object3.id, - }, - }; - const result2 = await apolloClient.query({ query: gql` - query FindSomeObject( - $where1: Object - $where2: GraphQLClassWhereInput - ) { - find( - className: "GraphQLClass" - where: $where1 - include: "pointerToUser" - ) { - results - } - graphQLClasses(where: $where2) { + query FindSomeObject($where: GraphQLClassWhereInput) { + find: graphQLClasses(where: $where) { results { pointerToUser { username @@ -3920,8 +3772,7 @@ describe('ParseGraphQLServer', () => { } `, variables: { - where1: where, - where2: where, + where, }, context: { headers: { @@ -3935,53 +3786,6 @@ describe('ParseGraphQLServer', () => { expect( result2.data.find.results[0].pointerToUser.username ).toBeDefined(); - expect( - result2.data.graphQLClasses.results[0].pointerToUser.username - ).toBeDefined(); - }); - - it('should support includeAll argument', async () => { - const obj1 = new Parse.Object('SomeClass1'); - obj1.set('someField1', 'someValue1'); - const obj2 = new Parse.Object('SomeClass2'); - obj2.set('someField2', 'someValue2'); - const obj3 = new Parse.Object('SomeClass3'); - obj3.set('obj1', obj1); - obj3.set('obj2', obj2); - await Promise.all([obj1.save(), obj2.save(), obj3.save()]); - - const result1 = await apolloClient.query({ - query: gql` - query FindSomeObject { - find(className: "SomeClass3") { - results - } - } - `, - }); - - const result2 = await apolloClient.query({ - query: gql` - query FindSomeObject { - find(className: "SomeClass3", includeAll: true) { - results - } - } - `, - }); - - expect( - result1.data.find.results[0].obj1.someField1 - ).toBeUndefined(); - expect( - result1.data.find.results[0].obj2.someField2 - ).toBeUndefined(); - expect(result2.data.find.results[0].obj1.someField1).toEqual( - 'someValue1' - ); - expect(result2.data.find.results[0].obj2.someField2).toEqual( - 'someValue2' - ); }); describe_only_db('mongo')('read preferences', () => { @@ -3998,8 +3802,12 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query FindSomeObjects { - find(className: "GraphQLClass", include: "pointerToUser") { - results + find: graphQLClasses { + results { + pointerToUser { + username + } + } } } `, @@ -4045,12 +3853,12 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query FindSomeObjects { - find( - className: "GraphQLClass" - include: "pointerToUser" - readPreference: SECONDARY - ) { - results + find: graphQLClasses(readPreference: SECONDARY) { + results { + pointerToUser { + username + } + } } } `, @@ -4096,13 +3904,15 @@ describe('ParseGraphQLServer', () => { await apolloClient.query({ query: gql` query FindSomeObjects { - find( - className: "GraphQLClass" - include: "pointerToUser" + graphQLClasses( readPreference: SECONDARY includeReadPreference: NEAREST ) { - results + results { + pointerToUser { + username + } + } } } `, @@ -4135,63 +3945,76 @@ describe('ParseGraphQLServer', () => { expect(foundUserClassReadPreference).toBe(true); }); - it('should support subqueryReadPreference argument', async () => { - await prepareData(); - - const databaseAdapter = - parseServer.config.databaseController.adapter; - spyOn( - databaseAdapter.database.serverConfig, - 'cursor' - ).and.callThrough(); - - await apolloClient.query({ - query: gql` - query FindSomeObjects($where: Object) { - find( - className: "GraphQLClass" - where: $where - readPreference: SECONDARY - subqueryReadPreference: NEAREST - ) { - results + xit('should support subqueryReadPreference argument', async () => { + try { + await prepareData(); + + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + + const databaseAdapter = + parseServer.config.databaseController.adapter; + spyOn( + databaseAdapter.database.serverConfig, + 'cursor' + ).and.callThrough(); + + await apolloClient.query({ + query: gql` + query FindSomeObjects($where: GraphQLClassWhereInput) { + find: graphQLClasses( + where: $where + readPreference: SECONDARY + subqueryReadPreference: NEAREST + ) { + results { + pointerToUser { + username + } + } + } } - } - `, - variables: { - where: { - pointerToUser: { - $inQuery: { where: {}, className: '_User' }, + `, + variables: { + where: { + pointerToUser: { + _inQuery: { where: {}, className: '_User' }, + }, }, }, - }, - context: { - headers: { - 'X-Parse-Master-Key': 'test', + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, }, - }, - }); - - let foundGraphQLClassReadPreference = false; - let foundUserClassReadPreference = false; - databaseAdapter.database.serverConfig.cursor.calls - .all() - .forEach(call => { - if (call.args[0].ns.collection.indexOf('GraphQLClass') >= 0) { - foundGraphQLClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe( - ReadPreference.SECONDARY - ); - } else if (call.args[0].ns.collection.indexOf('_User') >= 0) { - foundUserClassReadPreference = true; - expect(call.args[0].options.readPreference.mode).toBe( - ReadPreference.NEAREST - ); - } }); - expect(foundGraphQLClassReadPreference).toBe(true); - expect(foundUserClassReadPreference).toBe(true); + let foundGraphQLClassReadPreference = false; + let foundUserClassReadPreference = false; + databaseAdapter.database.serverConfig.cursor.calls + .all() + .forEach(call => { + if ( + call.args[0].ns.collection.indexOf('GraphQLClass') >= 0 + ) { + foundGraphQLClassReadPreference = true; + expect(call.args[0].options.readPreference.mode).toBe( + ReadPreference.SECONDARY + ); + } else if ( + call.args[0].ns.collection.indexOf('_User') >= 0 + ) { + foundUserClassReadPreference = true; + expect(call.args[0].options.readPreference.mode).toBe( + ReadPreference.NEAREST + ); + } + }); + + expect(foundGraphQLClassReadPreference).toBe(true); + expect(foundUserClassReadPreference).toBe(true); + } catch (e) { + handleError(e); + } }); }); }); @@ -6592,7 +6415,6 @@ describe('ParseGraphQLServer', () => { query GetSomeObject( $objectId: ID! $where: SomeClassWhereInput - $genericWhere: Object ) { someClass(objectId: $objectId) { objectId @@ -6604,23 +6426,15 @@ describe('ParseGraphQLServer', () => { someField } } - find(className: "SomeClass", where: $genericWhere) { - results - } } `, variables: { objectId: createResult.data.createSomeClass.objectId, where, - genericWhere: where, // where and genericWhere types are different }, }); - const { - someClass: getResult, - someClasses, - find, - } = queryResult.data; + const { someClass: getResult, someClasses } = queryResult.data; const { someField } = getResult; expect(typeof someField).toEqual('object'); @@ -6629,10 +6443,6 @@ describe('ParseGraphQLServer', () => { // Checks class query results expect(someClasses.results.length).toEqual(1); expect(someClasses.results[0].someField).toEqual(someFieldValue); - - // Checks generic query results - expect(find.results.length).toEqual(1); - expect(find.results[0].someField).toEqual(someFieldValue); } catch (e) { handleError(e); } @@ -6725,29 +6535,22 @@ describe('ParseGraphQLServer', () => { }; const findResult = await apolloClient.query({ query: gql` - query FindSomeObject( - $where: SomeClassWhereInput - $genericWhere: Object - ) { + query FindSomeObject($where: SomeClassWhereInput) { someClasses(where: $where) { results { objectId someField } } - find(className: "SomeClass", where: $genericWhere) { - results - } } `, variables: { where, - genericWhere: where, // where and genericWhere types are different }, }); const { create1, create2 } = createResult.data; - const { someClasses, find } = findResult.data; + const { someClasses } = findResult.data; // Checks class query results const { results } = someClasses; @@ -6760,20 +6563,6 @@ describe('ParseGraphQLServer', () => { results.find(result => result.objectId === create2.objectId) .someField ).toEqual(someFieldValue2); - - // Checks generic query results - const { results: genericResults } = find; - expect(genericResults.length).toEqual(2); - expect( - genericResults.find( - result => result.objectId === create1.objectId - ).someField - ).toEqual(someFieldValue); - expect( - genericResults.find( - result => result.objectId === create2.objectId - ).someField - ).toEqual(someFieldValue2); } catch (e) { handleError(e); } @@ -7497,33 +7286,6 @@ describe('ParseGraphQLServer', () => { expect(getResult.data.get.objectId).toEqual(product.id); }); - - it('should support Hooks class', async () => { - const functionName = 'fooHook'; - await parseServer.config.hooksController.saveHook({ - functionName, - url: 'http://foo.bar', - }); - - const getResult = await apolloClient.query({ - query: gql` - query FindSomeObject { - find(className: "_Hooks") { - results - } - } - `, - context: { - headers: { - 'X-Parse-Master-Key': 'test', - }, - }, - }); - - const { results } = getResult.data.find; - expect(results.length).toEqual(1); - expect(results[0].functionName).toEqual(functionName); - }); }); }); }); diff --git a/src/GraphQL/loaders/defaultGraphQLQueries.js b/src/GraphQL/loaders/defaultGraphQLQueries.js index 990b15a67a..37b9e4a393 100644 --- a/src/GraphQL/loaders/defaultGraphQLQueries.js +++ b/src/GraphQL/loaders/defaultGraphQLQueries.js @@ -1,5 +1,4 @@ import { GraphQLNonNull, GraphQLBoolean } from 'graphql'; -import * as objectsQueries from './objectsQueries'; import * as usersQueries from './usersQueries'; import * as classSchemaQueries from './classSchemaQueries'; @@ -16,7 +15,6 @@ const load = parseGraphQLSchema => { true ); - objectsQueries.load(parseGraphQLSchema); usersQueries.load(parseGraphQLSchema); classSchemaQueries.load(parseGraphQLSchema); }; diff --git a/src/GraphQL/loaders/objectsQueries.js b/src/GraphQL/loaders/objectsQueries.js index 2cb76e3e5a..b267da8624 100644 --- a/src/GraphQL/loaders/objectsQueries.js +++ b/src/GraphQL/loaders/objectsQueries.js @@ -1,7 +1,4 @@ -import { GraphQLNonNull, GraphQLBoolean, GraphQLString } from 'graphql'; -import getFieldNames from 'graphql-list-fields'; import Parse from 'parse/node'; -import * as defaultGraphQLTypes from './defaultGraphQLTypes'; import rest from '../../rest'; import { transformQueryInputToParse } from '../transformers/query'; @@ -128,125 +125,4 @@ const findObjects = async ( ); }; -const load = parseGraphQLSchema => { - parseGraphQLSchema.addGraphQLQuery( - 'get', - { - description: - 'The get query can be used to get an object of a certain class by its objectId.', - args: { - className: defaultGraphQLTypes.CLASS_NAME_ATT, - objectId: defaultGraphQLTypes.OBJECT_ID_ATT, - keys: defaultGraphQLTypes.KEYS_ATT, - include: defaultGraphQLTypes.INCLUDE_ATT, - readPreference: defaultGraphQLTypes.READ_PREFERENCE_ATT, - includeReadPreference: defaultGraphQLTypes.INCLUDE_READ_PREFERENCE_ATT, - }, - type: new GraphQLNonNull(defaultGraphQLTypes.OBJECT), - async resolve(_source, args, context) { - try { - const { - className, - objectId, - keys, - include, - readPreference, - includeReadPreference, - } = args; - - const { config, auth, info } = context; - - return await getObject( - className, - objectId, - keys, - include, - readPreference, - includeReadPreference, - config, - auth, - info - ); - } catch (e) { - parseGraphQLSchema.handleError(e); - } - }, - }, - true, - true - ); - - parseGraphQLSchema.addGraphQLQuery( - 'find', - { - description: - 'The find query can be used to find objects of a certain class.', - args: { - className: defaultGraphQLTypes.CLASS_NAME_ATT, - where: defaultGraphQLTypes.WHERE_ATT, - order: { - description: - 'This is the order in which the objects should be returned', - type: GraphQLString, - }, - skip: defaultGraphQLTypes.SKIP_ATT, - limit: defaultGraphQLTypes.LIMIT_ATT, - keys: defaultGraphQLTypes.KEYS_ATT, - include: defaultGraphQLTypes.INCLUDE_ATT, - includeAll: { - description: 'All pointers will be returned', - type: GraphQLBoolean, - }, - readPreference: defaultGraphQLTypes.READ_PREFERENCE_ATT, - includeReadPreference: defaultGraphQLTypes.INCLUDE_READ_PREFERENCE_ATT, - subqueryReadPreference: - defaultGraphQLTypes.SUBQUERY_READ_PREFERENCE_ATT, - }, - type: new GraphQLNonNull(defaultGraphQLTypes.FIND_RESULT), - async resolve(_source, args, context, queryInfo) { - try { - const { - className, - where, - order, - skip, - limit, - keys, - include, - includeAll, - readPreference, - includeReadPreference, - subqueryReadPreference, - } = args; - - const { config, auth, info } = context; - const selectedFields = getFieldNames(queryInfo); - - return await findObjects( - className, - where, - order, - skip, - limit, - keys, - include, - includeAll, - readPreference, - includeReadPreference, - subqueryReadPreference, - config, - auth, - info, - selectedFields - ); - } catch (e) { - parseGraphQLSchema.handleError(e); - } - }, - }, - true, - true - ); -}; - -export { getObject, findObjects, load }; +export { getObject, findObjects }; From 50fb255fb9877949103334208426117732a6bf24 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 17:19:11 -0700 Subject: [PATCH 53/60] Fix last test --- spec/ParseGraphQLServer.spec.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 3b785264a7..4861fa1163 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -3945,7 +3945,7 @@ describe('ParseGraphQLServer', () => { expect(foundUserClassReadPreference).toBe(true); }); - xit('should support subqueryReadPreference argument', async () => { + it('should support subqueryReadPreference argument', async () => { try { await prepareData(); @@ -3967,9 +3967,7 @@ describe('ParseGraphQLServer', () => { subqueryReadPreference: NEAREST ) { results { - pointerToUser { - username - } + objectId } } } From febf15e8298aa069bdd1ed4c6fee7bb7e1d07ad6 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 17:53:09 -0700 Subject: [PATCH 54/60] Try to fix redis tests --- spec/ParseGraphQLServer.spec.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 4861fa1163..38d8a21c83 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -3096,6 +3096,8 @@ describe('ParseGraphQLServer', () => { it('should read from primary by default', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const databaseAdapter = parseServer.config.databaseController.adapter; spyOn( @@ -3148,6 +3150,8 @@ describe('ParseGraphQLServer', () => { it('should support readPreference argument', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const databaseAdapter = parseServer.config.databaseController.adapter; spyOn( @@ -3203,6 +3207,8 @@ describe('ParseGraphQLServer', () => { it('should support includeReadPreference argument', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const databaseAdapter = parseServer.config.databaseController.adapter; spyOn( @@ -3792,6 +3798,8 @@ describe('ParseGraphQLServer', () => { it('should read from primary by default', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const databaseAdapter = parseServer.config.databaseController.adapter; spyOn( @@ -3843,6 +3851,8 @@ describe('ParseGraphQLServer', () => { it('should support readPreference argument', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const databaseAdapter = parseServer.config.databaseController.adapter; spyOn( @@ -3894,6 +3904,8 @@ describe('ParseGraphQLServer', () => { it('should support includeReadPreference argument', async () => { await prepareData(); + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + const databaseAdapter = parseServer.config.databaseController.adapter; spyOn( From ac7d7c9511c19f1a9d7336f24776260863dec54d Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Wed, 28 Aug 2019 18:06:49 -0700 Subject: [PATCH 55/60] Fix postgres tests --- spec/ParseGraphQLServer.spec.js | 230 +++++++++++++++++--------------- 1 file changed, 120 insertions(+), 110 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 38d8a21c83..983d4e7d21 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -1759,112 +1759,117 @@ describe('ParseGraphQLServer', () => { }, }, }); - expect(result).toEqual({ - data: { - class1: { - name: 'Class1', - schemaFields: [ - { name: 'objectId', __typename: 'SchemaStringField' }, - { name: 'updatedAt', __typename: 'SchemaDateField' }, - { name: 'createdAt', __typename: 'SchemaDateField' }, - { name: 'ACL', __typename: 'SchemaACLField' }, - ], - __typename: 'Class', - }, - class2: { - name: 'Class2', - schemaFields: [ - { name: 'objectId', __typename: 'SchemaStringField' }, - { name: 'updatedAt', __typename: 'SchemaDateField' }, - { name: 'createdAt', __typename: 'SchemaDateField' }, - { name: 'ACL', __typename: 'SchemaACLField' }, - ], - __typename: 'Class', - }, - class3: { - name: 'Class3', - schemaFields: [ - { name: 'objectId', __typename: 'SchemaStringField' }, - { name: 'updatedAt', __typename: 'SchemaDateField' }, - { name: 'createdAt', __typename: 'SchemaDateField' }, - { name: 'ACL', __typename: 'SchemaACLField' }, - ], - __typename: 'Class', - }, - class4: { - name: 'Class4', - schemaFields: [ - { name: 'objectId', __typename: 'SchemaStringField' }, - { name: 'updatedAt', __typename: 'SchemaDateField' }, - { name: 'createdAt', __typename: 'SchemaDateField' }, - { name: 'ACL', __typename: 'SchemaACLField' }, - ], - __typename: 'Class', - }, - class5: { - name: 'Class5', - schemaFields: [ - { name: 'objectId', __typename: 'SchemaStringField' }, - { name: 'updatedAt', __typename: 'SchemaDateField' }, - { name: 'createdAt', __typename: 'SchemaDateField' }, - { name: 'ACL', __typename: 'SchemaACLField' }, - ], - __typename: 'Class', - }, - class6: { - name: 'Class6', - schemaFields: [ - { name: 'objectId', __typename: 'SchemaStringField' }, - { name: 'updatedAt', __typename: 'SchemaDateField' }, - { name: 'createdAt', __typename: 'SchemaDateField' }, - { name: 'stringField1', __typename: 'SchemaStringField' }, - { name: 'stringField2', __typename: 'SchemaStringField' }, - { name: 'numberField1', __typename: 'SchemaNumberField' }, - { name: 'numberField2', __typename: 'SchemaNumberField' }, - { name: 'booleanField1', __typename: 'SchemaBooleanField' }, - { name: 'booleanField2', __typename: 'SchemaBooleanField' }, - { name: 'arrayField1', __typename: 'SchemaArrayField' }, - { name: 'arrayField2', __typename: 'SchemaArrayField' }, - { name: 'objectField1', __typename: 'SchemaObjectField' }, - { name: 'objectField2', __typename: 'SchemaObjectField' }, - { name: 'dateField1', __typename: 'SchemaDateField' }, - { name: 'dateField2', __typename: 'SchemaDateField' }, - { name: 'fileField1', __typename: 'SchemaFileField' }, - { name: 'fileField2', __typename: 'SchemaFileField' }, - { - name: 'geoPointField', - __typename: 'SchemaGeoPointField', - }, - { name: 'polygonField1', __typename: 'SchemaPolygonField' }, - { name: 'polygonField2', __typename: 'SchemaPolygonField' }, - { name: 'bytesField1', __typename: 'SchemaBytesField' }, - { name: 'bytesField2', __typename: 'SchemaBytesField' }, - { - name: 'pointerField1', - __typename: 'SchemaPointerField', - targetClassName: 'Class1', - }, - { - name: 'pointerField2', - __typename: 'SchemaPointerField', - targetClassName: 'Class6', - }, - { - name: 'relationField1', - __typename: 'SchemaRelationField', - targetClassName: 'Class1', - }, - { - name: 'relationField2', - __typename: 'SchemaRelationField', - targetClassName: 'Class6', - }, - { name: 'ACL', __typename: 'SchemaACLField' }, - ], - __typename: 'Class', - }, + const classes = Object.keys(result.data).map(fieldName => ({ + name: result.data[fieldName].name, + schemaFields: result.data[fieldName].schemaFields.sort((a, b) => + a.name > b.name ? 1 : -1 + ), + __typename: result.data[fieldName].__typename, + })); + expect(classes).toEqual([ + { + name: 'Class1', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', }, - }); + { + name: 'Class2', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + { + name: 'Class3', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + { + name: 'Class4', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + { + name: 'Class5', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + { + name: 'Class6', + schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'arrayField1', __typename: 'SchemaArrayField' }, + { name: 'arrayField2', __typename: 'SchemaArrayField' }, + { name: 'booleanField1', __typename: 'SchemaBooleanField' }, + { name: 'booleanField2', __typename: 'SchemaBooleanField' }, + { name: 'bytesField1', __typename: 'SchemaBytesField' }, + { name: 'bytesField2', __typename: 'SchemaBytesField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, + { name: 'dateField1', __typename: 'SchemaDateField' }, + { name: 'dateField2', __typename: 'SchemaDateField' }, + { name: 'fileField1', __typename: 'SchemaFileField' }, + { name: 'fileField2', __typename: 'SchemaFileField' }, + { + name: 'geoPointField', + __typename: 'SchemaGeoPointField', + }, + { name: 'numberField1', __typename: 'SchemaNumberField' }, + { name: 'numberField2', __typename: 'SchemaNumberField' }, + { name: 'objectField1', __typename: 'SchemaObjectField' }, + { name: 'objectField2', __typename: 'SchemaObjectField' }, + { name: 'objectId', __typename: 'SchemaStringField' }, + { + name: 'pointerField1', + __typename: 'SchemaPointerField', + targetClassName: 'Class1', + }, + { + name: 'pointerField2', + __typename: 'SchemaPointerField', + targetClassName: 'Class6', + }, + { name: 'polygonField1', __typename: 'SchemaPolygonField' }, + { name: 'polygonField2', __typename: 'SchemaPolygonField' }, + { + name: 'relationField1', + __typename: 'SchemaRelationField', + targetClassName: 'Class1', + }, + { + name: 'relationField2', + __typename: 'SchemaRelationField', + targetClassName: 'Class6', + }, + { name: 'stringField1', __typename: 'SchemaStringField' }, + { name: 'stringField2', __typename: 'SchemaStringField' }, + { name: 'updatedAt', __typename: 'SchemaDateField' }, + ], + __typename: 'Class', + }, + ]); const findResult = await apolloClient.query({ query: gql` @@ -1890,7 +1895,6 @@ describe('ParseGraphQLServer', () => { }, }, }); - console.log(findResult.data); findResult.data.classes = findResult.data.classes .filter(schemaClass => !schemaClass.name.startsWith('_')) .sort((a, b) => (a.name > b.name ? 1 : -1)); @@ -2174,6 +2178,9 @@ describe('ParseGraphQLServer', () => { }, }, }); + result.data.createClass.schemaFields = result.data.createClass.schemaFields.sort( + (a, b) => (a.name > b.name ? 1 : -1) + ); result.data.updateClass.schemaFields = result.data.updateClass.schemaFields.sort( (a, b) => (a.name > b.name ? 1 : -1) ); @@ -2182,11 +2189,11 @@ describe('ParseGraphQLServer', () => { createClass: { name: 'MyNewClass', schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, { name: 'objectId', __typename: 'SchemaStringField' }, { name: 'updatedAt', __typename: 'SchemaDateField' }, - { name: 'createdAt', __typename: 'SchemaDateField' }, { name: 'willBeRemoved', __typename: 'SchemaStringField' }, - { name: 'ACL', __typename: 'SchemaACLField' }, ], __typename: 'Class', }, @@ -2483,6 +2490,9 @@ describe('ParseGraphQLServer', () => { }, }, }); + result.data.createClass.schemaFields = result.data.createClass.schemaFields.sort( + (a, b) => (a.name > b.name ? 1 : -1) + ); result.data.deleteClass.schemaFields = result.data.deleteClass.schemaFields.sort( (a, b) => (a.name > b.name ? 1 : -1) ); @@ -2491,11 +2501,11 @@ describe('ParseGraphQLServer', () => { createClass: { name: 'MyNewClass', schemaFields: [ + { name: 'ACL', __typename: 'SchemaACLField' }, + { name: 'createdAt', __typename: 'SchemaDateField' }, { name: 'objectId', __typename: 'SchemaStringField' }, { name: 'updatedAt', __typename: 'SchemaDateField' }, - { name: 'createdAt', __typename: 'SchemaDateField' }, { name: 'willBeRemoved', __typename: 'SchemaStringField' }, - { name: 'ACL', __typename: 'SchemaACLField' }, ], __typename: 'Class', }, From 86d1841daa4d90aaec3dbd1a37a7d5f5d381326a Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 30 Aug 2019 17:55:10 -0700 Subject: [PATCH 56/60] Update objectsMutations and objectsQueries files locations --- spec/ParseGraphQLServer.spec.js | 58 +++++++++---------- .../{loaders => helpers}/objectsMutations.js | 0 .../{loaders => helpers}/objectsQueries.js | 0 3 files changed, 29 insertions(+), 29 deletions(-) rename src/GraphQL/{loaders => helpers}/objectsMutations.js (100%) rename src/GraphQL/{loaders => helpers}/objectsQueries.js (100%) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index ed4c23fc6d..8d9fc7c23c 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -2673,9 +2673,9 @@ describe('ParseGraphQLServer', () => { const result = (await apolloClient.query({ query: gql` - query GetCustomer($objectId: ID!) { - customer(objectId: $objectId) { - objectId + query GetCustomer($id: ID!) { + customer(id: $id) { + id someField createdAt updatedAt @@ -2683,11 +2683,11 @@ describe('ParseGraphQLServer', () => { } `, variables: { - objectId: obj.id, + id: obj.id, }, })).data.customer; - expect(result.objectId).toEqual(obj.id); + expect(result.id).toEqual(obj.id); expect(result.someField).toEqual('someValue'); expect(new Date(result.createdAt)).toEqual(obj.createdAt); expect(new Date(result.updatedAt)).toEqual(obj.updatedAt); @@ -2715,12 +2715,12 @@ describe('ParseGraphQLServer', () => { const result = (await apolloClient.query({ query: gql` - query GetCustomer($objectId: ID!) { - customer(objectId: $objectId) { - objectId + query GetCustomer($id: ID!) { + customer(id: $id) { + id manyRelations { ... on Customer { - objectId + id someCustomerField arrayField { ... on Element { @@ -2729,7 +2729,7 @@ describe('ParseGraphQLServer', () => { } } ... on SomeClass { - objectId + id someClassField } } @@ -2739,11 +2739,11 @@ describe('ParseGraphQLServer', () => { } `, variables: { - objectId: obj3.id, + id: obj3.id, }, })).data.customer; - expect(result.objectId).toEqual(obj3.id); + expect(result.id).toEqual(obj3.id); expect(result.manyRelations.length).toEqual(2); const customerSubObject = result.manyRelations.find( @@ -3742,7 +3742,7 @@ describe('ParseGraphQLServer', () => { await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); const where = { - objectId: { + id: { _eq: object3.id, }, }; @@ -3753,7 +3753,7 @@ describe('ParseGraphQLServer', () => { find: graphQLClasses(where: $where) { results { pointerToUser { - objectId + id } } } @@ -3983,7 +3983,7 @@ describe('ParseGraphQLServer', () => { subqueryReadPreference: NEAREST ) { results { - objectId + id } } } @@ -4671,7 +4671,7 @@ describe('ParseGraphQLServer', () => { ); expect( (await deleteObject(object4.className, object4.id)).data.delete - ).toEqual({ objectId: object4.id, __typename: 'PublicClass' }); + ).toEqual({ id: object4.id, __typename: 'PublicClass' }); await expectAsync( object4.fetch({ useMasterKey: true }) ).toBeRejectedWith(jasmine.stringMatching('Object not found')); @@ -4679,7 +4679,7 @@ describe('ParseGraphQLServer', () => { (await deleteObject(object1.className, object1.id, { 'X-Parse-Master-Key': 'test', })).data.delete - ).toEqual({ objectId: object1.id, __typename: 'GraphQLClass' }); + ).toEqual({ id: object1.id, __typename: 'GraphQLClass' }); await expectAsync( object1.fetch({ useMasterKey: true }) ).toBeRejectedWith(jasmine.stringMatching('Object not found')); @@ -4687,7 +4687,7 @@ describe('ParseGraphQLServer', () => { (await deleteObject(object2.className, object2.id, { 'X-Parse-Session-Token': user2.getSessionToken(), })).data.delete - ).toEqual({ objectId: object2.id, __typename: 'GraphQLClass' }); + ).toEqual({ id: object2.id, __typename: 'GraphQLClass' }); await expectAsync( object2.fetch({ useMasterKey: true }) ).toBeRejectedWith(jasmine.stringMatching('Object not found')); @@ -4695,7 +4695,7 @@ describe('ParseGraphQLServer', () => { (await deleteObject(object3.className, object3.id, { 'X-Parse-Session-Token': user5.getSessionToken(), })).data.delete - ).toEqual({ objectId: object3.id, __typename: 'GraphQLClass' }); + ).toEqual({ id: object3.id, __typename: 'GraphQLClass' }); await expectAsync( object3.fetch({ useMasterKey: true }) ).toBeRejectedWith(jasmine.stringMatching('Object not found')); @@ -5546,7 +5546,7 @@ describe('ParseGraphQLServer', () => { $someFieldValueTrue: Boolean $someFieldValueFalse: Boolean ) { - someClass(objectId: $objectId) { + someClass(id: $id) { someFieldTrue someFieldFalse } @@ -6423,7 +6423,7 @@ describe('ParseGraphQLServer', () => { } someClasses(where: $where) { results { - objectId + id someField } } @@ -6489,10 +6489,10 @@ describe('ParseGraphQLServer', () => { $fields2: CreateSomeClassFieldsInput ) { create1: createSomeClass(fields: $fields1) { - objectId + id } create2: createSomeClass(fields: $fields2) { - objectId + id } } `, @@ -6629,7 +6629,7 @@ describe('ParseGraphQLServer', () => { } someClasses(where: { someField: { _exists: true } }) { results { - objectId + id someField { ... on Element { value @@ -6746,7 +6746,7 @@ describe('ParseGraphQLServer', () => { } `, variables: { - objectId: createResult.data.createSomeClass.objectId, + id: createResult.data.createSomeClass.id, fields: { someStringField: null, someNumberField: null, @@ -6847,7 +6847,7 @@ describe('ParseGraphQLServer', () => { } someClasses(where: { someField: { _eq: $someFieldValue } }) { results { - objectId + id someField } } @@ -6904,7 +6904,7 @@ describe('ParseGraphQLServer', () => { mutation: gql` mutation CreateSomeObject($fields: CreateSomeClassFieldsInput) { createSomeClass(fields: $fields) { - objectId + id } } `, @@ -6929,7 +6929,7 @@ describe('ParseGraphQLServer', () => { } someClasses(where: { someField: { _exists: true } }) { results { - objectId + id someField { latitude longitude @@ -7024,7 +7024,7 @@ describe('ParseGraphQLServer', () => { } `, variables: { - objectId: createResult.data.createSomeClass.objectId, + id: createResult.data.createSomeClass.id, }, }); diff --git a/src/GraphQL/loaders/objectsMutations.js b/src/GraphQL/helpers/objectsMutations.js similarity index 100% rename from src/GraphQL/loaders/objectsMutations.js rename to src/GraphQL/helpers/objectsMutations.js diff --git a/src/GraphQL/loaders/objectsQueries.js b/src/GraphQL/helpers/objectsQueries.js similarity index 100% rename from src/GraphQL/loaders/objectsQueries.js rename to src/GraphQL/helpers/objectsQueries.js From 608fae962e5212f80c762d6398a2702a416574d5 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 30 Aug 2019 17:59:09 -0700 Subject: [PATCH 57/60] Rename classSchema files to schema files --- .../loaders/{classSchemaMutations.js => schemaMutations.js} | 0 src/GraphQL/loaders/{classSchemaQueries.js => schemaQueries.js} | 0 src/GraphQL/loaders/{classSchemaTypes.js => schemaTypes.js} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/GraphQL/loaders/{classSchemaMutations.js => schemaMutations.js} (100%) rename src/GraphQL/loaders/{classSchemaQueries.js => schemaQueries.js} (100%) rename src/GraphQL/loaders/{classSchemaTypes.js => schemaTypes.js} (100%) diff --git a/src/GraphQL/loaders/classSchemaMutations.js b/src/GraphQL/loaders/schemaMutations.js similarity index 100% rename from src/GraphQL/loaders/classSchemaMutations.js rename to src/GraphQL/loaders/schemaMutations.js diff --git a/src/GraphQL/loaders/classSchemaQueries.js b/src/GraphQL/loaders/schemaQueries.js similarity index 100% rename from src/GraphQL/loaders/classSchemaQueries.js rename to src/GraphQL/loaders/schemaQueries.js diff --git a/src/GraphQL/loaders/classSchemaTypes.js b/src/GraphQL/loaders/schemaTypes.js similarity index 100% rename from src/GraphQL/loaders/classSchemaTypes.js rename to src/GraphQL/loaders/schemaTypes.js From 1bfedd2b28dbad8bdc859b8f0a9269dbcead56cc Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 30 Aug 2019 18:09:59 -0700 Subject: [PATCH 58/60] Rename ClassObject to ParseObject --- spec/ParseGraphQLServer.spec.js | 4 ++-- src/GraphQL/loaders/defaultGraphQLMutations.js | 2 +- src/GraphQL/loaders/defaultGraphQLTypes.js | 16 ++++++++-------- src/GraphQL/loaders/parseClassMutations.js | 4 ++-- src/GraphQL/loaders/parseClassQueries.js | 2 +- src/GraphQL/loaders/parseClassTypes.js | 10 +++++----- src/GraphQL/loaders/schemaTypes.js | 2 +- src/GraphQL/loaders/usersMutations.js | 2 +- src/GraphQL/transformers/mutation.js | 2 +- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 8d9fc7c23c..36fc3070c7 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -646,7 +646,7 @@ describe('ParseGraphQLServer', () => { const classType = (await apolloClient.query({ query: gql` query ClassType { - __type(name: "ClassObject") { + __type(name: "ParseObject") { kind fields { name @@ -739,7 +739,7 @@ describe('ParseGraphQLServer', () => { })).data['__schema'].types.map(type => type.name); const expectedTypes = [ - 'ClassObject', + 'ParseObject', 'CreateResult', 'Date', 'FileInfo', diff --git a/src/GraphQL/loaders/defaultGraphQLMutations.js b/src/GraphQL/loaders/defaultGraphQLMutations.js index a437d9ac53..203fd6d712 100644 --- a/src/GraphQL/loaders/defaultGraphQLMutations.js +++ b/src/GraphQL/loaders/defaultGraphQLMutations.js @@ -1,7 +1,7 @@ import * as filesMutations from './filesMutations'; import * as usersMutations from './usersMutations'; import * as functionsMutations from './functionsMutations'; -import * as classSchemaMutations from './classSchemaMutations'; +import * as classSchemaMutations from './schemaMutations'; const load = parseGraphQLSchema => { filesMutations.load(parseGraphQLSchema); diff --git a/src/GraphQL/loaders/defaultGraphQLTypes.js b/src/GraphQL/loaders/defaultGraphQLTypes.js index ba37b87a23..2c57a2d065 100644 --- a/src/GraphQL/loaders/defaultGraphQLTypes.js +++ b/src/GraphQL/loaders/defaultGraphQLTypes.js @@ -455,17 +455,17 @@ const UPDATE_RESULT = new GraphQLObjectType({ fields: UPDATE_RESULT_FIELDS, }); -const CLASS_OBJECT_FIELDS = { +const PARSE_OBJECT_FIELDS = { ...CREATE_RESULT_FIELDS, ...UPDATE_RESULT_FIELDS, ...INPUT_FIELDS, }; -const CLASS_OBJECT = new GraphQLInterfaceType({ - name: 'ClassObject', +const PARSE_OBJECT = new GraphQLInterfaceType({ + name: 'ParseObject', description: - 'The ClassObject interface type is used as a base type for the auto generated class object types.', - fields: CLASS_OBJECT_FIELDS, + 'The ParseObject interface type is used as a base type for the auto generated object types.', + fields: PARSE_OBJECT_FIELDS, }); const SESSION_TOKEN_ATT = { @@ -1074,7 +1074,7 @@ const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLType(GEO_POINT, true); parseGraphQLSchema.addGraphQLType(CREATE_RESULT, true); parseGraphQLSchema.addGraphQLType(UPDATE_RESULT, true); - parseGraphQLSchema.addGraphQLType(CLASS_OBJECT, true); + parseGraphQLSchema.addGraphQLType(PARSE_OBJECT, true); parseGraphQLSchema.addGraphQLType(READ_PREFERENCE, true); parseGraphQLSchema.addGraphQLType(SUBQUERY_INPUT, true); parseGraphQLSchema.addGraphQLType(SELECT_INPUT, true); @@ -1137,8 +1137,8 @@ export { CREATE_RESULT, UPDATE_RESULT_FIELDS, UPDATE_RESULT, - CLASS_OBJECT_FIELDS, - CLASS_OBJECT, + PARSE_OBJECT_FIELDS, + PARSE_OBJECT, SESSION_TOKEN_ATT, KEYS_ATT, INCLUDE_ATT, diff --git a/src/GraphQL/loaders/parseClassMutations.js b/src/GraphQL/loaders/parseClassMutations.js index c6343501cf..4a3b87f89e 100644 --- a/src/GraphQL/loaders/parseClassMutations.js +++ b/src/GraphQL/loaders/parseClassMutations.js @@ -5,8 +5,8 @@ import { extractKeysAndInclude, getParseClassMutationConfig, } from '../parseGraphQLUtils'; -import * as objectsMutations from './objectsMutations'; -import * as objectsQueries from './objectsQueries'; +import * as objectsMutations from '../helpers/objectsMutations'; +import * as objectsQueries from '../helpers/objectsQueries'; import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController'; import { transformClassNameToGraphQL } from '../transformers/className'; import { transformTypes } from '../transformers/mutation'; diff --git a/src/GraphQL/loaders/parseClassQueries.js b/src/GraphQL/loaders/parseClassQueries.js index cf98cc63c9..274dc13e70 100644 --- a/src/GraphQL/loaders/parseClassQueries.js +++ b/src/GraphQL/loaders/parseClassQueries.js @@ -2,7 +2,7 @@ import { GraphQLNonNull } from 'graphql'; import getFieldNames from 'graphql-list-fields'; import pluralize from 'pluralize'; import * as defaultGraphQLTypes from './defaultGraphQLTypes'; -import * as objectsQueries from './objectsQueries'; +import * as objectsQueries from '../helpers/objectsQueries'; import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController'; import { transformClassNameToGraphQL } from '../transformers/className'; import { extractKeysAndInclude } from '../parseGraphQLUtils'; diff --git a/src/GraphQL/loaders/parseClassTypes.js b/src/GraphQL/loaders/parseClassTypes.js index 0e1fed5e6e..69c529eb3a 100644 --- a/src/GraphQL/loaders/parseClassTypes.js +++ b/src/GraphQL/loaders/parseClassTypes.js @@ -11,7 +11,7 @@ import { } from 'graphql'; import getFieldNames from 'graphql-list-fields'; import * as defaultGraphQLTypes from './defaultGraphQLTypes'; -import * as objectsQueries from './objectsQueries'; +import * as objectsQueries from '../helpers/objectsQueries'; import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController'; import { transformClassNameToGraphQL } from '../transformers/className'; import { transformInputTypeToGraphQL } from '../transformers/inputType'; @@ -50,7 +50,7 @@ const getInputFieldsAndConstraints = function( // All allowed customs fields const classCustomFields = classFields.filter(field => { - return !Object.keys(defaultGraphQLTypes.CLASS_OBJECT_FIELDS).includes( + return !Object.keys(defaultGraphQLTypes.PARSE_OBJECT_FIELDS).includes( field ); }); @@ -572,12 +572,12 @@ const load = ( } else { return fields; } - }, defaultGraphQLTypes.CLASS_OBJECT_FIELDS); + }, defaultGraphQLTypes.PARSE_OBJECT_FIELDS); }; let classGraphQLOutputType = new GraphQLObjectType({ name: classGraphQLOutputTypeName, description: `The ${classGraphQLOutputTypeName} object type is used in operations that involve outputting objects of ${graphQLClassName} class.`, - interfaces: [defaultGraphQLTypes.CLASS_OBJECT], + interfaces: [defaultGraphQLTypes.PARSE_OBJECT], fields: outputFields, }); classGraphQLOutputType = parseGraphQLSchema.addGraphQLType( @@ -628,7 +628,7 @@ const load = ( const viewerType = new GraphQLObjectType({ name: 'Viewer', description: `The Viewer object type is used in operations that involve outputting the current user data.`, - interfaces: [defaultGraphQLTypes.CLASS_OBJECT], + interfaces: [defaultGraphQLTypes.PARSE_OBJECT], fields: () => ({ ...outputFields(), sessionToken: defaultGraphQLTypes.SESSION_TOKEN_ATT, diff --git a/src/GraphQL/loaders/schemaTypes.js b/src/GraphQL/loaders/schemaTypes.js index 76b9dcea88..6572969787 100644 --- a/src/GraphQL/loaders/schemaTypes.js +++ b/src/GraphQL/loaders/schemaTypes.js @@ -24,7 +24,7 @@ const SCHEMA_FIELD_INPUT = new GraphQLInputObjectType({ const SCHEMA_FIELD = new GraphQLInterfaceType({ name: 'SchemaField', description: - 'The ClassObject interface type is used as a base type for the auto generated class object types.', + 'The SchemaField interface type is used as a base type for the different supported fields of an object class schema.', fields: { name: SCHEMA_FIELD_NAME_ATT, }, diff --git a/src/GraphQL/loaders/usersMutations.js b/src/GraphQL/loaders/usersMutations.js index 98f3ea7a59..a4fb69faca 100644 --- a/src/GraphQL/loaders/usersMutations.js +++ b/src/GraphQL/loaders/usersMutations.js @@ -1,6 +1,6 @@ import { GraphQLNonNull } from 'graphql'; import UsersRouter from '../../Routers/UsersRouter'; -import * as objectsMutations from './objectsMutations'; +import * as objectsMutations from '../helpers/objectsMutations'; import { getUserFromSessionToken } from './usersQueries'; const usersRouter = new UsersRouter(); diff --git a/src/GraphQL/transformers/mutation.js b/src/GraphQL/transformers/mutation.js index eec564fe59..4fc5f6275c 100644 --- a/src/GraphQL/transformers/mutation.js +++ b/src/GraphQL/transformers/mutation.js @@ -1,5 +1,5 @@ import * as defaultGraphQLTypes from '../loaders/defaultGraphQLTypes'; -import * as objectsMutations from '../loaders/objectsMutations'; +import * as objectsMutations from '../helpers/objectsMutations'; const transformTypes = async ( inputType: 'create' | 'update', From b040db014fbc02c485bbfa285db92f17765e0f26 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 30 Aug 2019 18:20:07 -0700 Subject: [PATCH 59/60] Fix names and paths --- src/GraphQL/loaders/defaultGraphQLMutations.js | 4 ++-- src/GraphQL/loaders/defaultGraphQLQueries.js | 4 ++-- src/GraphQL/loaders/schemaMutations.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/GraphQL/loaders/defaultGraphQLMutations.js b/src/GraphQL/loaders/defaultGraphQLMutations.js index 203fd6d712..4d997a4822 100644 --- a/src/GraphQL/loaders/defaultGraphQLMutations.js +++ b/src/GraphQL/loaders/defaultGraphQLMutations.js @@ -1,13 +1,13 @@ import * as filesMutations from './filesMutations'; import * as usersMutations from './usersMutations'; import * as functionsMutations from './functionsMutations'; -import * as classSchemaMutations from './schemaMutations'; +import * as schemaMutations from './schemaMutations'; const load = parseGraphQLSchema => { filesMutations.load(parseGraphQLSchema); usersMutations.load(parseGraphQLSchema); functionsMutations.load(parseGraphQLSchema); - classSchemaMutations.load(parseGraphQLSchema); + schemaMutations.load(parseGraphQLSchema); }; export { load }; diff --git a/src/GraphQL/loaders/defaultGraphQLQueries.js b/src/GraphQL/loaders/defaultGraphQLQueries.js index 37b9e4a393..8e8616ca5f 100644 --- a/src/GraphQL/loaders/defaultGraphQLQueries.js +++ b/src/GraphQL/loaders/defaultGraphQLQueries.js @@ -1,6 +1,6 @@ import { GraphQLNonNull, GraphQLBoolean } from 'graphql'; import * as usersQueries from './usersQueries'; -import * as classSchemaQueries from './classSchemaQueries'; +import * as schemaQueries from './schemaQueries'; const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLQuery( @@ -16,7 +16,7 @@ const load = parseGraphQLSchema => { ); usersQueries.load(parseGraphQLSchema); - classSchemaQueries.load(parseGraphQLSchema); + schemaQueries.load(parseGraphQLSchema); }; export { load }; diff --git a/src/GraphQL/loaders/schemaMutations.js b/src/GraphQL/loaders/schemaMutations.js index 10bd882881..65c1a58795 100644 --- a/src/GraphQL/loaders/schemaMutations.js +++ b/src/GraphQL/loaders/schemaMutations.js @@ -6,7 +6,7 @@ import { transformToGraphQL, } from '../transformers/schemaFields'; import { enforceMasterKeyAccess } from '../parseGraphQLUtils'; -import { getClass } from './classSchemaQueries'; +import { getClass } from './schemaQueries'; const load = parseGraphQLSchema => { parseGraphQLSchema.addGraphQLMutation( From 153718ef8dd733f1c766200a55c9d85d04b9580f Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 30 Aug 2019 18:25:39 -0700 Subject: [PATCH 60/60] Still some wrong names --- src/GraphQL/ParseGraphQLSchema.js | 4 ++-- src/GraphQL/loaders/schemaMutations.js | 18 +++++++++--------- src/GraphQL/loaders/schemaQueries.js | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/GraphQL/ParseGraphQLSchema.js b/src/GraphQL/ParseGraphQLSchema.js index 1f55fbfd91..59efe9290d 100644 --- a/src/GraphQL/ParseGraphQLSchema.js +++ b/src/GraphQL/ParseGraphQLSchema.js @@ -14,7 +14,7 @@ import ParseGraphQLController, { import DatabaseController from '../Controllers/DatabaseController'; import { toGraphQLError } from './parseGraphQLUtils'; import * as schemaDirectives from './loaders/schemaDirectives'; -import * as classSchemaTypes from './loaders/classSchemaTypes'; +import * as schemaTypes from './loaders/schemaTypes'; const RESERVED_GRAPHQL_TYPE_NAMES = [ 'String', @@ -98,7 +98,7 @@ class ParseGraphQLSchema { this.graphQLSchemaDirectives = {}; defaultGraphQLTypes.load(this); - classSchemaTypes.load(this); + schemaTypes.load(this); this._getParseClassesWithConfig(parseClasses, parseGraphQLConfig).forEach( ([parseClass, parseClassConfig]) => { diff --git a/src/GraphQL/loaders/schemaMutations.js b/src/GraphQL/loaders/schemaMutations.js index 65c1a58795..71ac32d43d 100644 --- a/src/GraphQL/loaders/schemaMutations.js +++ b/src/GraphQL/loaders/schemaMutations.js @@ -1,6 +1,6 @@ import Parse from 'parse/node'; import { GraphQLNonNull } from 'graphql'; -import * as classSchemaTypes from './classSchemaTypes'; +import * as schemaTypes from './schemaTypes'; import { transformToParse, transformToGraphQL, @@ -15,13 +15,13 @@ const load = parseGraphQLSchema => { description: 'The createClass mutation can be used to create the schema for a new object class.', args: { - name: classSchemaTypes.CLASS_NAME_ATT, + name: schemaTypes.CLASS_NAME_ATT, schemaFields: { description: "These are the schema's fields of the object class.", - type: classSchemaTypes.SCHEMA_FIELDS_INPUT, + type: schemaTypes.SCHEMA_FIELDS_INPUT, }, }, - type: new GraphQLNonNull(classSchemaTypes.CLASS), + type: new GraphQLNonNull(schemaTypes.CLASS), resolve: async (_source, args, context) => { try { const { name, schemaFields } = args; @@ -60,13 +60,13 @@ const load = parseGraphQLSchema => { description: 'The updateClass mutation can be used to update the schema for an existing object class.', args: { - name: classSchemaTypes.CLASS_NAME_ATT, + name: schemaTypes.CLASS_NAME_ATT, schemaFields: { description: "These are the schema's fields of the object class.", - type: classSchemaTypes.SCHEMA_FIELDS_INPUT, + type: schemaTypes.SCHEMA_FIELDS_INPUT, }, }, - type: new GraphQLNonNull(classSchemaTypes.CLASS), + type: new GraphQLNonNull(schemaTypes.CLASS), resolve: async (_source, args, context) => { try { const { name, schemaFields } = args; @@ -109,9 +109,9 @@ const load = parseGraphQLSchema => { description: 'The deleteClass mutation can be used to delete an existing object class.', args: { - name: classSchemaTypes.CLASS_NAME_ATT, + name: schemaTypes.CLASS_NAME_ATT, }, - type: new GraphQLNonNull(classSchemaTypes.CLASS), + type: new GraphQLNonNull(schemaTypes.CLASS), resolve: async (_source, args, context) => { try { const { name } = args; diff --git a/src/GraphQL/loaders/schemaQueries.js b/src/GraphQL/loaders/schemaQueries.js index 2b0632ccfb..f5a166433a 100644 --- a/src/GraphQL/loaders/schemaQueries.js +++ b/src/GraphQL/loaders/schemaQueries.js @@ -1,7 +1,7 @@ import Parse from 'parse/node'; import { GraphQLNonNull, GraphQLList } from 'graphql'; import { transformToGraphQL } from '../transformers/schemaFields'; -import * as classSchemaTypes from './classSchemaTypes'; +import * as schemaTypes from './schemaTypes'; import { enforceMasterKeyAccess } from '../parseGraphQLUtils'; const getClass = async (name, schema) => { @@ -29,9 +29,9 @@ const load = parseGraphQLSchema => { description: 'The class query can be used to retrieve an existing object class.', args: { - name: classSchemaTypes.CLASS_NAME_ATT, + name: schemaTypes.CLASS_NAME_ATT, }, - type: new GraphQLNonNull(classSchemaTypes.CLASS), + type: new GraphQLNonNull(schemaTypes.CLASS), resolve: async (_source, args, context) => { try { const { name } = args; @@ -60,7 +60,7 @@ const load = parseGraphQLSchema => { description: 'The classes query can be used to retrieve the existing object classes.', type: new GraphQLNonNull( - new GraphQLList(new GraphQLNonNull(classSchemaTypes.CLASS)) + new GraphQLList(new GraphQLNonNull(schemaTypes.CLASS)) ), resolve: async (_source, _args, context) => { try {