341 lines
10 KiB
JavaScript
341 lines
10 KiB
JavaScript
import { GraphQLNonNull } from 'graphql';
|
|
import { fromGlobalId, mutationWithClientMutationId } from 'graphql-relay';
|
|
import getFieldNames from 'graphql-list-fields';
|
|
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
|
import {
|
|
extractKeysAndInclude,
|
|
getParseClassMutationConfig,
|
|
} from '../parseGraphQLUtils';
|
|
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';
|
|
|
|
const getOnlyRequiredFields = (
|
|
updatedFields,
|
|
selectedFieldsString,
|
|
includedFieldsString,
|
|
nativeObjectFields
|
|
) => {
|
|
const includedFields = includedFieldsString
|
|
? includedFieldsString.split(',')
|
|
: [];
|
|
const selectedFields = selectedFieldsString
|
|
? selectedFieldsString.split(',')
|
|
: [];
|
|
const missingFields = selectedFields
|
|
.filter(
|
|
field =>
|
|
!nativeObjectFields.includes(field) || includedFields.includes(field)
|
|
)
|
|
.join(',');
|
|
if (!missingFields.length) {
|
|
return { needGet: false, keys: '' };
|
|
} else {
|
|
return { needGet: true, keys: missingFields };
|
|
}
|
|
};
|
|
|
|
const load = function(
|
|
parseGraphQLSchema,
|
|
parseClass,
|
|
parseClassConfig: ?ParseGraphQLClassConfig
|
|
) {
|
|
const className = parseClass.className;
|
|
const graphQLClassName = transformClassNameToGraphQL(className);
|
|
const getGraphQLQueryName =
|
|
graphQLClassName.charAt(0).toLowerCase() + graphQLClassName.slice(1);
|
|
|
|
const {
|
|
create: isCreateEnabled = true,
|
|
update: isUpdateEnabled = true,
|
|
destroy: isDestroyEnabled = true,
|
|
createAlias: createAlias = '',
|
|
updateAlias: updateAlias = '',
|
|
destroyAlias: destroyAlias = '',
|
|
} = getParseClassMutationConfig(parseClassConfig);
|
|
|
|
const {
|
|
classGraphQLCreateType,
|
|
classGraphQLUpdateType,
|
|
classGraphQLOutputType,
|
|
} = parseGraphQLSchema.parseClassTypes[className];
|
|
|
|
if (isCreateEnabled) {
|
|
const createGraphQLMutationName =
|
|
createAlias || `create${graphQLClassName}`;
|
|
const createGraphQLMutation = mutationWithClientMutationId({
|
|
name: `Create${graphQLClassName}`,
|
|
description: `The ${createGraphQLMutationName} mutation can be used to create a new object of the ${graphQLClassName} class.`,
|
|
inputFields: {
|
|
fields: {
|
|
description:
|
|
'These are the fields that will be used to create the new object.',
|
|
type: classGraphQLCreateType || defaultGraphQLTypes.OBJECT,
|
|
},
|
|
},
|
|
outputFields: {
|
|
[getGraphQLQueryName]: {
|
|
description: 'This is the created object.',
|
|
type: new GraphQLNonNull(
|
|
classGraphQLOutputType || defaultGraphQLTypes.OBJECT
|
|
),
|
|
},
|
|
},
|
|
mutateAndGetPayload: async (args, context, mutationInfo) => {
|
|
try {
|
|
let { fields } = args;
|
|
if (!fields) fields = {};
|
|
const { config, auth, info } = context;
|
|
|
|
const parseFields = await transformTypes('create', fields, {
|
|
className,
|
|
parseGraphQLSchema,
|
|
req: { config, auth, info },
|
|
});
|
|
|
|
const createdObject = await objectsMutations.createObject(
|
|
className,
|
|
parseFields,
|
|
config,
|
|
auth,
|
|
info
|
|
);
|
|
const selectedFields = getFieldNames(mutationInfo)
|
|
.filter(field => field.startsWith(`${getGraphQLQueryName}.`))
|
|
.map(field => field.replace(`${getGraphQLQueryName}.`, ''));
|
|
const { keys, include } = extractKeysAndInclude(selectedFields);
|
|
const { keys: requiredKeys, needGet } = getOnlyRequiredFields(
|
|
fields,
|
|
keys,
|
|
include,
|
|
['id', 'objectId', 'createdAt', 'updatedAt']
|
|
);
|
|
let optimizedObject = {};
|
|
if (needGet) {
|
|
optimizedObject = await objectsQueries.getObject(
|
|
className,
|
|
createdObject.objectId,
|
|
requiredKeys,
|
|
include,
|
|
undefined,
|
|
undefined,
|
|
config,
|
|
auth,
|
|
info
|
|
);
|
|
}
|
|
return {
|
|
[getGraphQLQueryName]: {
|
|
...createdObject,
|
|
updatedAt: createdObject.createdAt,
|
|
...parseFields,
|
|
...optimizedObject,
|
|
},
|
|
};
|
|
} catch (e) {
|
|
parseGraphQLSchema.handleError(e);
|
|
}
|
|
},
|
|
});
|
|
|
|
if (
|
|
parseGraphQLSchema.addGraphQLType(
|
|
createGraphQLMutation.args.input.type.ofType
|
|
) &&
|
|
parseGraphQLSchema.addGraphQLType(createGraphQLMutation.type)
|
|
) {
|
|
parseGraphQLSchema.addGraphQLMutation(
|
|
createGraphQLMutationName,
|
|
createGraphQLMutation
|
|
);
|
|
}
|
|
}
|
|
|
|
if (isUpdateEnabled) {
|
|
const updateGraphQLMutationName =
|
|
updateAlias || `update${graphQLClassName}`;
|
|
const updateGraphQLMutation = mutationWithClientMutationId({
|
|
name: `Update${graphQLClassName}`,
|
|
description: `The ${updateGraphQLMutationName} mutation can be used to update an object of the ${graphQLClassName} class.`,
|
|
inputFields: {
|
|
id: defaultGraphQLTypes.GLOBAL_OR_OBJECT_ID_ATT,
|
|
fields: {
|
|
description:
|
|
'These are the fields that will be used to update the object.',
|
|
type: classGraphQLUpdateType || defaultGraphQLTypes.OBJECT,
|
|
},
|
|
},
|
|
outputFields: {
|
|
[getGraphQLQueryName]: {
|
|
description: 'This is the updated object.',
|
|
type: new GraphQLNonNull(
|
|
classGraphQLOutputType || defaultGraphQLTypes.OBJECT
|
|
),
|
|
},
|
|
},
|
|
mutateAndGetPayload: async (args, context, mutationInfo) => {
|
|
try {
|
|
let { id, fields } = args;
|
|
if (!fields) fields = {};
|
|
const { config, auth, info } = context;
|
|
|
|
const globalIdObject = fromGlobalId(id);
|
|
|
|
if (globalIdObject.type === className) {
|
|
id = globalIdObject.id;
|
|
}
|
|
|
|
const parseFields = await transformTypes('update', fields, {
|
|
className,
|
|
parseGraphQLSchema,
|
|
req: { config, auth, info },
|
|
});
|
|
|
|
const updatedObject = await objectsMutations.updateObject(
|
|
className,
|
|
id,
|
|
parseFields,
|
|
config,
|
|
auth,
|
|
info
|
|
);
|
|
|
|
const selectedFields = getFieldNames(mutationInfo)
|
|
.filter(field => field.startsWith(`${getGraphQLQueryName}.`))
|
|
.map(field => field.replace(`${getGraphQLQueryName}.`, ''));
|
|
const { keys, include } = extractKeysAndInclude(selectedFields);
|
|
const { keys: requiredKeys, needGet } = getOnlyRequiredFields(
|
|
fields,
|
|
keys,
|
|
include,
|
|
['id', 'objectId', 'updatedAt']
|
|
);
|
|
|
|
let optimizedObject = {};
|
|
if (needGet) {
|
|
optimizedObject = await objectsQueries.getObject(
|
|
className,
|
|
id,
|
|
requiredKeys,
|
|
include,
|
|
undefined,
|
|
undefined,
|
|
config,
|
|
auth,
|
|
info
|
|
);
|
|
}
|
|
return {
|
|
[getGraphQLQueryName]: {
|
|
objectId: id,
|
|
...updatedObject,
|
|
...parseFields,
|
|
...optimizedObject,
|
|
},
|
|
};
|
|
} catch (e) {
|
|
parseGraphQLSchema.handleError(e);
|
|
}
|
|
},
|
|
});
|
|
|
|
if (
|
|
parseGraphQLSchema.addGraphQLType(
|
|
updateGraphQLMutation.args.input.type.ofType
|
|
) &&
|
|
parseGraphQLSchema.addGraphQLType(updateGraphQLMutation.type)
|
|
) {
|
|
parseGraphQLSchema.addGraphQLMutation(
|
|
updateGraphQLMutationName,
|
|
updateGraphQLMutation
|
|
);
|
|
}
|
|
}
|
|
|
|
if (isDestroyEnabled) {
|
|
const deleteGraphQLMutationName =
|
|
destroyAlias || `delete${graphQLClassName}`;
|
|
const deleteGraphQLMutation = mutationWithClientMutationId({
|
|
name: `Delete${graphQLClassName}`,
|
|
description: `The ${deleteGraphQLMutationName} mutation can be used to delete an object of the ${graphQLClassName} class.`,
|
|
inputFields: {
|
|
id: defaultGraphQLTypes.GLOBAL_OR_OBJECT_ID_ATT,
|
|
},
|
|
outputFields: {
|
|
[getGraphQLQueryName]: {
|
|
description: 'This is the deleted object.',
|
|
type: new GraphQLNonNull(
|
|
classGraphQLOutputType || defaultGraphQLTypes.OBJECT
|
|
),
|
|
},
|
|
},
|
|
mutateAndGetPayload: async (args, context, mutationInfo) => {
|
|
try {
|
|
let { id } = args;
|
|
const { config, auth, info } = context;
|
|
|
|
const globalIdObject = fromGlobalId(id);
|
|
|
|
if (globalIdObject.type === className) {
|
|
id = globalIdObject.id;
|
|
}
|
|
|
|
const selectedFields = getFieldNames(mutationInfo)
|
|
.filter(field => field.startsWith(`${getGraphQLQueryName}.`))
|
|
.map(field => field.replace(`${getGraphQLQueryName}.`, ''));
|
|
const { keys, include } = extractKeysAndInclude(selectedFields);
|
|
let optimizedObject = {};
|
|
if (
|
|
keys &&
|
|
keys.split(',').filter(key => !['id', 'objectId'].includes(key))
|
|
.length > 0
|
|
) {
|
|
optimizedObject = await objectsQueries.getObject(
|
|
className,
|
|
id,
|
|
keys,
|
|
include,
|
|
undefined,
|
|
undefined,
|
|
config,
|
|
auth,
|
|
info
|
|
);
|
|
}
|
|
await objectsMutations.deleteObject(
|
|
className,
|
|
id,
|
|
config,
|
|
auth,
|
|
info
|
|
);
|
|
return {
|
|
[getGraphQLQueryName]: {
|
|
objectId: id,
|
|
...optimizedObject,
|
|
},
|
|
};
|
|
} catch (e) {
|
|
parseGraphQLSchema.handleError(e);
|
|
}
|
|
},
|
|
});
|
|
|
|
if (
|
|
parseGraphQLSchema.addGraphQLType(
|
|
deleteGraphQLMutation.args.input.type.ofType
|
|
) &&
|
|
parseGraphQLSchema.addGraphQLType(deleteGraphQLMutation.type)
|
|
) {
|
|
parseGraphQLSchema.addGraphQLMutation(
|
|
deleteGraphQLMutationName,
|
|
deleteGraphQLMutation
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
export { load };
|