Skip to content

Commit 4d1bd93

Browse files
authored
Allow to unset file from graphql (#6651)
1 parent d279198 commit 4d1bd93

File tree

3 files changed

+85
-50
lines changed

3 files changed

+85
-50
lines changed

spec/ParseGraphQLServer.spec.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9522,6 +9522,29 @@ describe('ParseGraphQLServer', () => {
95229522

95239523
expect(res.status).toEqual(200);
95249524
expect(await res.text()).toEqual('My File Content');
9525+
9526+
const mutationResult = await apolloClient.mutate({
9527+
mutation: gql`
9528+
mutation UnlinkFile($id: ID!) {
9529+
updateSomeClass(
9530+
input: { id: $id, fields: { someField: { file: null } } }
9531+
) {
9532+
someClass {
9533+
someField {
9534+
name
9535+
url
9536+
}
9537+
}
9538+
}
9539+
}
9540+
`,
9541+
variables: {
9542+
id: result2.data.createSomeClass3.someClass.id,
9543+
},
9544+
});
9545+
expect(
9546+
mutationResult.data.updateSomeClass.someClass.someField
9547+
).toEqual(null);
95259548
} catch (e) {
95269549
handleError(e);
95279550
}

src/GraphQL/loaders/defaultGraphQLTypes.js

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ class TypeValidationError extends Error {
2323
}
2424
}
2525

26-
const parseStringValue = value => {
26+
const parseStringValue = (value) => {
2727
if (typeof value === 'string') {
2828
return value;
2929
}
3030

3131
throw new TypeValidationError(value, 'String');
3232
};
3333

34-
const parseIntValue = value => {
34+
const parseIntValue = (value) => {
3535
if (typeof value === 'string') {
3636
const int = Number(value);
3737
if (Number.isInteger(int)) {
@@ -42,7 +42,7 @@ const parseIntValue = value => {
4242
throw new TypeValidationError(value, 'Int');
4343
};
4444

45-
const parseFloatValue = value => {
45+
const parseFloatValue = (value) => {
4646
if (typeof value === 'string') {
4747
const float = Number(value);
4848
if (!isNaN(float)) {
@@ -53,15 +53,15 @@ const parseFloatValue = value => {
5353
throw new TypeValidationError(value, 'Float');
5454
};
5555

56-
const parseBooleanValue = value => {
56+
const parseBooleanValue = (value) => {
5757
if (typeof value === 'boolean') {
5858
return value;
5959
}
6060

6161
throw new TypeValidationError(value, 'Boolean');
6262
};
6363

64-
const parseValue = value => {
64+
const parseValue = (value) => {
6565
switch (value.kind) {
6666
case Kind.STRING:
6767
return parseStringValue(value.value);
@@ -86,15 +86,15 @@ const parseValue = value => {
8686
}
8787
};
8888

89-
const parseListValues = values => {
89+
const parseListValues = (values) => {
9090
if (Array.isArray(values)) {
91-
return values.map(value => parseValue(value));
91+
return values.map((value) => parseValue(value));
9292
}
9393

9494
throw new TypeValidationError(values, 'List');
9595
};
9696

97-
const parseObjectFields = fields => {
97+
const parseObjectFields = (fields) => {
9898
if (Array.isArray(fields)) {
9999
return fields.reduce(
100100
(object, field) => ({
@@ -112,9 +112,9 @@ const ANY = new GraphQLScalarType({
112112
name: 'Any',
113113
description:
114114
'The Any scalar type is used in operations and types that involve any type of value.',
115-
parseValue: value => value,
116-
serialize: value => value,
117-
parseLiteral: ast => parseValue(ast),
115+
parseValue: (value) => value,
116+
serialize: (value) => value,
117+
parseLiteral: (ast) => parseValue(ast),
118118
});
119119

120120
const OBJECT = new GraphQLScalarType({
@@ -144,7 +144,7 @@ const OBJECT = new GraphQLScalarType({
144144
},
145145
});
146146

147-
const parseDateIsoValue = value => {
147+
const parseDateIsoValue = (value) => {
148148
if (typeof value === 'string') {
149149
const date = new Date(value);
150150
if (!isNaN(date)) {
@@ -157,7 +157,7 @@ const parseDateIsoValue = value => {
157157
throw new TypeValidationError(value, 'Date');
158158
};
159159

160-
const serializeDateIso = value => {
160+
const serializeDateIso = (value) => {
161161
if (typeof value === 'string') {
162162
return value;
163163
}
@@ -168,7 +168,7 @@ const serializeDateIso = value => {
168168
throw new TypeValidationError(value, 'Date');
169169
};
170170

171-
const parseDateIsoLiteral = ast => {
171+
const parseDateIsoLiteral = (ast) => {
172172
if (ast.kind === Kind.STRING) {
173173
return parseDateIsoValue(ast.value);
174174
}
@@ -219,8 +219,8 @@ const DATE = new GraphQLScalarType({
219219
iso: parseDateIsoLiteral(ast),
220220
};
221221
} else if (ast.kind === Kind.OBJECT) {
222-
const __type = ast.fields.find(field => field.name.value === '__type');
223-
const iso = ast.fields.find(field => field.name.value === 'iso');
222+
const __type = ast.fields.find((field) => field.name.value === '__type');
223+
const iso = ast.fields.find((field) => field.name.value === 'iso');
224224
if (__type && __type.value && __type.value.value === 'Date' && iso) {
225225
return {
226226
__type: __type.value.value,
@@ -273,8 +273,8 @@ const BYTES = new GraphQLScalarType({
273273
base64: ast.value,
274274
};
275275
} else if (ast.kind === Kind.OBJECT) {
276-
const __type = ast.fields.find(field => field.name.value === '__type');
277-
const base64 = ast.fields.find(field => field.name.value === 'base64');
276+
const __type = ast.fields.find((field) => field.name.value === '__type');
277+
const base64 = ast.fields.find((field) => field.name.value === 'base64');
278278
if (
279279
__type &&
280280
__type.value &&
@@ -294,7 +294,7 @@ const BYTES = new GraphQLScalarType({
294294
},
295295
});
296296

297-
const parseFileValue = value => {
297+
const parseFileValue = (value) => {
298298
if (typeof value === 'string') {
299299
return {
300300
__type: 'File',
@@ -317,7 +317,7 @@ const FILE = new GraphQLScalarType({
317317
description:
318318
'The File scalar type is used in operations and types that involve files.',
319319
parseValue: parseFileValue,
320-
serialize: value => {
320+
serialize: (value) => {
321321
if (typeof value === 'string') {
322322
return value;
323323
} else if (
@@ -335,9 +335,9 @@ const FILE = new GraphQLScalarType({
335335
if (ast.kind === Kind.STRING) {
336336
return parseFileValue(ast.value);
337337
} else if (ast.kind === Kind.OBJECT) {
338-
const __type = ast.fields.find(field => field.name.value === '__type');
339-
const name = ast.fields.find(field => field.name.value === 'name');
340-
const url = ast.fields.find(field => field.name.value === 'url');
338+
const __type = ast.fields.find((field) => field.name.value === '__type');
339+
const name = ast.fields.find((field) => field.name.value === 'name');
340+
const url = ast.fields.find((field) => field.name.value === 'url');
341341
if (__type && __type.value && name && name.value) {
342342
return parseFileValue({
343343
__type: __type.value.value,
@@ -371,13 +371,19 @@ const FILE_INPUT = new GraphQLInputObjectType({
371371
name: 'FileInput',
372372
fields: {
373373
file: {
374-
description: 'A File Scalar can be an url or a FileInfo object.',
374+
description:
375+
'A File Scalar can be an url or a FileInfo object. If this field is set to null the file will be unlinked.',
375376
type: FILE,
376377
},
377378
upload: {
378379
description: 'Use this field if you want to create a new file.',
379380
type: GraphQLUpload,
380381
},
382+
unlink: {
383+
description:
384+
'Use this field if you want to unlink the file (the file will not be deleted on cloud storage)',
385+
type: GraphQLBoolean,
386+
},
381387
},
382388
});
383389

@@ -551,7 +557,7 @@ const ACL = new GraphQLObjectType({
551557
type: new GraphQLList(new GraphQLNonNull(USER_ACL)),
552558
resolve(p) {
553559
const users = [];
554-
Object.keys(p).forEach(rule => {
560+
Object.keys(p).forEach((rule) => {
555561
if (rule !== '*' && rule.indexOf('role:') !== 0) {
556562
users.push({
557563
userId: toGlobalId('_User', rule),
@@ -568,7 +574,7 @@ const ACL = new GraphQLObjectType({
568574
type: new GraphQLList(new GraphQLNonNull(ROLE_ACL)),
569575
resolve(p) {
570576
const roles = [];
571-
Object.keys(p).forEach(rule => {
577+
Object.keys(p).forEach((rule) => {
572578
if (rule.indexOf('role:') === 0) {
573579
roles.push({
574580
roleName: rule.replace('role:', ''),
@@ -839,49 +845,49 @@ const GEO_INTERSECTS_INPUT = new GraphQLInputObjectType({
839845
},
840846
});
841847

842-
const equalTo = type => ({
848+
const equalTo = (type) => ({
843849
description:
844850
'This is the equalTo operator to specify a constraint to select the objects where the value of a field equals to a specified value.',
845851
type,
846852
});
847853

848-
const notEqualTo = type => ({
854+
const notEqualTo = (type) => ({
849855
description:
850856
'This is the notEqualTo operator to specify a constraint to select the objects where the value of a field do not equal to a specified value.',
851857
type,
852858
});
853859

854-
const lessThan = type => ({
860+
const lessThan = (type) => ({
855861
description:
856862
'This is the lessThan operator to specify a constraint to select the objects where the value of a field is less than a specified value.',
857863
type,
858864
});
859865

860-
const lessThanOrEqualTo = type => ({
866+
const lessThanOrEqualTo = (type) => ({
861867
description:
862868
'This is the lessThanOrEqualTo operator to specify a constraint to select the objects where the value of a field is less than or equal to a specified value.',
863869
type,
864870
});
865871

866-
const greaterThan = type => ({
872+
const greaterThan = (type) => ({
867873
description:
868874
'This is the greaterThan operator to specify a constraint to select the objects where the value of a field is greater than a specified value.',
869875
type,
870876
});
871877

872-
const greaterThanOrEqualTo = type => ({
878+
const greaterThanOrEqualTo = (type) => ({
873879
description:
874880
'This is the greaterThanOrEqualTo operator to specify a constraint to select the objects where the value of a field is greater than or equal to a specified value.',
875881
type,
876882
});
877883

878-
const inOp = type => ({
884+
const inOp = (type) => ({
879885
description:
880886
'This is the in operator to specify a constraint to select the objects where the value of a field equals any value in the specified array.',
881887
type: new GraphQLList(type),
882888
});
883889

884-
const notIn = type => ({
890+
const notIn = (type) => ({
885891
description:
886892
'This is the notIn operator to specify a constraint to select the objects where the value of a field do not equal any value in the specified array.',
887893
type: new GraphQLList(type),
@@ -1219,14 +1225,14 @@ let ARRAY_RESULT;
12191225

12201226
const loadArrayResult = (parseGraphQLSchema, parseClasses) => {
12211227
const classTypes = parseClasses
1222-
.filter(parseClass =>
1228+
.filter((parseClass) =>
12231229
parseGraphQLSchema.parseClassTypes[parseClass.className]
12241230
.classGraphQLOutputType
12251231
? true
12261232
: false
12271233
)
12281234
.map(
1229-
parseClass =>
1235+
(parseClass) =>
12301236
parseGraphQLSchema.parseClassTypes[parseClass.className]
12311237
.classGraphQLOutputType
12321238
);
@@ -1235,7 +1241,7 @@ const loadArrayResult = (parseGraphQLSchema, parseClasses) => {
12351241
description:
12361242
'Use Inline Fragment on Array to get results: https://graphql.org/learn/queries/#inline-fragments',
12371243
types: () => [ELEMENT, ...classTypes],
1238-
resolveType: value => {
1244+
resolveType: (value) => {
12391245
if (value.__type === 'Object' && value.className && value.objectId) {
12401246
if (parseGraphQLSchema.parseClassTypes[value.className]) {
12411247
return parseGraphQLSchema.parseClassTypes[value.className]
@@ -1251,7 +1257,7 @@ const loadArrayResult = (parseGraphQLSchema, parseClasses) => {
12511257
parseGraphQLSchema.graphQLTypes.push(ARRAY_RESULT);
12521258
};
12531259

1254-
const load = parseGraphQLSchema => {
1260+
const load = (parseGraphQLSchema) => {
12551261
parseGraphQLSchema.addGraphQLType(GraphQLUpload, true);
12561262
parseGraphQLSchema.addGraphQLType(ANY, true);
12571263
parseGraphQLSchema.addGraphQLType(OBJECT, true);

0 commit comments

Comments
 (0)