Skip to content
This repository has been archived by the owner on Apr 15, 2020. It is now read-only.

Commit

Permalink
fix(stitching): fixes error mapping with ExtendSchema transform. Also…
Browse files Browse the repository at this point in the history
…, refactors!

= uses createMergedResolver instead of individual wrapFields, extractFields, and renameFields functions. These functionss likely should be deprecated or at least renamed, as their function (creating specialized resolvers for merging) is not clear from current names. createMergedResolver works with multiple layers of wrapping, extracting, or even a combination thereof.

= exports new extractFields function for use within a fieldNodeTransformerMap when wrapping fields.

= allows specification of the fieldNodeTransformerMap directly on ExtendSchema transform so that separate MapFields transform not required. Under the hood, the ExtendSchema transform calls its own MapFields transform.

= fixes file structure; as most of the recent new functionality is stitching functionality rather than transform functionality, even though it relies on the new ExtendSchema and MapFields transforms.
  • Loading branch information
yaacovCR committed Aug 16, 2019
1 parent f0f880b commit 81959e1
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 100 deletions.
File renamed without changes.
64 changes: 64 additions & 0 deletions src/stitching/createMergedResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { IFieldResolver } from '../Interfaces';
import { defaultMergedResolver } from '../stitching';
import { GraphQLObjectType } from 'graphql';
import { extractOneLevelOfFields } from './extractFields';

export function wrapField(wrapper: string, fieldName: string): IFieldResolver<any, any> {
return createMergedResolver({ fromPath: [wrapper, fieldName] });
}

export function extractField(fieldName: string): IFieldResolver<any, any> {
return createMergedResolver({ toPath: [fieldName] });
}

export function renameField(fieldName: string): IFieldResolver<any, any> {
return createMergedResolver({ fromPath: [fieldName] });
}

export function createMergedResolver({
fromPath = [],
toPath = [],
}: {
toPath?: Array<string>;
fromPath?: Array<string>;
}): IFieldResolver<any, any> {
return (parent, args, context, info) => {

let fieldNodes = info.fieldNodes;
let returnType = info.returnType;
let parentType = info.parentType;
let path = info.path;

toPath.forEach(pathSegment => {
fieldNodes = extractOneLevelOfFields(fieldNodes, pathSegment, info.fragments);
parentType = returnType as GraphQLObjectType;
returnType = (returnType as GraphQLObjectType).getFields()[pathSegment].type;
path = { prev: path, key: pathSegment };
});

if (!fieldNodes.length) {
return null;
}

let fieldName;

const fromPathLength = fromPath.length;
if (fromPathLength) {
parent = fromPath.slice(0, -1).reduce((p, pathSegment) => p[pathSegment], parent);
fieldName = fromPath[fromPathLength - 1];
}

if (!fieldName) {
fieldName = toPath[toPath.length - 1];
}

return defaultMergedResolver(parent, args, context, {
...info,
fieldName,
fieldNodes,
returnType,
parentType,
path,
});
};
}
34 changes: 34 additions & 0 deletions src/stitching/extractFields.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { FieldNode, FragmentDefinitionNode } from 'graphql';
import { collectFields } from './collectFields';

export function extractFields({
fieldNode,
path = [],
fragments = {},
}: {
fieldNode: FieldNode;
path?: Array<string>;
fragments?: Record<string, FragmentDefinitionNode>;
}) {
const fieldNodes = collectFields(fieldNode.selectionSet, fragments);
return path.length ? path.reduce(
(acc, pathSegment) => extractOneLevelOfFields(acc, pathSegment, fragments),
fieldNodes,
) : fieldNodes;
}

export function extractOneLevelOfFields(
fieldNodes: ReadonlyArray<FieldNode>,
fieldName: string,
fragments: Record<string, FragmentDefinitionNode>,
) {
const newFieldNodes: Array<FieldNode> = [];
fieldNodes.forEach(fieldNode => {
collectFields(fieldNode.selectionSet, fragments).forEach(selection => {
if (selection.name.value === fieldName) {
newFieldNodes.push(selection);
}
});
});
return newFieldNodes;
}
18 changes: 16 additions & 2 deletions src/stitching/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,29 @@ import mergeSchemas from './mergeSchemas';
import delegateToSchema from './delegateToSchema';
import delegateToRemoteSchema from './delegateToRemoteSchema';
import defaultMergedResolver from './defaultMergedResolver';
import { wrapField, extractField, renameField, createMergedResolver } from './createMergedResolver';
import { extractFields } from './extractFields';
import { collectFields } from './collectFields';


export {
makeRemoteExecutableSchema,
introspectSchema,
mergeSchemas,
// Those are currently undocumented and not part of official API,

// These are currently undocumented and not part of official API,
// but exposed for the community use
delegateToSchema,
delegateToRemoteSchema,
defaultCreateRemoteResolver,
defaultMergedResolver,
defaultCreateRemoteResolver
createMergedResolver,
collectFields,
extractFields,

// TBD: deprecate in favor of createMergedResolver?
// OR: fix naming to clarify that these functions return resolvers?
wrapField,
extractField,
renameField,
};

0 comments on commit 81959e1

Please sign in to comment.