Skip to content

Commit 1788e53

Browse files
committed
Create Fulfilled Meta Field
1 parent 01414be commit 1788e53

File tree

7 files changed

+75
-6
lines changed

7 files changed

+75
-6
lines changed

src/__testUtils__/kitchenSinkQuery.ts

+5
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,9 @@ fragment frag on Friend @onFragmentDefinition {
6565
query {
6666
__typename
6767
}
68+
69+
query Fulfilled {
70+
__fulfilled
71+
a: __fulfilled(label: "a")
72+
}
6873
`;

src/execution/__tests__/union-interface-test.ts

+9
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,9 @@ describe('Execute: Union and intersection types', () => {
265265
name
266266
pets {
267267
__typename
268+
__fulfilled
268269
... on Dog {
270+
isDog: __fulfilled(label: "Dog")
269271
name
270272
barks
271273
}
@@ -284,11 +286,14 @@ describe('Execute: Union and intersection types', () => {
284286
pets: [
285287
{
286288
__typename: 'Cat',
289+
__fulfilled: true,
287290
name: 'Garfield',
288291
meows: false,
289292
},
290293
{
291294
__typename: 'Dog',
295+
__fulfilled: true,
296+
isDog: true,
292297
name: 'Odie',
293298
barks: true,
294299
},
@@ -341,6 +346,7 @@ describe('Execute: Union and intersection types', () => {
341346
}
342347
343348
... on Mammal {
349+
isMammal: __fulfilled(label: "Mammal")
344350
mother {
345351
__typename
346352
... on Dog {
@@ -364,11 +370,13 @@ describe('Execute: Union and intersection types', () => {
364370
friends: [
365371
{
366372
__typename: 'Person',
373+
isMammal: true,
367374
name: 'Liz',
368375
mother: null,
369376
},
370377
{
371378
__typename: 'Dog',
379+
isMammal: true,
372380
name: 'Odie',
373381
barks: true,
374382
mother: { __typename: 'Dog', name: "Odie's Mom", barks: true },
@@ -396,6 +404,7 @@ describe('Execute: Union and intersection types', () => {
396404
}
397405
398406
fragment CatMeows on Cat {
407+
catMeowsFulfilled: __fulfilled(label: "CatMeows")
399408
meows
400409
}
401410
`);

src/execution/execute.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import type {
3939
} from '../type/definition';
4040
import { assertValidSchema } from '../type/validate';
4141
import {
42+
FulfilledMetaFieldDef,
4243
SchemaMetaFieldDef,
4344
TypeMetaFieldDef,
4445
TypeNameMetaFieldDef,
@@ -1016,12 +1017,12 @@ export const defaultFieldResolver: GraphQLFieldResolver<unknown, unknown> =
10161017

10171018
/**
10181019
* This method looks up the field on the given type definition.
1019-
* It has special casing for the three introspection fields,
1020-
* __schema, __type and __typename. __typename is special because
1021-
* it can always be queried as a field, even in situations where no
1022-
* other fields are allowed, like on a Union. __schema and __type
1023-
* could get automatically added to the query type, but that would
1024-
* require mutating type definitions, which would cause issues.
1020+
* It has special casing for the four introspection fields,
1021+
* __schema, __type, __typename and __fulfilled. __typename and __fulfilled
1022+
* are special because they can always be queried as a field, even in
1023+
* situations where no other fields are allowed, like on a Union.
1024+
* __schema and __type could get automatically added to the query type,
1025+
* but that would require mutating type definitions, which would cause issues.
10251026
*
10261027
* @internal
10271028
*/
@@ -1044,6 +1045,8 @@ export function getFieldDef(
10441045
return TypeMetaFieldDef;
10451046
} else if (fieldName === TypeNameMetaFieldDef.name) {
10461047
return TypeNameMetaFieldDef;
1048+
} else if (fieldName === FulfilledMetaFieldDef.name) {
1049+
return FulfilledMetaFieldDef;
10471050
}
10481051
return parentType.getFields()[fieldName];
10491052
}

src/language/__tests__/printer-test.ts

+5
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ describe('Printer: Query document', () => {
237237
{
238238
__typename
239239
}
240+
241+
query Fulfilled {
242+
__fulfilled
243+
a: __fulfilled(label: "a")
244+
}
240245
`),
241246
);
242247
});

src/language/__tests__/visitor-test.ts

+22
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,28 @@ describe('Visitor', () => {
931931
['leave', 'Field', 0, undefined],
932932
['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
933933
['leave', 'OperationDefinition', 5, undefined],
934+
['enter', 'OperationDefinition', 6, undefined],
935+
['enter', 'Name', 'name', 'OperationDefinition'],
936+
['leave', 'Name', 'name', 'OperationDefinition'],
937+
['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
938+
['enter', 'Field', 0, undefined],
939+
['enter', 'Name', 'name', 'Field'],
940+
['leave', 'Name', 'name', 'Field'],
941+
['leave', 'Field', 0, undefined],
942+
['enter', 'Field', 1, undefined],
943+
['enter', 'Name', 'alias', 'Field'],
944+
['leave', 'Name', 'alias', 'Field'],
945+
['enter', 'Name', 'name', 'Field'],
946+
['leave', 'Name', 'name', 'Field'],
947+
['enter', 'Argument', 0, undefined],
948+
['enter', 'Name', 'name', 'Argument'],
949+
['leave', 'Name', 'name', 'Argument'],
950+
['enter', 'StringValue', 'value', 'Argument'],
951+
['leave', 'StringValue', 'value', 'Argument'],
952+
['leave', 'Argument', 0, undefined],
953+
['leave', 'Field', 1, undefined],
954+
['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
955+
['leave', 'OperationDefinition', 6, undefined],
934956
['leave', 'Document', undefined, undefined],
935957
]);
936958
});

src/type/introspection.ts

+21
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,27 @@ export const TypeNameMetaFieldDef: GraphQLField<unknown, unknown> = {
528528
astNode: undefined,
529529
};
530530

531+
export const FulfilledMetaFieldDef: GraphQLField<unknown, unknown> = {
532+
name: '__fulfilled',
533+
type: new GraphQLNonNull(GraphQLBoolean),
534+
description: 'If the current selection was included at runtime.',
535+
args: [
536+
{
537+
name: 'label',
538+
description: undefined,
539+
type: GraphQLString,
540+
defaultValue: undefined,
541+
deprecationReason: undefined,
542+
extensions: undefined,
543+
astNode: undefined,
544+
},
545+
],
546+
resolve: (_source, _args, _context, _info) => true,
547+
deprecationReason: undefined,
548+
extensions: undefined,
549+
astNode: undefined,
550+
};
551+
531552
export const introspectionTypes: ReadonlyArray<GraphQLNamedType> =
532553
Object.freeze([
533554
__Schema,

src/utilities/TypeInfo.ts

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
getNamedType,
3232
} from '../type/definition';
3333
import {
34+
FulfilledMetaFieldDef,
3435
SchemaMetaFieldDef,
3536
TypeMetaFieldDef,
3637
TypeNameMetaFieldDef,
@@ -327,6 +328,9 @@ function getFieldDef(
327328
if (name === TypeNameMetaFieldDef.name && isCompositeType(parentType)) {
328329
return TypeNameMetaFieldDef;
329330
}
331+
if (name === FulfilledMetaFieldDef.name && isCompositeType(parentType)) {
332+
return FulfilledMetaFieldDef;
333+
}
330334
if (isObjectType(parentType) || isInterfaceType(parentType)) {
331335
return parentType.getFields()[name];
332336
}

0 commit comments

Comments
 (0)