Skip to content

Commit

Permalink
refactor(stitchSchemas): clean up
Browse files Browse the repository at this point in the history
= remove schemaLikeObjects in favor of better typed sources

= make sure to retrieve the transformedSubschema stored with the transformedSubschemaConfig
  • Loading branch information
yaacovCR committed Sep 26, 2020
1 parent 4b8b3b5 commit b795ba8
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 107 deletions.
17 changes: 10 additions & 7 deletions packages/delegate/src/delegateToSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ export function delegateRequest({

let allTransforms: Array<Transform>;

const stitchingInfo: StitchingInfo = info?.schema.extensions?.stitchingInfo;
if (isSubschemaConfig(subschemaOrSubschemaConfig)) {
const stitchingInfo: StitchingInfo = info?.schema.extensions?.stitchingInfo;
if (stitchingInfo) {
const processedSubschema = stitchingInfo.transformedSubschemaConfigs.get(subschemaOrSubschemaConfig);
subschemaConfig = processedSubschema != null ? processedSubschema : subschemaOrSubschemaConfig;
const transformedSubschemaConfig = stitchingInfo.transformedSubschemaConfigs.get(subschemaOrSubschemaConfig);
subschemaConfig = transformedSubschemaConfig || subschemaOrSubschemaConfig;
} else {
subschemaConfig = subschemaOrSubschemaConfig;
}
Expand All @@ -144,13 +144,17 @@ export function delegateRequest({
}
targetRootValue = rootValue ?? endpoint?.rootValue ?? info?.rootValue;
} else {
if (stitchingInfo) {
const transformedSubschemaConfig = stitchingInfo.transformedSubschemaConfigs.get(subschemaOrSubschemaConfig);
if (transformedSubschemaConfig) {
subschemaConfig = transformedSubschemaConfig;
}
}
targetSchema = subschemaOrSubschemaConfig;
targetRootValue = rootValue ?? info?.rootValue;
allTransforms = transforms;
}

const stitchingInfo: StitchingInfo = info?.schema.extensions?.stitchingInfo;

const delegationContext = {
subschema: subschemaOrSubschemaConfig,
targetSchema,
Expand All @@ -163,8 +167,7 @@ export function delegateRequest({
returnType ?? info?.returnType ?? getDelegationReturnType(targetSchema, targetOperation, targetFieldName),
transforms: allTransforms,
transformedSchema:
transformedSchema ??
(stitchingInfo ? stitchingInfo.transformedSchemas.get(subschemaOrSubschemaConfig) : targetSchema),
transformedSchema ?? (stitchingInfo ? stitchingInfo.transformedSchemas.get(subschemaConfig) : targetSchema),
skipTypeMerging,
};

Expand Down
4 changes: 2 additions & 2 deletions packages/delegate/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ export type MergedTypeResolver = (
) => any;

export interface StitchingInfo {
transformedSubschemaConfigs: Map<SubschemaConfig, SubschemaConfig>;
transformedSchemas: Map<GraphQLSchema | SubschemaConfig, GraphQLSchema>;
transformedSubschemaConfigs: Map<GraphQLSchema | SubschemaConfig, SubschemaConfig>;
transformedSchemas: Map<SubschemaConfig, GraphQLSchema>;
fragmentsByField: Record<string, Record<string, InlineFragmentNode>>;
selectionSetsByField: Record<string, Record<string, SelectionSetNode>>;
dynamicSelectionSetsByField: Record<string, Record<string, Array<(node: FieldNode) => SelectionSetNode>>>;
Expand Down
23 changes: 8 additions & 15 deletions packages/stitch/src/stitchSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
specifiedDirectives,
extendSchema,
ASTNode,
GraphQLNamedType,
} from 'graphql';

import { SchemaDirectiveVisitor, mergeDeep, IResolvers, rewireTypes, pruneSchema } from '@graphql-tools/utils';
Expand All @@ -18,7 +17,6 @@ import {
addCatchUndefinedToSchema,
assertResolversPresent,
attachDirectiveResolvers,
buildDocumentFromTypeDefinitions,
extendResolversFromInterfaces,
} from '@graphql-tools/schema';

Expand Down Expand Up @@ -53,18 +51,18 @@ export function stitchSchemas({
throw new Error('Expected `resolverValidationOptions` to be an object');
}

let schemaLikeObjects: Array<GraphQLSchema | SubschemaConfig | DocumentNode | GraphQLNamedType> = [];
let subschemaConfigs: Array<SubschemaConfig> = [];
const transformedSubschemaConfigs: Map<SubschemaConfig, SubschemaConfig> = new Map();

subschemas.forEach(subschemaOrSubschemaArray => {
if (Array.isArray(subschemaOrSubschemaArray)) {
subschemaOrSubschemaArray.forEach(s => {
schemaLikeObjects = schemaLikeObjects.concat(
subschemaConfigs = subschemaConfigs.concat(
applySubschemaConfigTransforms(subschemaConfigTransforms, s, transformedSubschemaConfigs)
);
});
} else {
schemaLikeObjects = schemaLikeObjects.concat(
subschemaConfigs = subschemaConfigs.concat(
applySubschemaConfigTransforms(
subschemaConfigTransforms,
subschemaOrSubschemaArray,
Expand All @@ -74,15 +72,7 @@ export function stitchSchemas({
}
});

if ((typeDefs && !Array.isArray(typeDefs)) || (Array.isArray(typeDefs) && typeDefs.length)) {
schemaLikeObjects.push(buildDocumentFromTypeDefinitions(typeDefs, parseOptions));
}

if (types != null) {
schemaLikeObjects = schemaLikeObjects.concat(types);
}

const transformedSchemas: Map<GraphQLSchema | SubschemaConfig, GraphQLSchema> = new Map();
const transformedSchemas: Map<SubschemaConfig, GraphQLSchema> = new Map();
const extensions: Array<DocumentNode> = [];
const directives: Array<GraphQLDirective> = [];
const directiveMap: Record<string, GraphQLDirective> = specifiedDirectives.reduce((acc, directive) => {
Expand All @@ -97,7 +87,10 @@ export function stitchSchemas({
};

const typeCandidates = buildTypeCandidates({
schemaLikeObjects,
subschemaConfigs,
types,
typeDefs,
parseOptions,
transformedSchemas,
extensions,
directiveMap,
Expand Down
2 changes: 1 addition & 1 deletion packages/stitch/src/stitchingInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { MergeTypeCandidate, MergedTypeInfo, StitchingInfo, MergeTypeFilter } fr

export function createStitchingInfo(
transformedSubschemaConfigs: Map<SubschemaConfig, SubschemaConfig>,
transformedSchemas: Map<GraphQLSchema | SubschemaConfig, GraphQLSchema>,
transformedSchemas: Map<SubschemaConfig, GraphQLSchema>,
typeCandidates: Record<string, Array<MergeTypeCandidate>>,
mergeTypes?: boolean | Array<string> | MergeTypeFilter
): StitchingInfo {
Expand Down
155 changes: 75 additions & 80 deletions packages/stitch/src/typeCandidates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import {
getNamedType,
isNamedType,
GraphQLDirective,
ASTNode,
isSchema,
SchemaDefinitionNode,
SchemaExtensionNode,
isSpecifiedScalarType,
} from 'graphql';

import { wrapSchema } from '@graphql-tools/wrap';
import { isSubschemaConfig, SubschemaConfig } from '@graphql-tools/delegate';
import { SubschemaConfig } from '@graphql-tools/delegate';
import { GraphQLParseOptions, ITypeDefinitions, TypeMap } from '@graphql-tools/utils';
import { buildDocumentFromTypeDefinitions } from '@graphql-tools/schema';

import {
extractTypeDefinitions,
Expand All @@ -25,26 +25,27 @@ import {

import typeFromAST from './typeFromAST';
import { MergeTypeCandidate, MergeTypeFilter, OnTypeConflict, StitchingInfo, TypeMergingOptions } from './types';
import { TypeMap } from '@graphql-tools/utils';
import { mergeCandidates } from './mergeCandidates';

type CandidateSelector = (candidates: Array<MergeTypeCandidate>) => MergeTypeCandidate;

function isDocumentNode(schemaLikeObject: any): schemaLikeObject is DocumentNode {
return (schemaLikeObject as ASTNode).kind !== undefined;
}

export function buildTypeCandidates({
schemaLikeObjects,
subschemaConfigs,
types,
typeDefs,
parseOptions,
transformedSchemas,
extensions,
directiveMap,
schemaDefs,
operationTypeNames,
mergeDirectives,
}: {
schemaLikeObjects: Array<GraphQLSchema | SubschemaConfig | DocumentNode | GraphQLNamedType>;
transformedSchemas: Map<GraphQLSchema | SubschemaConfig, GraphQLSchema>;
subschemaConfigs: Array<SubschemaConfig>;
types: Array<GraphQLNamedType>;
typeDefs: ITypeDefinitions;
parseOptions: GraphQLParseOptions;
transformedSchemas: Map<SubschemaConfig, GraphQLSchema>;
extensions: Array<DocumentNode>;
directiveMap: Record<string, GraphQLDirective>;
schemaDefs: {
Expand All @@ -59,93 +60,87 @@ export function buildTypeCandidates({
let schemaDef: SchemaDefinitionNode;
let schemaExtensions: Array<SchemaExtensionNode> = [];

schemaLikeObjects.forEach(schemaLikeObject => {
if (isDocumentNode(schemaLikeObject)) {
schemaDef = extractSchemaDefinition(schemaLikeObject);
schemaExtensions = schemaExtensions.concat(extractSchemaExtensions(schemaLikeObject));
}
});
let document: DocumentNode;
if ((typeDefs && !Array.isArray(typeDefs)) || (Array.isArray(typeDefs) && typeDefs.length)) {
document = buildDocumentFromTypeDefinitions(typeDefs, parseOptions);
schemaDef = extractSchemaDefinition(document);
schemaExtensions = schemaExtensions.concat(extractSchemaExtensions(document));
}

schemaDefs.schemaDef = schemaDef;
schemaDefs.schemaExtensions = schemaExtensions;

setOperationTypeNames(schemaDefs, operationTypeNames);

schemaLikeObjects.forEach(schemaLikeObject => {
if (isSchema(schemaLikeObject) || isSubschemaConfig(schemaLikeObject)) {
const schema = wrapSchema(schemaLikeObject);

transformedSchemas.set(schemaLikeObject, schema);
subschemaConfigs.forEach(subschemaConfig => {
const schema = wrapSchema(subschemaConfig);

const operationTypes = {
query: schema.getQueryType(),
mutation: schema.getMutationType(),
subscription: schema.getSubscriptionType(),
};
transformedSchemas.set(subschemaConfig, schema);

Object.keys(operationTypes).forEach(operationType => {
if (operationTypes[operationType] != null) {
addTypeCandidate(typeCandidates, operationTypeNames[operationType], {
type: operationTypes[operationType],
subschema: schemaLikeObject,
transformedSchema: schema,
});
}
});
const operationTypes = {
query: schema.getQueryType(),
mutation: schema.getMutationType(),
subscription: schema.getSubscriptionType(),
};

if (mergeDirectives) {
schema.getDirectives().forEach(directive => {
directiveMap[directive.name] = directive;
Object.keys(operationTypes).forEach(operationType => {
if (operationTypes[operationType] != null) {
addTypeCandidate(typeCandidates, operationTypeNames[operationType], {
type: operationTypes[operationType],
subschema: subschemaConfig,
transformedSchema: schema,
});
}
});

const originalTypeMap = schema.getTypeMap();
Object.keys(originalTypeMap).forEach(typeName => {
const type: GraphQLNamedType = originalTypeMap[typeName];
if (
isNamedType(type) &&
getNamedType(type).name.slice(0, 2) !== '__' &&
type !== operationTypes.query &&
type !== operationTypes.mutation &&
type !== operationTypes.subscription
) {
addTypeCandidate(typeCandidates, type.name, {
type,
subschema: schemaLikeObject,
transformedSchema: schema,
});
}
});
} else if (isDocumentNode(schemaLikeObject)) {
const typesDocument = extractTypeDefinitions(schemaLikeObject);
typesDocument.definitions.forEach(def => {
const type = typeFromAST(def) as GraphQLNamedType;
if (type != null) {
addTypeCandidate(typeCandidates, type.name, {
type,
});
}
});

const directivesDocument = extractDirectiveDefinitions(schemaLikeObject);
directivesDocument.definitions.forEach(def => {
const directive = typeFromAST(def) as GraphQLDirective;
if (mergeDirectives) {
schema.getDirectives().forEach(directive => {
directiveMap[directive.name] = directive;
});
}

const extensionsDocument = extractTypeExtensionDefinitions(schemaLikeObject);
if (extensionsDocument.definitions.length > 0) {
extensions.push(extensionsDocument);
const originalTypeMap = schema.getTypeMap();
Object.keys(originalTypeMap).forEach(typeName => {
const type: GraphQLNamedType = originalTypeMap[typeName];
if (
isNamedType(type) &&
getNamedType(type).name.slice(0, 2) !== '__' &&
type !== operationTypes.query &&
type !== operationTypes.mutation &&
type !== operationTypes.subscription
) {
addTypeCandidate(typeCandidates, type.name, {
type,
subschema: subschemaConfig,
transformedSchema: schema,
});
}
} else if (isNamedType(schemaLikeObject)) {
addTypeCandidate(typeCandidates, schemaLikeObject.name, {
type: schemaLikeObject,
});
} else {
throw new Error(`Invalid object ${schemaLikeObject as string}`);
}
});
});

if (document !== undefined) {
const typesDocument = extractTypeDefinitions(document);
typesDocument.definitions.forEach(def => {
const type = typeFromAST(def) as GraphQLNamedType;
if (type != null) {
addTypeCandidate(typeCandidates, type.name, { type });
}
});

const directivesDocument = extractDirectiveDefinitions(document);
directivesDocument.definitions.forEach(def => {
const directive = typeFromAST(def) as GraphQLDirective;
directiveMap[directive.name] = directive;
});

const extensionsDocument = extractTypeExtensionDefinitions(document);
if (extensionsDocument.definitions.length > 0) {
extensions.push(extensionsDocument);
}
}

types.forEach(type => addTypeCandidate(typeCandidates, type.name, { type }));

return typeCandidates;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/stitch/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export interface MergedTypeInfo {
}

export interface StitchingInfo {
transformedSubschemaConfigs: Map<SubschemaConfig, SubschemaConfig>;
transformedSchemas: Map<GraphQLSchema | SubschemaConfig, GraphQLSchema>;
transformedSubschemaConfigs: Map<GraphQLSchema | SubschemaConfig, SubschemaConfig>;
transformedSchemas: Map<SubschemaConfig, GraphQLSchema>;
fragmentsByField: Record<string, Record<string, InlineFragmentNode>>;
selectionSetsByField: Record<string, Record<string, SelectionSetNode>>;
dynamicSelectionSetsByField: Record<string, Record<string, Array<(node: FieldNode) => SelectionSetNode>>>;
Expand Down

0 comments on commit b795ba8

Please sign in to comment.