Skip to content

Commit b489677

Browse files
Add parentType to path to avoid path ambiguity (#2669)
Co-authored-by: Ivan Goncharov <[email protected]>
1 parent 2232ebd commit b489677

File tree

6 files changed

+76
-9
lines changed

6 files changed

+76
-9
lines changed

src/execution/__tests__/executor-test.js

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
GraphQLScalarType,
1818
GraphQLInterfaceType,
1919
GraphQLObjectType,
20+
GraphQLUnionType,
2021
} from '../../type/definition';
2122

2223
import { execute, executeSync } from '../execute';
@@ -306,11 +307,70 @@ describe('Execute: Handles basic execution tasks', () => {
306307
const field = operation.selectionSet.selections[0];
307308
expect(resolvedInfo).to.deep.include({
308309
fieldNodes: [field],
309-
path: { prev: undefined, key: 'result' },
310+
path: { prev: undefined, key: 'result', typename: 'Test' },
310311
variableValues: { var: 'abc' },
311312
});
312313
});
313314

315+
it('populates path correctly with complex types', () => {
316+
let path;
317+
const someObject = new GraphQLObjectType({
318+
name: 'SomeObject',
319+
fields: {
320+
test: {
321+
type: GraphQLString,
322+
resolve(_val, _args, _ctx, info) {
323+
path = info.path;
324+
},
325+
},
326+
},
327+
});
328+
const someUnion = new GraphQLUnionType({
329+
name: 'SomeUnion',
330+
types: [someObject],
331+
resolveType() {
332+
return 'SomeObject';
333+
},
334+
});
335+
const testType = new GraphQLObjectType({
336+
name: 'SomeQuery',
337+
fields: {
338+
test: {
339+
type: new GraphQLNonNull(
340+
new GraphQLList(new GraphQLNonNull(someUnion)),
341+
),
342+
},
343+
},
344+
});
345+
const schema = new GraphQLSchema({ query: testType });
346+
const rootValue = { test: [{}] };
347+
const document = parse(`
348+
query {
349+
l1: test {
350+
... on SomeObject {
351+
l2: test
352+
}
353+
}
354+
}
355+
`);
356+
357+
executeSync({ schema, document, rootValue });
358+
359+
expect(path).to.deep.equal({
360+
key: 'l2',
361+
typename: 'SomeObject',
362+
prev: {
363+
key: 0,
364+
typename: undefined,
365+
prev: {
366+
key: 'l1',
367+
typename: 'SomeQuery',
368+
prev: undefined,
369+
},
370+
},
371+
});
372+
});
373+
314374
it('threads root value context correctly', () => {
315375
let resolvedRootValue;
316376
const schema = new GraphQLSchema({

src/execution/execute.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ function executeFieldsSerially(
416416
Object.keys(fields),
417417
(results, responseName) => {
418418
const fieldNodes = fields[responseName];
419-
const fieldPath = addPath(path, responseName);
419+
const fieldPath = addPath(path, responseName, parentType.name);
420420
const result = resolveField(
421421
exeContext,
422422
parentType,
@@ -456,7 +456,7 @@ function executeFields(
456456

457457
for (const responseName of Object.keys(fields)) {
458458
const fieldNodes = fields[responseName];
459-
const fieldPath = addPath(path, responseName);
459+
const fieldPath = addPath(path, responseName, parentType.name);
460460
const result = resolveField(
461461
exeContext,
462462
parentType,
@@ -934,7 +934,7 @@ function completeListValue(
934934
const completedResults = arrayFrom(result, (item, index) => {
935935
// No need to modify the info object containing the path,
936936
// since from here on it is not ever accessed by resolver functions.
937-
const fieldPath = addPath(path, index);
937+
const fieldPath = addPath(path, index, undefined);
938938
const completedItem = completeValueCatchingError(
939939
exeContext,
940940
itemType,

src/jsutils/Path.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
export interface Path {
22
prev: Path | undefined;
33
key: string | number;
4+
typename: string | undefined;
45
}
56

67
/**
78
* Given a Path and a key, return a new Path containing the new key.
89
*/
9-
export function addPath(prev: Path | undefined, key: string | number): Path;
10+
export function addPath(
11+
prev: Path | undefined,
12+
key: string | number,
13+
typename: string | undefined,
14+
): Path;
1015

1116
/**
1217
* Given a Path, return an Array of the path keys.

src/jsutils/Path.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
export type Path = {|
44
+prev: Path | void,
55
+key: string | number,
6+
+typename: string | void,
67
|};
78

89
/**
@@ -11,8 +12,9 @@ export type Path = {|
1112
export function addPath(
1213
prev: $ReadOnly<Path> | void,
1314
key: string | number,
15+
typename: string | void,
1416
): Path {
15-
return { prev, key };
17+
return { prev, key, typename };
1618
}
1719

1820
/**

src/subscription/subscribe.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ export function createSourceEventStream(
253253
// AsyncIterable yielding raw payloads.
254254
const resolveFn = fieldDef.subscribe ?? exeContext.fieldResolver;
255255

256-
const path = addPath(undefined, responseName);
256+
const path = addPath(undefined, responseName, type.name);
257257

258258
const info = buildResolveInfo(exeContext, fieldDef, fieldNodes, type, path);
259259

src/utilities/coerceInputValue.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function coerceInputValueImpl(
8282
const itemType = type.ofType;
8383
if (isCollection(inputValue)) {
8484
return arrayFrom(inputValue, (itemValue, index) => {
85-
const itemPath = addPath(path, index);
85+
const itemPath = addPath(path, index, undefined);
8686
return coerceInputValueImpl(itemValue, itemType, onError, itemPath);
8787
});
8888
}
@@ -126,7 +126,7 @@ function coerceInputValueImpl(
126126
fieldValue,
127127
field.type,
128128
onError,
129-
addPath(path, field.name),
129+
addPath(path, field.name, type.name),
130130
);
131131
}
132132

0 commit comments

Comments
 (0)