From f9b77c1bc7be266fa44b0a233306f26ccf3df685 Mon Sep 17 00:00:00 2001 From: Douglas Muraoka Date: Wed, 4 Sep 2019 19:46:18 -0300 Subject: [PATCH] refactor(GraphQL): Pointer constraint input type as ID (#6020) * refactor(GraphQL): Pointer constraint input type as ID Redefines the Pointer constraint input type from a custom scalar to a simple ID. * fix: PR review requested changes --- spec/ParseGraphQLServer.spec.js | 52 +++++++++---- src/GraphQL/helpers/objectsQueries.js | 5 +- src/GraphQL/loaders/parseClassQueries.js | 3 +- src/GraphQL/loaders/parseClassTypes.js | 94 ++---------------------- src/GraphQL/transformers/query.js | 23 +++++- 5 files changed, 68 insertions(+), 109 deletions(-) diff --git a/spec/ParseGraphQLServer.spec.js b/spec/ParseGraphQLServer.spec.js index 8ef884875f..7718ad184b 100644 --- a/spec/ParseGraphQLServer.spec.js +++ b/spec/ParseGraphQLServer.spec.js @@ -3384,11 +3384,7 @@ describe('ParseGraphQLServer', () => { OR: [ { pointerToUser: { - equalTo: { - __type: 'Pointer', - className: '_User', - objectId: user5.id, - }, + equalTo: user5.id, }, }, { @@ -3413,6 +3409,40 @@ describe('ParseGraphQLServer', () => { ).toEqual(['someValue1', 'someValue3']); }); + it('should support in pointer operator using class specific query', async () => { + await prepareData(); + + await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(); + + const result = await apolloClient.query({ + query: gql` + query FindSomeObjects($where: GraphQLClassWhereInput) { + graphQLClasses(where: $where) { + results { + someField + } + } + } + `, + variables: { + where: { + pointerToUser: { + in: [user5.id], + }, + }, + }, + context: { + headers: { + 'X-Parse-Master-Key': 'test', + }, + }, + }); + + const { results } = result.data.graphQLClasses; + expect(results.length).toBe(1); + expect(results[0].someField).toEqual('someValue3'); + }); + it('should support OR operation', async () => { await prepareData(); @@ -3558,11 +3588,7 @@ describe('ParseGraphQLServer', () => { OR: [ { pointerToUser: { - equalTo: { - __type: 'Pointer', - className: '_User', - objectId: user5.id, - }, + equalTo: user5.id, }, }, { @@ -3614,11 +3640,7 @@ describe('ParseGraphQLServer', () => { OR: [ { pointerToUser: { - equalTo: { - __type: 'Pointer', - className: '_User', - objectId: user5.id, - }, + equalTo: user5.id, }, }, { diff --git a/src/GraphQL/helpers/objectsQueries.js b/src/GraphQL/helpers/objectsQueries.js index 4eeb4c2bfb..b63e38eb25 100644 --- a/src/GraphQL/helpers/objectsQueries.js +++ b/src/GraphQL/helpers/objectsQueries.js @@ -62,12 +62,13 @@ const findObjects = async ( config, auth, info, - selectedFields + selectedFields, + fields ) => { if (!where) { where = {}; } - transformQueryInputToParse(where); + transformQueryInputToParse(where, fields); const options = {}; diff --git a/src/GraphQL/loaders/parseClassQueries.js b/src/GraphQL/loaders/parseClassQueries.js index 274dc13e70..cc33e73704 100644 --- a/src/GraphQL/loaders/parseClassQueries.js +++ b/src/GraphQL/loaders/parseClassQueries.js @@ -120,7 +120,8 @@ const load = function( config, auth, info, - selectedFields.map(field => field.split('.', 1)[0]) + selectedFields.map(field => field.split('.', 1)[0]), + parseClass.fields ); } catch (e) { parseGraphQLSchema.handleError(e); diff --git a/src/GraphQL/loaders/parseClassTypes.js b/src/GraphQL/loaders/parseClassTypes.js index b86bf9b264..6c6a6777e1 100644 --- a/src/GraphQL/loaders/parseClassTypes.js +++ b/src/GraphQL/loaders/parseClassTypes.js @@ -1,12 +1,10 @@ import { - Kind, GraphQLID, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLInputObjectType, GraphQLNonNull, - GraphQLScalarType, GraphQLEnumType, } from 'graphql'; import getFieldNames from 'graphql-list-fields'; @@ -138,86 +136,6 @@ const load = ( update: isUpdateEnabled = true, } = getParseClassMutationConfig(parseClassConfig); - const classGraphQLScalarTypeName = `${graphQLClassName}Pointer`; - const parseScalarValue = value => { - if (typeof value === 'string') { - return { - __type: 'Pointer', - className: className, - objectId: value, - }; - } else if ( - typeof value === 'object' && - value.__type === 'Pointer' && - value.className === className && - typeof value.objectId === 'string' - ) { - return { ...value, className }; - } - - throw new defaultGraphQLTypes.TypeValidationError( - value, - classGraphQLScalarTypeName - ); - }; - let classGraphQLScalarType = new GraphQLScalarType({ - name: classGraphQLScalarTypeName, - description: `The ${classGraphQLScalarTypeName} is used in operations that involve ${graphQLClassName} pointers.`, - parseValue: parseScalarValue, - serialize(value) { - if (typeof value === 'string') { - return value; - } else if ( - typeof value === 'object' && - value.__type === 'Pointer' && - value.className === className && - typeof value.objectId === 'string' - ) { - return value.objectId; - } - - throw new defaultGraphQLTypes.TypeValidationError( - value, - classGraphQLScalarTypeName - ); - }, - parseLiteral(ast) { - if (ast.kind === Kind.STRING) { - return parseScalarValue(ast.value); - } else if (ast.kind === Kind.OBJECT) { - const __type = ast.fields.find(field => field.name.value === '__type'); - const className = ast.fields.find( - field => field.name.value === 'className' - ); - const objectId = ast.fields.find( - field => field.name.value === 'objectId' - ); - if ( - __type && - __type.value && - className && - className.value && - objectId && - objectId.value - ) { - return parseScalarValue({ - __type: __type.value.value, - className: className.value.value, - objectId: objectId.value.value, - }); - } - } - - throw new defaultGraphQLTypes.TypeValidationError( - ast.kind, - classGraphQLScalarTypeName - ); - }, - }); - classGraphQLScalarType = - parseGraphQLSchema.addGraphQLType(classGraphQLScalarType) || - defaultGraphQLTypes.OBJECT; - const classGraphQLCreateTypeName = `Create${graphQLClassName}FieldsInput`; let classGraphQLCreateType = new GraphQLInputObjectType({ name: classGraphQLCreateTypeName, @@ -341,10 +259,10 @@ const load = ( name: classGraphQLConstraintTypeName, description: `The ${classGraphQLConstraintTypeName} input type is used in operations that involve filtering objects by a pointer field to ${graphQLClassName} class.`, fields: { - equalTo: defaultGraphQLTypes.equalTo(classGraphQLScalarType), - notEqualTo: defaultGraphQLTypes.notEqualTo(classGraphQLScalarType), - in: defaultGraphQLTypes.inOp(classGraphQLScalarType), - notIn: defaultGraphQLTypes.notIn(classGraphQLScalarType), + equalTo: defaultGraphQLTypes.equalTo(GraphQLID), + notEqualTo: defaultGraphQLTypes.notEqualTo(GraphQLID), + in: defaultGraphQLTypes.inOp(defaultGraphQLTypes.OBJECT_ID), + notIn: defaultGraphQLTypes.notIn(defaultGraphQLTypes.OBJECT_ID), exists: defaultGraphQLTypes.exists, inQueryKey: defaultGraphQLTypes.inQueryKey, notInQueryKey: defaultGraphQLTypes.notInQueryKey, @@ -519,7 +437,8 @@ const load = ( config, auth, info, - selectedFields.map(field => field.split('.', 1)[0]) + selectedFields.map(field => field.split('.', 1)[0]), + parseClass.fields ); } catch (e) { parseGraphQLSchema.handleError(e); @@ -615,7 +534,6 @@ const load = ( parseGraphQLSchema.parseClassTypes[className] = { classGraphQLPointerType, classGraphQLRelationType, - classGraphQLScalarType, classGraphQLCreateType, classGraphQLUpdateType, classGraphQLConstraintType, diff --git a/src/GraphQL/transformers/query.js b/src/GraphQL/transformers/query.js index 06c4c0f1d6..e202b2a94f 100644 --- a/src/GraphQL/transformers/query.js +++ b/src/GraphQL/transformers/query.js @@ -45,6 +45,7 @@ const parseConstraintMap = { const transformQueryConstraintInputToParse = ( constraints, + fields, parentFieldName, parentConstraints ) => { @@ -92,6 +93,21 @@ const transformQueryConstraintInputToParse = ( delete constraints[fieldName]; fieldName = parseConstraintMap[fieldName]; constraints[fieldName] = fieldValue; + + // If parent field type is Pointer, changes constraint value to format expected + // by Parse. + if ( + fields[parentFieldName] && + fields[parentFieldName].type === 'Pointer' && + typeof fieldValue === 'string' + ) { + const { targetClass } = fields[parentFieldName]; + constraints[fieldName] = { + __type: 'Pointer', + className: targetClass, + objectId: fieldValue, + }; + } } switch (fieldName) { case '$point': @@ -151,6 +167,7 @@ const transformQueryConstraintInputToParse = ( } else { transformQueryConstraintInputToParse( fieldValue, + fields, fieldName, constraints ); @@ -159,7 +176,7 @@ const transformQueryConstraintInputToParse = ( }); }; -const transformQueryInputToParse = constraints => { +const transformQueryInputToParse = (constraints, fields) => { if (!constraints || typeof constraints !== 'object') { return; } @@ -174,14 +191,14 @@ const transformQueryInputToParse = constraints => { if (fieldName !== 'objectId') { fieldValue.forEach(fieldValueItem => { - transformQueryInputToParse(fieldValueItem); + transformQueryInputToParse(fieldValueItem, fields); }); return; } } if (typeof fieldValue === 'object') { - transformQueryConstraintInputToParse(fieldValue, fieldName, constraints); + transformQueryConstraintInputToParse(fieldValue, fields, fieldName, constraints); } }); };