Skip to content

Commit

Permalink
enhance(stitching): simplify subschema sets (#2001)
Browse files Browse the repository at this point in the history
further simplified subschema config sets by simply using an array of SubschemaConfig objects

Named endpoints are no longer necessary, as common endpoints can simply be used by using identical (===) endpoint objects which will allow query batching across subschemas.

Technically, there is now no difference from including an array of SubschemaConfig objects within the `subschemas` property or simply spreading the arrray into the subschemas property, whatever is simpler for end-users.
  • Loading branch information
yaacovCR committed Sep 4, 2020
1 parent 968b1b3 commit fe85dcb
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 79 deletions.
13 changes: 1 addition & 12 deletions packages/delegate/src/Subschema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@ import { GraphQLSchema } from 'graphql';

import { Transform, applySchemaTransforms } from '@graphql-tools/utils';

import {
SubschemaConfig,
MergedTypeConfig,
CreateProxyingResolverFn,
Subscriber,
Executor,
SubschemaSetConfig,
} from './types';
import { SubschemaConfig, MergedTypeConfig, CreateProxyingResolverFn, Subscriber, Executor } from './types';

import { FIELD_SUBSCHEMA_MAP_SYMBOL, OBJECT_SUBSCHEMA_SYMBOL } from './symbols';

Expand All @@ -29,10 +22,6 @@ export function isSubschema(value: any): value is Subschema {
return Boolean(value.transformedSchema);
}

export function isSubschemaSetConfig(value: any): value is SubschemaSetConfig {
return Boolean(value.permutations);
}

export class Subschema {
public schema: GraphQLSchema;
public rootValue?: Record<string, any>;
Expand Down
2 changes: 1 addition & 1 deletion packages/delegate/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export { createRequestFromInfo, createRequest } from './createRequest';
export { defaultMergedResolver } from './defaultMergedResolver';
export { createMergedResolver } from './createMergedResolver';
export { handleResult } from './results/handleResult';
export { Subschema, isSubschema, isSubschemaConfig, isSubschemaSetConfig, getSubschema } from './Subschema';
export { Subschema, isSubschema, isSubschemaConfig, getSubschema } from './Subschema';

export * from './delegationBindings';
export * from './transforms';
Expand Down
12 changes: 1 addition & 11 deletions packages/delegate/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,6 @@ export interface Endpoint<K = any, V = any, C = K> {
};
}

export interface NamedEndpoint extends Endpoint {
name: string;
}

export interface SubschemaPermutation {
createProxyingResolver?: CreateProxyingResolverFn;
transforms?: Array<Transform>;
Expand All @@ -151,13 +147,7 @@ export interface SubschemaPermutation {

export interface SubschemaConfig<K = any, V = any, C = K> extends SubschemaPermutation, Endpoint<K, V, C> {
schema: GraphQLSchema;
endpoint?: Endpoint | string;
}

export interface SubschemaSetConfig<K = any, V = any, C = K> extends Endpoint<K, V, C> {
schema: GraphQLSchema;
permutations: Array<SubschemaPermutation>;
endpoint: Endpoint;
endpoint?: Endpoint;
}

export interface MergedTypeConfig<K = any, V = any> {
Expand Down
73 changes: 43 additions & 30 deletions packages/delegate/tests/batchExecution.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { graphql, execute, ExecutionResult } from 'graphql';

import { makeExecutableSchema } from '@graphql-tools/schema';
import { delegateToSchema, SubschemaConfig, ExecutionParams, SyncExecutor, SubschemaSetConfig } from '../src';
import { delegateToSchema, SubschemaConfig, ExecutionParams, SyncExecutor, Endpoint } from '../src';
import { stitchSchemas } from '@graphql-tools/stitch';
import { FilterObjectFields } from '@graphql-tools/wrap';

Expand Down Expand Up @@ -104,33 +104,35 @@ describe('batch execution', () => {

let executions = 0;

const innerSubschemaSetConfigA: SubschemaSetConfig = {
const endpoint: Endpoint = {
batch: true,
executor: ((params: ExecutionParams): ExecutionResult => {
executions++;
return execute(innerSchemaA, params.document, undefined, params.context, params.variables) as ExecutionResult;
}) as SyncExecutor
};

const innerSubschemaConfigA: Array<SubschemaConfig> = [{
schema: innerSchemaA,
permutations: [{
transforms: [new FilterObjectFields((typeName, fieldName) => typeName !== 'Object' || fieldName !== 'field2')],
merge: {
Object: {
fieldName: 'objectA',
args: () => ({}),
},
transforms: [new FilterObjectFields((typeName, fieldName) => typeName !== 'Object' || fieldName !== 'field2')],
merge: {
Object: {
fieldName: 'objectA',
args: () => ({}),
},
}, {
transforms: [new FilterObjectFields((typeName, fieldName) => typeName !== 'Object' || fieldName !== 'field1')],
merge: {
Object: {
fieldName: 'objectA',
args: () => ({}),
},
},
endpoint,
}, {
schema: innerSchemaA,
transforms: [new FilterObjectFields((typeName, fieldName) => typeName !== 'Object' || fieldName !== 'field1')],
merge: {
Object: {
fieldName: 'objectA',
args: () => ({}),
},
}],
endpoint: {
batch: true,
executor: ((params: ExecutionParams): ExecutionResult => {
executions++;
return execute(innerSchemaA, params.document, undefined, params.context, params.variables) as ExecutionResult;
}) as SyncExecutor
}
}
},
endpoint,
}];

const innerSubschemaConfigB: SubschemaConfig = {
schema: innerSchemaB,
Expand All @@ -142,9 +144,7 @@ describe('batch execution', () => {
},
}

const outerSchema = stitchSchemas({
subschemas: [innerSubschemaSetConfigA, innerSubschemaConfigB],
});
const query = '{ objectB { field1 field2 field3 } }';

const expectedResult = {
data: {
Expand All @@ -156,9 +156,22 @@ describe('batch execution', () => {
},
};

const result = await graphql(outerSchema, '{ objectB { field1 field2 field3 } }', undefined, {});
const outerSchemaWithSubschemasAsArray = stitchSchemas({
subschemas: [innerSubschemaConfigA, innerSubschemaConfigB],
});

const resultWhenAsArray = await graphql(outerSchemaWithSubschemasAsArray, query, undefined, {});

expect(result).toEqual(expectedResult);
expect(resultWhenAsArray).toEqual(expectedResult);
expect(executions).toEqual(1);

const outerSchemaWithSubschemasSpread = stitchSchemas({
subschemas: [...innerSubschemaConfigA, innerSubschemaConfigB],
});

const resultWhenSpread = await graphql(outerSchemaWithSubschemasSpread, query, undefined, {});

expect(resultWhenSpread).toEqual(expectedResult);
expect(executions).toEqual(2);
});
});
20 changes: 6 additions & 14 deletions packages/stitch/src/stitchSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@ import {
import { buildTypeCandidates, buildTypeMap } from './typeCandidates';
import { createStitchingInfo, completeStitchingInfo, addStitchingInfo } from './stitchingInfo';
import { IStitchSchemasOptions } from './types';
import { SubschemaConfig, isSubschemaConfig, isSubschemaSetConfig } from '@graphql-tools/delegate';
import { SubschemaConfig, isSubschemaConfig } from '@graphql-tools/delegate';

export function stitchSchemas({
subschemas = [],
endpoints = [],
types = [],
typeDefs,
schemas = [],
Expand All @@ -55,18 +54,11 @@ export function stitchSchemas({

let schemaLikeObjects: Array<GraphQLSchema | SubschemaConfig | DocumentNode | GraphQLNamedType> = [];

subschemas.forEach(subschema => {
if (isSubschemaSetConfig(subschema)) {
const { schema, permutations, endpoint } = subschema;
permutations.forEach(permutation => {
schemaLikeObjects.push({
schema,
...permutation,
endpoint,
});
});
subschemas.forEach(subschemaOrSubschemaArray => {
if (Array.isArray(subschemaOrSubschemaArray)) {
schemaLikeObjects = schemaLikeObjects.concat(subschemaOrSubschemaArray);
} else {
schemaLikeObjects.push(subschema);
schemaLikeObjects.push(subschemaOrSubschemaArray);
}
});

Expand Down Expand Up @@ -133,7 +125,7 @@ export function stitchSchemas({
directives.push(directiveMap[directiveName]);
});

let stitchingInfo = createStitchingInfo(transformedSchemas, typeCandidates, mergeTypes, endpoints);
let stitchingInfo = createStitchingInfo(transformedSchemas, typeCandidates, mergeTypes);

const typeMap = buildTypeMap({
typeCandidates,
Expand Down
9 changes: 2 additions & 7 deletions packages/stitch/src/stitchingInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
IFieldResolverOptions,
} from '@graphql-tools/utils';

import { delegateToSchema, isSubschemaConfig, SubschemaConfig, NamedEndpoint } from '@graphql-tools/delegate';
import { delegateToSchema, isSubschemaConfig, SubschemaConfig } from '@graphql-tools/delegate';

import { batchDelegateToSchema } from '@graphql-tools/batch-delegate';

Expand All @@ -32,8 +32,7 @@ import { MergeTypeCandidate, MergedTypeInfo, StitchingInfo, MergeTypeFilter } fr
export function createStitchingInfo(
transformedSchemas: Map<GraphQLSchema | SubschemaConfig, GraphQLSchema>,
typeCandidates: Record<string, Array<MergeTypeCandidate>>,
mergeTypes?: boolean | Array<string> | MergeTypeFilter,
endpoints?: Array<NamedEndpoint>
mergeTypes?: boolean | Array<string> | MergeTypeFilter
): StitchingInfo {
const mergedTypes = createMergedTypes(typeCandidates, mergeTypes);
const selectionSetsByField: Record<string, Record<string, SelectionSetNode>> = Object.create(null);
Expand Down Expand Up @@ -88,10 +87,6 @@ export function createStitchingInfo(
selectionSetsByField,
dynamicSelectionSetsByField: undefined,
mergedTypes,
endpoints: endpoints.reduce((acc, endpoint) => {
acc[endpoint.name] = endpoint;
return acc;
}, Object.create(null)),
};
}

Expand Down
6 changes: 2 additions & 4 deletions packages/stitch/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
GraphQLInputObjectType,
} from 'graphql';
import { ITypeDefinitions, TypeMap } from '@graphql-tools/utils';
import { SubschemaConfig, NamedEndpoint, Endpoint, SubschemaSetConfig } from '@graphql-tools/delegate';
import { SubschemaConfig } from '@graphql-tools/delegate';
import { IExecutableSchemaDefinition } from '@graphql-tools/schema';

export interface MergeTypeCandidate {
Expand Down Expand Up @@ -55,14 +55,12 @@ export interface StitchingInfo {
selectionSetsByField: Record<string, Record<string, SelectionSetNode>>;
dynamicSelectionSetsByField: Record<string, Record<string, Array<(node: FieldNode) => SelectionSetNode>>>;
mergedTypes: Record<string, MergedTypeInfo>;
endpoints: Record<string, Endpoint>;
}

export type SchemaLikeObject = SubschemaConfig | GraphQLSchema | string | DocumentNode | Array<GraphQLNamedType>;

export interface IStitchSchemasOptions<TContext = any> extends Omit<IExecutableSchemaDefinition<TContext>, 'typeDefs'> {
subschemas?: Array<GraphQLSchema | SubschemaConfig | SubschemaSetConfig>;
endpoints?: Array<NamedEndpoint>;
subschemas?: Array<GraphQLSchema | SubschemaConfig | Array<SubschemaConfig>>;
typeDefs?: ITypeDefinitions;
types?: Array<GraphQLNamedType>;
schemas?: Array<SchemaLikeObject>;
Expand Down

0 comments on commit fe85dcb

Please sign in to comment.