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

File diff suppressed because it is too large Load Diff

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',