Skip to content

Commit

Permalink
fix: Required option not handled correctly for special fields (File…
Browse files Browse the repository at this point in the history
…, GeoPoint, Polygon) on GraphQL API mutations (#8915)
  • Loading branch information
Moumouls authored Mar 20, 2024
1 parent 6fb19bd commit 907ad42
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 10 deletions.
2 changes: 1 addition & 1 deletion spec/AuthenticationAdaptersV2.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ describe('Auth Adapter features', () => {
allowExpiredAuthDataToken: false,
});
logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => { });
spyOn(logger, 'error').and.callFake(() => {});
user = new Parse.User();
await user.save({ authData: { modernAdapter: { id: 'modernAdapter' } } });
const user2 = new Parse.User();
Expand Down
65 changes: 65 additions & 0 deletions spec/ParseGraphQLServer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9548,6 +9548,71 @@ describe('ParseGraphQLServer', () => {
}
});

it('should support files on required file', async () => {
try {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
});
const schemaController = await parseServer.config.databaseController.loadSchema();
await schemaController.addClassIfNotExists('SomeClassWithRequiredFile', {
someField: { type: 'File', required: true },
});
await resetGraphQLCache();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();

const body = new FormData();
body.append(
'operations',
JSON.stringify({
query: `
mutation CreateSomeObject(
$fields: CreateSomeClassWithRequiredFileFieldsInput
) {
createSomeClassWithRequiredFile(
input: { fields: $fields }
) {
someClassWithRequiredFile {
id
someField {
name
url
}
}
}
}
`,
variables: {
fields: {
someField: { upload: null },
},
},
})
);
body.append('map', JSON.stringify({ 1: ['variables.fields.someField.upload'] }));
body.append('1', 'My File Content', {
filename: 'myFileName.txt',
contentType: 'text/plain',
});

const res = await fetch('http://localhost:13377/graphql', {
method: 'POST',
headers,
body,
});
expect(res.status).toEqual(200);
const resText = await res.text();
const result = JSON.parse(resText);
expect(
result.data.createSomeClassWithRequiredFile.someClassWithRequiredFile.someField.name
).toEqual(jasmine.stringMatching(/_myFileName.txt$/));
expect(
result.data.createSomeClassWithRequiredFile.someClassWithRequiredFile.someField.url
).toEqual(jasmine.stringMatching(/_myFileName.txt$/));
} catch (e) {
handleError(e);
}
});

it('should support file upload for on fly creation through pointer and relation', async () => {
parseServer = await global.reconfigureServer({
publicServerURL: 'http://localhost:13377/parse',
Expand Down
18 changes: 9 additions & 9 deletions src/GraphQL/transformers/mutation.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Parse from 'parse/node';
import { fromGlobalId } from 'graphql-relay';
import { handleUpload } from '../loaders/filesMutations';
import * as defaultGraphQLTypes from '../loaders/defaultGraphQLTypes';
import * as objectsMutations from '../helpers/objectsMutations';

const transformTypes = async (
Expand All @@ -28,27 +27,28 @@ const transformTypes = async (
inputTypeField = classGraphQLUpdateTypeFields[field];
}
if (inputTypeField) {
switch (true) {
case inputTypeField.type === defaultGraphQLTypes.GEO_POINT_INPUT:
const parseFieldType = parseClass.fields[field].type;
switch (parseFieldType) {
case 'GeoPoint':
if (fields[field] === null) {
fields[field] = { __op: 'Delete' };
break;
}
fields[field] = transformers.geoPoint(fields[field]);
break;
case inputTypeField.type === defaultGraphQLTypes.POLYGON_INPUT:
case 'Polygon':
if (fields[field] === null) {
fields[field] = { __op: 'Delete' };
break;
}
fields[field] = transformers.polygon(fields[field]);
break;
case inputTypeField.type === defaultGraphQLTypes.FILE_INPUT:
// Use `originalFields` to handle file upload since fields are a deepcopy and do not
// keep the file object
case 'File':
// We need to use the originalFields to handle the file upload
// since fields are a deepcopy and do not keep the file object
fields[field] = await transformers.file(originalFields[field], req);
break;
case parseClass.fields[field].type === 'Relation':
case 'Relation':
fields[field] = await transformers.relation(
parseClass.fields[field].targetClass,
field,
Expand All @@ -58,7 +58,7 @@ const transformTypes = async (
req
);
break;
case parseClass.fields[field].type === 'Pointer':
case 'Pointer':
if (fields[field] === null) {
fields[field] = { __op: 'Delete' };
break;
Expand Down

0 comments on commit 907ad42

Please sign in to comment.