Files
kami-parse-server/src/GraphQL/transformers/mutation.js
Antonio Davi Macedo Coelho de Castro a9066e20dc Relay Spec (#6089)
* Install graphql-relay

* Add relayNodeInterface to ParseGraphQLSchema

* Add support to global id

* Add support to global id in other operations

* Fix sort by glboal id

* Fix where by global id

* Introduce IdWhereInput

* Add Relay object identification tests

* Client mutation id on createFile mutation

* Client mutation id on callCloudCode mutation

* Client mutation id on signUp mutation

* Client mutation id on logIn mutation

* Client mutation id on logOut mutation

* Client mutation id on createClass mutation

* Client mutation id on updateClass mutation

* Client mutation id on deleteClass mutation

* Client mutation id on create object mutation

* Improve Viewer type

* Client mutation id on update object mutation

* Client mutation id on delete object mutation

* Introducing connections

* Fix tests

* Add pagination test

* Fix file location

* Fix postgres tests

* Add comments

* Tests to calculateSkipAndLimit
2019-12-01 21:43:08 -08:00

233 lines
6.3 KiB
JavaScript

import Parse from 'parse/node';
import { fromGlobalId } from 'graphql-relay';
import * as defaultGraphQLTypes from '../loaders/defaultGraphQLTypes';
import * as objectsMutations from '../helpers/objectsMutations';
const transformTypes = async (
inputType: 'create' | 'update',
fields,
{ className, parseGraphQLSchema, req }
) => {
const {
classGraphQLCreateType,
classGraphQLUpdateType,
config: { isCreateEnabled, isUpdateEnabled },
} = parseGraphQLSchema.parseClassTypes[className];
const parseClass = parseGraphQLSchema.parseClasses.find(
clazz => clazz.className === className
);
if (fields) {
const classGraphQLCreateTypeFields =
isCreateEnabled && classGraphQLCreateType
? classGraphQLCreateType.getFields()
: null;
const classGraphQLUpdateTypeFields =
isUpdateEnabled && classGraphQLUpdateType
? classGraphQLUpdateType.getFields()
: null;
const promises = Object.keys(fields).map(async field => {
let inputTypeField;
if (inputType === 'create' && classGraphQLCreateTypeFields) {
inputTypeField = classGraphQLCreateTypeFields[field];
} else if (classGraphQLUpdateTypeFields) {
inputTypeField = classGraphQLUpdateTypeFields[field];
}
if (inputTypeField) {
switch (true) {
case inputTypeField.type === defaultGraphQLTypes.GEO_POINT_INPUT:
fields[field] = transformers.geoPoint(fields[field]);
break;
case inputTypeField.type === defaultGraphQLTypes.POLYGON_INPUT:
fields[field] = transformers.polygon(fields[field]);
break;
case parseClass.fields[field].type === 'Relation':
fields[field] = await transformers.relation(
parseClass.fields[field].targetClass,
field,
fields[field],
parseGraphQLSchema,
req
);
break;
case parseClass.fields[field].type === 'Pointer':
fields[field] = await transformers.pointer(
parseClass.fields[field].targetClass,
field,
fields[field],
parseGraphQLSchema,
req
);
break;
}
}
});
await Promise.all(promises);
if (fields.ACL) fields.ACL = transformers.ACL(fields.ACL);
}
return fields;
};
const transformers = {
polygon: value => ({
__type: 'Polygon',
coordinates: value.map(geoPoint => [geoPoint.latitude, geoPoint.longitude]),
}),
geoPoint: value => ({
...value,
__type: 'GeoPoint',
}),
ACL: value => {
const parseACL = {};
if (value.public) {
parseACL['*'] = {
read: value.public.read,
write: value.public.write,
};
}
if (value.users) {
value.users.forEach(rule => {
parseACL[rule.userId] = {
read: rule.read,
write: rule.write,
};
});
}
if (value.roles) {
value.roles.forEach(rule => {
parseACL[`role:${rule.roleName}`] = {
read: rule.read,
write: rule.write,
};
});
}
return parseACL;
},
relation: async (
targetClass,
field,
value,
parseGraphQLSchema,
{ config, auth, info }
) => {
if (Object.keys(value) === 0)
throw new Parse.Error(
Parse.Error.INVALID_POINTER,
`You need to provide at least one operation on the relation mutation of field ${field}`
);
const op = {
__op: 'Batch',
ops: [],
};
let nestedObjectsToAdd = [];
if (value.createAndAdd) {
nestedObjectsToAdd = (await Promise.all(
value.createAndAdd.map(async input => {
const parseFields = await transformTypes('create', input, {
className: targetClass,
parseGraphQLSchema,
req: { config, auth, info },
});
return objectsMutations.createObject(
targetClass,
parseFields,
config,
auth,
info
);
})
)).map(object => ({
__type: 'Pointer',
className: targetClass,
objectId: object.objectId,
}));
}
if (value.add || nestedObjectsToAdd.length > 0) {
if (!value.add) value.add = [];
value.add = value.add.map(input => {
const globalIdObject = fromGlobalId(input);
if (globalIdObject.type === targetClass) {
input = globalIdObject.id;
}
return {
__type: 'Pointer',
className: targetClass,
objectId: input,
};
});
op.ops.push({
__op: 'AddRelation',
objects: [...value.add, ...nestedObjectsToAdd],
});
}
if (value.remove) {
op.ops.push({
__op: 'RemoveRelation',
objects: value.remove.map(input => {
const globalIdObject = fromGlobalId(input);
if (globalIdObject.type === targetClass) {
input = globalIdObject.id;
}
return {
__type: 'Pointer',
className: targetClass,
objectId: input,
};
}),
});
}
return op;
},
pointer: async (
targetClass,
field,
value,
parseGraphQLSchema,
{ config, auth, info }
) => {
if (Object.keys(value) > 1 || Object.keys(value) === 0)
throw new Parse.Error(
Parse.Error.INVALID_POINTER,
`You need to provide link OR createLink on the pointer mutation of field ${field}`
);
let nestedObjectToAdd;
if (value.createAndLink) {
const parseFields = await transformTypes('create', value.createAndLink, {
className: targetClass,
parseGraphQLSchema,
req: { config, auth, info },
});
nestedObjectToAdd = await objectsMutations.createObject(
targetClass,
parseFields,
config,
auth,
info
);
return {
__type: 'Pointer',
className: targetClass,
objectId: nestedObjectToAdd.objectId,
};
}
if (value.link) {
let objectId = value.link;
const globalIdObject = fromGlobalId(objectId);
if (globalIdObject.type === targetClass) {
objectId = globalIdObject.id;
}
return {
__type: 'Pointer',
className: targetClass,
objectId,
};
}
},
};
export { transformTypes };