Skip to content

Commit 907ad42

Browse files
authored
fix: Required option not handled correctly for special fields (File, GeoPoint, Polygon) on GraphQL API mutations (#8915)
1 parent 6fb19bd commit 907ad42

File tree

3 files changed

+75
-10
lines changed

3 files changed

+75
-10
lines changed

Diff for: spec/AuthenticationAdaptersV2.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ describe('Auth Adapter features', () => {
964964
allowExpiredAuthDataToken: false,
965965
});
966966
logger = require('../lib/logger').logger;
967-
spyOn(logger, 'error').and.callFake(() => { });
967+
spyOn(logger, 'error').and.callFake(() => {});
968968
user = new Parse.User();
969969
await user.save({ authData: { modernAdapter: { id: 'modernAdapter' } } });
970970
const user2 = new Parse.User();

Diff for: spec/ParseGraphQLServer.spec.js

+65
Original file line numberDiff line numberDiff line change
@@ -9548,6 +9548,71 @@ describe('ParseGraphQLServer', () => {
95489548
}
95499549
});
95509550

9551+
it('should support files on required file', async () => {
9552+
try {
9553+
parseServer = await global.reconfigureServer({
9554+
publicServerURL: 'http://localhost:13377/parse',
9555+
});
9556+
const schemaController = await parseServer.config.databaseController.loadSchema();
9557+
await schemaController.addClassIfNotExists('SomeClassWithRequiredFile', {
9558+
someField: { type: 'File', required: true },
9559+
});
9560+
await resetGraphQLCache();
9561+
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
9562+
9563+
const body = new FormData();
9564+
body.append(
9565+
'operations',
9566+
JSON.stringify({
9567+
query: `
9568+
mutation CreateSomeObject(
9569+
$fields: CreateSomeClassWithRequiredFileFieldsInput
9570+
) {
9571+
createSomeClassWithRequiredFile(
9572+
input: { fields: $fields }
9573+
) {
9574+
someClassWithRequiredFile {
9575+
id
9576+
someField {
9577+
name
9578+
url
9579+
}
9580+
}
9581+
}
9582+
}
9583+
`,
9584+
variables: {
9585+
fields: {
9586+
someField: { upload: null },
9587+
},
9588+
},
9589+
})
9590+
);
9591+
body.append('map', JSON.stringify({ 1: ['variables.fields.someField.upload'] }));
9592+
body.append('1', 'My File Content', {
9593+
filename: 'myFileName.txt',
9594+
contentType: 'text/plain',
9595+
});
9596+
9597+
const res = await fetch('http://localhost:13377/graphql', {
9598+
method: 'POST',
9599+
headers,
9600+
body,
9601+
});
9602+
expect(res.status).toEqual(200);
9603+
const resText = await res.text();
9604+
const result = JSON.parse(resText);
9605+
expect(
9606+
result.data.createSomeClassWithRequiredFile.someClassWithRequiredFile.someField.name
9607+
).toEqual(jasmine.stringMatching(/_myFileName.txt$/));
9608+
expect(
9609+
result.data.createSomeClassWithRequiredFile.someClassWithRequiredFile.someField.url
9610+
).toEqual(jasmine.stringMatching(/_myFileName.txt$/));
9611+
} catch (e) {
9612+
handleError(e);
9613+
}
9614+
});
9615+
95519616
it('should support file upload for on fly creation through pointer and relation', async () => {
95529617
parseServer = await global.reconfigureServer({
95539618
publicServerURL: 'http://localhost:13377/parse',

Diff for: src/GraphQL/transformers/mutation.js

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import Parse from 'parse/node';
22
import { fromGlobalId } from 'graphql-relay';
33
import { handleUpload } from '../loaders/filesMutations';
4-
import * as defaultGraphQLTypes from '../loaders/defaultGraphQLTypes';
54
import * as objectsMutations from '../helpers/objectsMutations';
65

76
const transformTypes = async (
@@ -28,27 +27,28 @@ const transformTypes = async (
2827
inputTypeField = classGraphQLUpdateTypeFields[field];
2928
}
3029
if (inputTypeField) {
31-
switch (true) {
32-
case inputTypeField.type === defaultGraphQLTypes.GEO_POINT_INPUT:
30+
const parseFieldType = parseClass.fields[field].type;
31+
switch (parseFieldType) {
32+
case 'GeoPoint':
3333
if (fields[field] === null) {
3434
fields[field] = { __op: 'Delete' };
3535
break;
3636
}
3737
fields[field] = transformers.geoPoint(fields[field]);
3838
break;
39-
case inputTypeField.type === defaultGraphQLTypes.POLYGON_INPUT:
39+
case 'Polygon':
4040
if (fields[field] === null) {
4141
fields[field] = { __op: 'Delete' };
4242
break;
4343
}
4444
fields[field] = transformers.polygon(fields[field]);
4545
break;
46-
case inputTypeField.type === defaultGraphQLTypes.FILE_INPUT:
47-
// Use `originalFields` to handle file upload since fields are a deepcopy and do not
48-
// keep the file object
46+
case 'File':
47+
// We need to use the originalFields to handle the file upload
48+
// since fields are a deepcopy and do not keep the file object
4949
fields[field] = await transformers.file(originalFields[field], req);
5050
break;
51-
case parseClass.fields[field].type === 'Relation':
51+
case 'Relation':
5252
fields[field] = await transformers.relation(
5353
parseClass.fields[field].targetClass,
5454
field,
@@ -58,7 +58,7 @@ const transformTypes = async (
5858
req
5959
);
6060
break;
61-
case parseClass.fields[field].type === 'Pointer':
61+
case 'Pointer':
6262
if (fields[field] === null) {
6363
fields[field] = { __op: 'Delete' };
6464
break;

0 commit comments

Comments
 (0)