Skip to content

Commit 10187de

Browse files
committed
Add types to simplifyParsedResolveInfoFragmentWithType and fix bug in field merging
1 parent 603bf8f commit 10187de

File tree

1 file changed

+53
-7
lines changed
  • packages/graphql-parse-resolve-info/src

1 file changed

+53
-7
lines changed

packages/graphql-parse-resolve-info/src/index.ts

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import * as debugFactory from "debug";
2323
type mixed = Record<string, any> | string | number | boolean | undefined | null;
2424

2525
export interface FieldsByTypeName {
26-
[str: string]: {
27-
[str: string]: ResolveTree;
26+
[typeName: string]: {
27+
[responseName: string]: ResolveTree;
2828
};
2929
}
3030

@@ -350,17 +350,32 @@ function getType(
350350
export function simplifyParsedResolveInfoFragmentWithType(
351351
parsedResolveInfoFragment: ResolveTree,
352352
type: GraphQLType
353-
) {
353+
): ResolveTree & { fields: { [responseName: string]: ResolveTree } } {
354354
const { fieldsByTypeName } = parsedResolveInfoFragment;
355-
const fields = {};
355+
const fields: { [responseName: string]: ResolveTree } = Object.create(null);
356356
const strippedType = getNamedType(type);
357357
if (isCompositeType(strippedType)) {
358-
Object.assign(fields, fieldsByTypeName[strippedType.name]);
358+
if (fieldsByTypeName[strippedType.name]) {
359+
Object.assign(fields, fieldsByTypeName[strippedType.name]);
360+
}
359361
if (strippedType instanceof GraphQLObjectType) {
360362
const objectType: GraphQLObjectType = strippedType;
361-
// GraphQL ensures that the subfields cannot clash, so it's safe to simply overwrite them
363+
// GraphQL ensures that the subfields cannot clash, so it's safe to
364+
// simply merge them.
362365
for (const anInterface of objectType.getInterfaces()) {
363-
Object.assign(fields, fieldsByTypeName[anInterface.name]);
366+
const interfaceFields = fieldsByTypeName[anInterface.name];
367+
if (!interfaceFields) continue;
368+
for (const responseName of Object.keys(interfaceFields)) {
369+
const interfaceField = interfaceFields[responseName];
370+
if (fields[responseName]) {
371+
fields[responseName] = recursiveMerge(
372+
fields[responseName],
373+
interfaceField
374+
);
375+
} else {
376+
fields[responseName] = interfaceField;
377+
}
378+
}
364379
}
365380
}
366381
}
@@ -370,6 +385,37 @@ export function simplifyParsedResolveInfoFragmentWithType(
370385
};
371386
}
372387

388+
function recursiveMerge(treeA: ResolveTree, treeB: ResolveTree): ResolveTree {
389+
const result: ResolveTree = {
390+
// GraphQL ensures that the subfields cannot clash, so the name, alias and
391+
// args will definitely line up, and the fieldsByTypeName can be merged.
392+
...treeA,
393+
fieldsByTypeName: Object.create(null),
394+
};
395+
396+
for (const tree of [treeA, treeB]) {
397+
for (const typeName of Object.keys(tree.fieldsByTypeName)) {
398+
if (!result.fieldsByTypeName[typeName]) {
399+
result.fieldsByTypeName[typeName] = Object.create(null);
400+
}
401+
const targetFields = result.fieldsByTypeName[typeName];
402+
const sourceFields = tree.fieldsByTypeName[typeName];
403+
for (const responseName of Object.keys(sourceFields)) {
404+
if (!targetFields[responseName]) {
405+
targetFields[responseName] = sourceFields[responseName];
406+
} else {
407+
targetFields[responseName] = recursiveMerge(
408+
targetFields[responseName],
409+
sourceFields[typeName]
410+
);
411+
}
412+
}
413+
}
414+
}
415+
416+
return result;
417+
}
418+
373419
export const parse = parseResolveInfo;
374420
export const simplify = simplifyParsedResolveInfoFragmentWithType;
375421
export const getAlias = getAliasFromResolveInfo;

0 commit comments

Comments
 (0)