refactor(GraphQL): Rename objectId to id (#5985)

* refactor(GraphQL): Rename objectId to id

Renames `objectId` to `id` for the GraphQL API. Queries, mutations,
custom and generic types were updated.
Removes `RELATION_INPUT` and `POINTER_INPUT`. Now the user just need
to provide the ID of the object to link.

* fix: Column "id" not found on Postgres

* fix: Avoid deleting Parse class objectId

* fix: Undo objectId removal on mutations

* fix: Handle generic mutation id
This commit is contained in:
Douglas Muraoka
2019-08-30 20:23:46 -03:00
committed by Antonio Davi Macedo Coelho de Castro
parent 194f548464
commit b47d9fb17e
10 changed files with 496 additions and 546 deletions

View File

@@ -395,16 +395,7 @@ const POLYGON_INPUT = new GraphQLList(new GraphQLNonNull(GEO_POINT_INPUT));
const POLYGON = new GraphQLList(new GraphQLNonNull(GEO_POINT));
const RELATION_INPUT = new GraphQLInputObjectType({
name: 'RelationInput',
description: 'Object involved into a relation',
fields: {
objectId: {
description: 'Id of the object involved.',
type: new GraphQLNonNull(GraphQLID),
},
},
});
const OBJECT_ID = new GraphQLNonNull(GraphQLID);
const CLASS_NAME_ATT = {
description: 'This is the class name of the object.',
@@ -418,7 +409,8 @@ const FIELDS_ATT = {
const OBJECT_ID_ATT = {
description: 'This is the object id.',
type: new GraphQLNonNull(GraphQLID),
type: OBJECT_ID,
resolve: ({ objectId }) => objectId,
};
const CREATED_AT_ATT = {
@@ -441,7 +433,7 @@ const INPUT_FIELDS = {
};
const CREATE_RESULT_FIELDS = {
objectId: OBJECT_ID_ATT,
id: OBJECT_ID_ATT,
createdAt: CREATED_AT_ATT,
};
@@ -491,17 +483,6 @@ const INCLUDE_ATT = {
type: GraphQLString,
};
const POINTER_INPUT = new GraphQLInputObjectType({
name: 'PointerInput',
description: 'Allow to link an object to another object',
fields: {
objectId: {
description: 'Id of the object involved.',
type: new GraphQLNonNull(GraphQLID),
},
},
});
const READ_PREFERENCE = new GraphQLEnumType({
name: 'ReadPreference',
description:
@@ -1118,8 +1099,7 @@ const load = parseGraphQLSchema => {
parseGraphQLSchema.addGraphQLType(FIND_RESULT, true);
parseGraphQLSchema.addGraphQLType(SIGN_UP_RESULT, true);
parseGraphQLSchema.addGraphQLType(ELEMENT, true);
parseGraphQLSchema.addGraphQLType(RELATION_INPUT, true);
parseGraphQLSchema.addGraphQLType(POINTER_INPUT, true);
parseGraphQLSchema.addGraphQLType(OBJECT_ID, true);
};
export {
@@ -1145,6 +1125,7 @@ export {
GEO_POINT,
POLYGON_INPUT,
POLYGON,
OBJECT_ID,
CLASS_NAME_ATT,
FIELDS_ATT,
OBJECT_ID_ATT,
@@ -1206,8 +1187,6 @@ export {
SIGN_UP_RESULT,
ARRAY_RESULT,
ELEMENT,
POINTER_INPUT,
RELATION_INPUT,
load,
loadArrayResult,
};

View File

@@ -54,7 +54,15 @@ const load = parseGraphQLSchema => {
const { className, fields } = args;
const { config, auth, info } = context;
return await createObject(className, fields, config, auth, info);
const object = await createObject(
className,
fields,
config,
auth,
info
);
return object;
} catch (e) {
parseGraphQLSchema.handleError(e);
}
@@ -71,23 +79,16 @@ const load = parseGraphQLSchema => {
'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,
id: 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 { className, id, fields } = args;
const { config, auth, info } = context;
return await updateObject(
className,
objectId,
fields,
config,
auth,
info
);
return await updateObject(className, id, fields, config, auth, info);
} catch (e) {
parseGraphQLSchema.handleError(e);
}
@@ -104,15 +105,15 @@ const load = parseGraphQLSchema => {
'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,
id: defaultGraphQLTypes.OBJECT_ID_ATT,
},
type: new GraphQLNonNull(GraphQLBoolean),
async resolve(_source, args, context) {
try {
const { className, objectId } = args;
const { className, id } = args;
const { config, auth, info } = context;
return await deleteObject(className, objectId, config, auth, info);
return await deleteObject(className, id, config, auth, info);
} catch (e) {
parseGraphQLSchema.handleError(e);
}

View File

@@ -43,11 +43,11 @@ const getObject = async (
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
}
const object = response.results[0];
if (className === '_User') {
delete response.results[0].sessionToken;
delete object.sessionToken;
}
return response.results[0];
return object;
};
const findObjects = async (
@@ -70,7 +70,6 @@ const findObjects = async (
if (!where) {
where = {};
}
transformQueryInputToParse(where);
const options = {};
@@ -136,7 +135,7 @@ const load = parseGraphQLSchema => {
'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,
id: defaultGraphQLTypes.OBJECT_ID_ATT,
keys: defaultGraphQLTypes.KEYS_ATT,
include: defaultGraphQLTypes.INCLUDE_ATT,
readPreference: defaultGraphQLTypes.READ_PREFERENCE_ATT,
@@ -147,7 +146,7 @@ const load = parseGraphQLSchema => {
try {
const {
className,
objectId,
id,
keys,
include,
readPreference,
@@ -156,9 +155,9 @@ const load = parseGraphQLSchema => {
const { config, auth, info } = context;
return await getObject(
const object = await getObject(
className,
objectId,
id,
keys,
include,
readPreference,
@@ -167,6 +166,10 @@ const load = parseGraphQLSchema => {
auth,
info
);
object.id = object.objectId;
delete object.objectId;
return object;
} catch (e) {
parseGraphQLSchema.handleError(e);
}
@@ -222,7 +225,7 @@ const load = parseGraphQLSchema => {
const { config, auth, info } = context;
const selectedFields = getFieldNames(queryInfo);
return await findObjects(
const objects = await findObjects(
className,
where,
order,
@@ -239,6 +242,11 @@ const load = parseGraphQLSchema => {
info,
selectedFields
);
objects.results.forEach(obj => {
obj.id = obj.objectId;
delete obj.objectId;
});
return objects;
} catch (e) {
parseGraphQLSchema.handleError(e);
}

View File

@@ -91,7 +91,7 @@ const load = function(
fields,
keys,
include,
['objectId', 'createdAt', 'updatedAt']
['id', 'createdAt', 'updatedAt']
);
let optimizedObject = {};
if (needGet) {
@@ -125,7 +125,7 @@ const load = function(
parseGraphQLSchema.addGraphQLMutation(updateGraphQLMutationName, {
description: `The ${updateGraphQLMutationName} mutation can be used to update an object of the ${graphQLClassName} class.`,
args: {
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
id: defaultGraphQLTypes.OBJECT_ID_ATT,
fields: {
description: 'These are the fields used to update the object.',
type: classGraphQLUpdateType || defaultGraphQLTypes.OBJECT,
@@ -136,7 +136,7 @@ const load = function(
),
async resolve(_source, args, context, mutationInfo) {
try {
const { objectId, fields } = args;
const { id, fields } = args;
const { config, auth, info } = context;
const parseFields = await transformTypes('update', fields, {
@@ -147,7 +147,7 @@ const load = function(
const updatedObject = await objectsMutations.updateObject(
className,
objectId,
id,
parseFields,
config,
auth,
@@ -160,13 +160,13 @@ const load = function(
fields,
keys,
include,
['objectId', 'updatedAt']
['id', 'updatedAt']
);
let optimizedObject = {};
if (needGet) {
optimizedObject = await objectsQueries.getObject(
className,
objectId,
id,
requiredKeys,
include,
undefined,
@@ -177,7 +177,7 @@ const load = function(
);
}
return {
objectId: objectId,
id,
...updatedObject,
...fields,
...optimizedObject,
@@ -194,24 +194,24 @@ const load = function(
parseGraphQLSchema.addGraphQLMutation(deleteGraphQLMutationName, {
description: `The ${deleteGraphQLMutationName} mutation can be used to delete an object of the ${graphQLClassName} class.`,
args: {
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
id: defaultGraphQLTypes.OBJECT_ID_ATT,
},
type: new GraphQLNonNull(
classGraphQLOutputType || defaultGraphQLTypes.OBJECT
),
async resolve(_source, args, context, mutationInfo) {
try {
const { objectId } = args;
const { id } = args;
const { config, auth, info } = context;
const selectedFields = getFieldNames(mutationInfo);
const { keys, include } = extractKeysAndInclude(selectedFields);
let optimizedObject = {};
const splitedKeys = keys.split(',');
if (splitedKeys.length > 1 || splitedKeys[0] !== 'objectId') {
if (splitedKeys.length > 1 || splitedKeys[0] !== 'id') {
optimizedObject = await objectsQueries.getObject(
className,
objectId,
id,
keys,
include,
undefined,
@@ -223,12 +223,12 @@ const load = function(
}
await objectsMutations.deleteObject(
className,
objectId,
id,
config,
auth,
info
);
return { objectId: objectId, ...optimizedObject };
return { id, ...optimizedObject };
} catch (e) {
parseGraphQLSchema.handleError(e);
}

View File

@@ -14,7 +14,7 @@ const getParseClassQueryConfig = function(
};
const getQuery = async (className, _source, args, context, queryInfo) => {
const { objectId, readPreference, includeReadPreference } = args;
const { id, readPreference, includeReadPreference } = args;
const { config, auth, info } = context;
const selectedFields = getFieldNames(queryInfo);
@@ -22,7 +22,7 @@ const getQuery = async (className, _source, args, context, queryInfo) => {
return await objectsQueries.getObject(
className,
objectId,
id,
keys,
include,
readPreference,
@@ -57,7 +57,7 @@ const load = function(
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,
id: defaultGraphQLTypes.OBJECT_ID_ATT,
readPreference: defaultGraphQLTypes.READ_PREFERENCE_ATT,
includeReadPreference: defaultGraphQLTypes.INCLUDE_READ_PREFERENCE_ATT,
},

View File

@@ -1,5 +1,6 @@
import {
Kind,
GraphQLID,
GraphQLObjectType,
GraphQLString,
GraphQLFloat,
@@ -165,7 +166,9 @@ const getInputFieldsAndConstraints = function(
parseClass,
parseClassConfig: ?ParseGraphQLClassConfig
) {
const classFields = Object.keys(parseClass.fields);
const classFields = Object.keys(parseClass.fields)
.filter(field => field !== 'objectId')
.concat('id');
const {
inputFields: allowedInputFields,
outputFields: allowedOutputFields,
@@ -227,7 +230,7 @@ const getInputFieldsAndConstraints = function(
// must have at least 1 order field
// otherwise the FindArgs Input Type will throw.
classSortFields.push({
field: 'objectId',
field: 'id',
asc: true,
desc: true,
});
@@ -421,7 +424,7 @@ const load = (
const fields = {
link: {
description: `Link an existing object from ${graphQLClassName} class.`,
type: defaultGraphQLTypes.POINTER_INPUT,
type: GraphQLID,
},
};
if (isCreateEnabled) {
@@ -445,15 +448,11 @@ const load = (
const fields = {
add: {
description: `Add an existing object from the ${graphQLClassName} class into the relation.`,
type: new GraphQLList(
new GraphQLNonNull(defaultGraphQLTypes.RELATION_INPUT)
),
type: new GraphQLList(defaultGraphQLTypes.OBJECT_ID),
},
remove: {
description: `Remove an existing object from the ${graphQLClassName} class out of the relation.`,
type: new GraphQLList(
new GraphQLNonNull(defaultGraphQLTypes.RELATION_INPUT)
),
type: new GraphQLList(defaultGraphQLTypes.OBJECT_ID),
},
};
if (isCreateEnabled) {
@@ -503,9 +502,10 @@ const load = (
description: `The ${classGraphQLConstraintsTypeName} input type is used in operations that involve filtering objects of ${graphQLClassName} class.`,
fields: () => ({
...classConstraintFields.reduce((fields, field) => {
const parseField = field === 'id' ? 'objectId' : field;
const type = mapConstraintType(
parseClass.fields[field].type,
parseClass.fields[field].targetClass,
parseClass.fields[parseField].type,
parseClass.fields[parseField].targetClass,
parseGraphQLSchema.parseClassTypes
);
if (type) {

View File

@@ -17,9 +17,17 @@ export const extractKeysAndInclude = selectedFields => {
selectedFields = selectedFields.filter(
field => !field.includes('__typename')
);
// Handles "id" field for both current and included objects
selectedFields = selectedFields.map(field => {
if (field === 'id') return 'objectId';
return field.endsWith('.id')
? `${field.substring(0, field.lastIndexOf('.id'))}.objectId`
: field;
});
let keys = undefined;
let include = undefined;
if (selectedFields && selectedFields.length > 0) {
if (selectedFields.length > 0) {
keys = selectedFields.join(',');
include = selectedFields
.reduce((fields, field) => {

View File

@@ -119,7 +119,7 @@ const transformers = {
value.add = value.add.map(input => ({
__type: 'Pointer',
className: targetClass,
objectId: input.objectId,
objectId: input,
}));
op.ops.push({
__op: 'AddRelation',
@@ -133,7 +133,7 @@ const transformers = {
objects: value.remove.map(input => ({
__type: 'Pointer',
className: targetClass,
objectId: input.objectId,
objectId: input,
})),
});
}
@@ -171,11 +171,11 @@ const transformers = {
objectId: nestedObjectToAdd.objectId,
};
}
if (value.link && value.link.objectId) {
if (value.link) {
return {
__type: 'Pointer',
className: targetClass,
objectId: value.link.objectId,
objectId: value.link,
};
}
},

View File

@@ -1,4 +1,5 @@
const parseMap = {
id: 'objectId',
_or: '$or',
_and: '$and',
_nor: '$nor',