Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6fc0a1f

Browse files
committedJul 29, 2021
add tests from #2951
and fix them by reworking batch delegation
1 parent a9aaa08 commit 6fc0a1f

23 files changed

+482
-324
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,60 @@
11
import { BatchDelegateOptions } from './types';
22

3+
import { getNullableType, GraphQLError, GraphQLList } from 'graphql';
4+
5+
import { externalValueFromResult } from '@graphql-tools/delegate';
6+
import { relocatedError } from '@graphql-tools/utils';
7+
38
import { getLoader } from './getLoader';
49

5-
export function batchDelegateToSchema<TContext = any>(options: BatchDelegateOptions<TContext>): any {
10+
export async function batchDelegateToSchema<TContext = any>(options: BatchDelegateOptions<TContext>): Promise<any> {
611
const key = options.key;
712
if (key == null) {
813
return null;
914
} else if (Array.isArray(key) && !key.length) {
1015
return [];
1116
}
17+
18+
const {
19+
schema,
20+
info,
21+
fieldName = info.fieldName,
22+
returnType = info.returnType,
23+
context,
24+
onLocatedError = (originalError: GraphQLError) =>
25+
relocatedError(originalError, originalError.path ? originalError.path.slice(1) : []),
26+
} = options;
27+
1228
const loader = getLoader(options);
13-
return Array.isArray(key) ? loader.loadMany(key) : loader.load(key);
29+
30+
if (Array.isArray(key)) {
31+
const results = await loader.loadMany(key);
32+
33+
return results.map(result =>
34+
result instanceof Error
35+
? result
36+
: externalValueFromResult({
37+
result,
38+
schema,
39+
info,
40+
context,
41+
fieldName,
42+
returnType: (getNullableType(returnType) as GraphQLList<any>).ofType,
43+
onLocatedError,
44+
})
45+
);
46+
}
47+
48+
const result = await loader.load(key);
49+
return result instanceof Error
50+
? result
51+
: externalValueFromResult({
52+
result,
53+
schema,
54+
info,
55+
context,
56+
fieldName,
57+
returnType,
58+
onLocatedError,
59+
});
1460
}

‎packages/batch-delegate/src/createBatchDelegateFn.ts

-31
This file was deleted.
+108-53
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,155 @@
1-
import { getNamedType, GraphQLOutputType, GraphQLList, GraphQLSchema, FieldNode } from 'graphql';
1+
import { GraphQLSchema, FieldNode } from 'graphql';
22

33
import DataLoader from 'dataloader';
44

5-
import { delegateToSchema, SubschemaConfig } from '@graphql-tools/delegate';
6-
import { relocatedError } from '@graphql-tools/utils';
5+
import {
6+
SubschemaConfig,
7+
Transformer,
8+
DelegationContext,
9+
validateRequest,
10+
getExecutor,
11+
getDelegatingOperation,
12+
createRequestFromInfo,
13+
getDelegationContext,
14+
} from '@graphql-tools/delegate';
15+
import { ExecutionRequest, ExecutionResult } from '@graphql-tools/utils';
716

817
import { BatchDelegateOptions } from './types';
918

1019
const cache1: WeakMap<
1120
ReadonlyArray<FieldNode>,
12-
WeakMap<GraphQLSchema | SubschemaConfig<any, any, any, any>, Record<string, DataLoader<any, any>>>
21+
WeakMap<GraphQLSchema | SubschemaConfig, Record<string, DataLoader<any, any>>>
1322
> = new WeakMap();
1423

15-
function createBatchFn<K = any>(options: BatchDelegateOptions) {
24+
function createBatchFn<K = any>(
25+
options: BatchDelegateOptions
26+
): (
27+
keys: ReadonlyArray<K>,
28+
request: ExecutionRequest,
29+
delegationContext: DelegationContext<any>
30+
) => Promise<Array<ExecutionResult<Record<string, any>>>> {
1631
const argsFromKeys = options.argsFromKeys ?? ((keys: ReadonlyArray<K>) => ({ ids: keys }));
17-
const fieldName = options.fieldName ?? options.info.fieldName;
18-
const { valuesFromResults, lazyOptionsFn } = options;
19-
20-
return async (keys: ReadonlyArray<K>) => {
21-
const results = await delegateToSchema({
22-
returnType: new GraphQLList(getNamedType(options.info.returnType) as GraphQLOutputType),
23-
onLocatedError: originalError => {
24-
if (originalError.path == null) {
25-
return originalError;
26-
}
27-
28-
const [pathFieldName, pathNumber] = originalError.path;
29-
30-
if (pathFieldName !== fieldName) {
31-
return originalError;
32-
}
33-
const pathNumberType = typeof pathNumber;
34-
if (pathNumberType !== 'number') {
35-
return originalError;
36-
}
37-
38-
return relocatedError(originalError, originalError.path.slice(0, 0).concat(originalError.path.slice(2)));
39-
},
32+
33+
const { validateRequest: shouldValidateRequest } = options;
34+
35+
return async (keys: ReadonlyArray<K>, request: ExecutionRequest, delegationContext: DelegationContext<any>) => {
36+
const { fieldName, context, info } = delegationContext;
37+
38+
const transformer = new Transformer({
39+
...delegationContext,
4040
args: argsFromKeys(keys),
41-
...(lazyOptionsFn == null ? options : lazyOptionsFn(options)),
4241
});
4342

44-
if (results instanceof Error) {
45-
return keys.map(() => results);
43+
const processedRequest = transformer.transformRequest(request);
44+
45+
if (shouldValidateRequest) {
46+
validateRequest(delegationContext, processedRequest.document);
4647
}
4748

48-
const values = valuesFromResults == null ? results : valuesFromResults(results, keys);
49+
const executor = getExecutor(delegationContext);
50+
51+
const batchResult = (await executor({
52+
...processedRequest,
53+
context,
54+
info,
55+
})) as ExecutionResult;
4956

50-
return Array.isArray(values) ? values : keys.map(() => values);
57+
return splitResult(transformer.transformResult(batchResult), fieldName, keys.length);
5158
};
5259
}
5360

54-
const cacheKeyFn = (key: any) => (typeof key === 'object' ? JSON.stringify(key) : key);
55-
56-
export function getLoader<K = any, V = any, C = K>(options: BatchDelegateOptions<any>): DataLoader<K, V, C> {
57-
const fieldName = options.fieldName ?? options.info.fieldName;
58-
59-
let cache2: WeakMap<GraphQLSchema | SubschemaConfig, Record<string, DataLoader<K, V, C>>> | undefined = cache1.get(
60-
options.info.fieldNodes
61-
);
61+
export function getLoader<K = any, C = K>(options: BatchDelegateOptions<any>): DataLoader<K, ExecutionResult, C> {
62+
const {
63+
info,
64+
operationName,
65+
operation = getDelegatingOperation(info.parentType, info.schema),
66+
fieldName = info.fieldName,
67+
returnType = info.returnType,
68+
selectionSet,
69+
fieldNodes,
70+
} = options;
71+
72+
if (operation !== 'query' && operation !== 'mutation') {
73+
throw new Error(`Batch delegation not possible for operation '${operation}'.`);
74+
}
6275

63-
// Prevents the keys to be passed with the same structure
64-
const dataLoaderOptions: DataLoader.Options<any, any, any> = {
65-
cacheKeyFn,
66-
...options.dataLoaderOptions,
67-
};
76+
const request = createRequestFromInfo({
77+
info,
78+
operation,
79+
fieldName,
80+
selectionSet,
81+
fieldNodes,
82+
operationName,
83+
});
84+
85+
const delegationContext = getDelegationContext({
86+
request,
87+
...options,
88+
operation,
89+
fieldName,
90+
returnType,
91+
});
92+
93+
let cache2 = cache1.get(options.info.fieldNodes);
6894

6995
if (cache2 === undefined) {
7096
cache2 = new WeakMap();
7197
cache1.set(options.info.fieldNodes, cache2);
7298
const loaders = Object.create(null);
7399
cache2.set(options.schema, loaders);
74100
const batchFn = createBatchFn(options);
75-
const loader = new DataLoader<K, V, C>(keys => batchFn(keys), dataLoaderOptions);
101+
const loader = new DataLoader<K, ExecutionResult, C>(
102+
keys => batchFn(keys, request, delegationContext),
103+
options.dataLoaderOptions
104+
);
76105
loaders[fieldName] = loader;
77106
return loader;
78107
}
79108

80-
let loaders = cache2.get(options.schema);
109+
const loaders = cache2.get(options.schema);
81110

82111
if (loaders === undefined) {
83-
loaders = Object.create(null) as Record<string, DataLoader<K, V, C>>;
84-
cache2.set(options.schema, loaders);
112+
const newLoaders = Object.create(null);
113+
cache2.set(options.schema, newLoaders);
85114
const batchFn = createBatchFn(options);
86-
const loader = new DataLoader<K, V, C>(keys => batchFn(keys), dataLoaderOptions);
87-
loaders[fieldName] = loader;
115+
const loader = new DataLoader<K, ExecutionResult, C>(
116+
keys => batchFn(keys, request, delegationContext),
117+
options.dataLoaderOptions
118+
);
119+
newLoaders[fieldName] = loader;
88120
return loader;
89121
}
90122

91123
let loader = loaders[fieldName];
92124

93125
if (loader === undefined) {
94126
const batchFn = createBatchFn(options);
95-
loader = new DataLoader<K, V, C>(keys => batchFn(keys), dataLoaderOptions);
127+
loader = new DataLoader<K, ExecutionResult, C>(
128+
keys => batchFn(keys, request, delegationContext),
129+
options.dataLoaderOptions
130+
);
96131
loaders[fieldName] = loader;
97132
}
98133

99134
return loader;
100135
}
136+
137+
function splitResult(result: ExecutionResult, fieldName: string, numItems: number): Array<ExecutionResult> {
138+
const { data, errors } = result;
139+
const fieldData = data?.[fieldName];
140+
141+
if (fieldData === undefined) {
142+
if (errors === undefined) {
143+
return Array(numItems).fill({});
144+
}
145+
146+
return Array(numItems).fill({ errors });
147+
}
148+
149+
return fieldData.map((value: any) => ({
150+
data: {
151+
[fieldName]: value,
152+
},
153+
errors,
154+
}));
155+
}

‎packages/batch-delegate/src/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export * from './batchDelegateToSchema';
2-
export * from './createBatchDelegateFn';
32

43
export * from './types';

‎packages/batch-delegate/src/types.ts

+6-22
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,20 @@
1-
import { FieldNode, GraphQLSchema } from 'graphql';
2-
31
import DataLoader from 'dataloader';
42

5-
import { IDelegateToSchemaOptions, SubschemaConfig } from '@graphql-tools/delegate';
6-
7-
// TODO: remove in next major release
8-
export type DataLoaderCache<K = any, V = any, C = K> = WeakMap<
9-
ReadonlyArray<FieldNode>,
10-
WeakMap<GraphQLSchema | SubschemaConfig, DataLoader<K, V, C>>
11-
>;
3+
import { IDelegateToSchemaOptions } from '@graphql-tools/delegate';
124

135
export type BatchDelegateFn<TContext = Record<string, any>, K = any> = (
146
batchDelegateOptions: BatchDelegateOptions<TContext, K>
157
) => any;
168

17-
export type BatchDelegateOptionsFn<TContext = Record<string, any>, K = any> = (
18-
batchDelegateOptions: BatchDelegateOptions<TContext, K>
19-
) => IDelegateToSchemaOptions<TContext>;
20-
21-
export interface BatchDelegateOptions<TContext = Record<string, any>, K = any, V = any, C = K>
22-
extends Omit<IDelegateToSchemaOptions<TContext>, 'args'> {
9+
export interface CreateBatchDelegateFnOptions<TContext = Record<string, any>, K = any, V = any, C = K>
10+
extends Partial<Omit<IDelegateToSchemaOptions<TContext>, 'args' | 'info'>> {
2311
dataLoaderOptions?: DataLoader.Options<K, V, C>;
24-
key: K;
2512
argsFromKeys?: (keys: ReadonlyArray<K>) => Record<string, any>;
26-
valuesFromResults?: (results: any, keys: ReadonlyArray<K>) => Array<V>;
27-
lazyOptionsFn?: BatchDelegateOptionsFn;
2813
}
2914

30-
export interface CreateBatchDelegateFnOptions<TContext = Record<string, any>, K = any, V = any, C = K>
31-
extends Partial<Omit<IDelegateToSchemaOptions<TContext>, 'args' | 'info'>> {
15+
export interface BatchDelegateOptions<TContext = Record<string, any>, K = any, V = any, C = K>
16+
extends Omit<IDelegateToSchemaOptions<TContext>, 'args'> {
3217
dataLoaderOptions?: DataLoader.Options<K, V, C>;
18+
key: K | Array<K>;
3319
argsFromKeys?: (keys: ReadonlyArray<K>) => Record<string, any>;
34-
valuesFromResults?: (results: any, keys: ReadonlyArray<K>) => Array<V>;
35-
lazyOptionsFn?: (batchDelegateOptions: BatchDelegateOptions<TContext, K>) => IDelegateToSchemaOptions<TContext>;
3620
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import { graphql, GraphQLError } from 'graphql';
2+
import { batchDelegateToSchema } from '@graphql-tools/batch-delegate';
3+
import { delegateToSchema } from '@graphql-tools/delegate';
4+
import { makeExecutableSchema } from '@graphql-tools/schema';
5+
import { stitchSchemas } from '@graphql-tools/stitch';
6+
7+
class NotFoundError extends GraphQLError {
8+
constructor(id: unknown) {
9+
super('Not Found', undefined, undefined, undefined, undefined, undefined, { id });
10+
}
11+
}
12+
13+
describe('preserves error path indices', () => {
14+
const getProperty = jest.fn((id: unknown) => {
15+
return new NotFoundError(id);
16+
});
17+
18+
beforeEach(() => {
19+
getProperty.mockClear();
20+
});
21+
22+
const subschema = makeExecutableSchema({
23+
typeDefs: /* GraphQL */ `
24+
type Property {
25+
id: ID!
26+
}
27+
28+
type Object {
29+
id: ID!
30+
propertyId: ID!
31+
}
32+
33+
type Query {
34+
objects: [Object!]!
35+
propertyById(id: ID!): Property
36+
propertiesByIds(ids: [ID!]!): [Property]!
37+
}
38+
`,
39+
resolvers: {
40+
Query: {
41+
objects: () => {
42+
return [
43+
{ id: '1', propertyId: '1' },
44+
{ id: '2', propertyId: '1' },
45+
];
46+
},
47+
propertyById: (_, args) => getProperty(args.id),
48+
propertiesByIds: (_, args) => args.ids.map(getProperty),
49+
},
50+
},
51+
});
52+
53+
const subschemas = [subschema];
54+
const typeDefs = /* GraphQL */ `
55+
extend type Object {
56+
property: Property
57+
}
58+
`;
59+
60+
const query = /* GraphQL */ `
61+
query {
62+
objects {
63+
id
64+
property {
65+
id
66+
}
67+
}
68+
}
69+
`;
70+
71+
const expected = {
72+
errors: [
73+
{
74+
message: 'Not Found',
75+
extensions: { id: '1' },
76+
path: ['objects', 0, 'property'],
77+
},
78+
{
79+
message: 'Not Found',
80+
extensions: { id: '1' },
81+
path: ['objects', 1, 'property'],
82+
},
83+
],
84+
data: {
85+
objects: [
86+
{
87+
id: '1',
88+
property: null as null,
89+
},
90+
{
91+
id: '2',
92+
property: null as null,
93+
},
94+
],
95+
},
96+
};
97+
98+
test('using delegateToSchema', async () => {
99+
const schema = stitchSchemas({
100+
subschemas,
101+
typeDefs,
102+
resolvers: {
103+
Object: {
104+
property: {
105+
selectionSet: '{ propertyId }',
106+
resolve: (source, _, context, info) => {
107+
return delegateToSchema({
108+
schema: subschema,
109+
fieldName: 'propertyById',
110+
args: { id: source.propertyId },
111+
context,
112+
info,
113+
});
114+
},
115+
},
116+
},
117+
},
118+
});
119+
120+
const result = await graphql(schema, query);
121+
122+
expect(getProperty).toBeCalledTimes(2);
123+
expect(result).toMatchObject(expected);
124+
});
125+
126+
test('using batchDelegateToSchema', async () => {
127+
const schema = stitchSchemas({
128+
subschemas,
129+
typeDefs,
130+
resolvers: {
131+
Object: {
132+
property: {
133+
selectionSet: '{ propertyId }',
134+
resolve: (source, _, context, info) => {
135+
return batchDelegateToSchema({
136+
schema: subschema,
137+
fieldName: 'propertiesByIds',
138+
key: source.propertyId,
139+
context,
140+
info,
141+
});
142+
},
143+
},
144+
},
145+
},
146+
});
147+
148+
const result = await graphql(schema, query);
149+
150+
expect(getProperty).toBeCalledTimes(1);
151+
expect(result).toMatchObject(expected);
152+
});
153+
});

‎packages/batch-delegate/tests/withTransforms.test.ts

-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ describe('works with complex transforms', () => {
100100
context,
101101
info,
102102
transforms: [queryTransform],
103-
returnType: new GraphQLList(new GraphQLList(info.schema.getType('Book')!))
104103
}),
105104
},
106105
},

‎packages/delegate/src/Subschema.ts

+2-7
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,8 @@ export function isSubschema(value: any): value is Subschema {
99
return Boolean(value.transformedSchema);
1010
}
1111

12-
interface ISubschema<K = any, V = any, C = K, TContext = Record<string, any>>
13-
extends SubschemaConfig<K, V, C, TContext> {
14-
transformedSchema: GraphQLSchema;
15-
}
16-
1712
export class Subschema<K = any, V = any, C = K, TContext = Record<string, any>>
18-
implements ISubschema<K, V, C, TContext>
13+
implements SubschemaConfig<K, V, C, TContext>
1914
{
2015
public schema: GraphQLSchema;
2116

@@ -27,7 +22,7 @@ export class Subschema<K = any, V = any, C = K, TContext = Record<string, any>>
2722
public transforms: Array<Transform<any, TContext>>;
2823
public transformedSchema: GraphQLSchema;
2924

30-
public merge?: Record<string, MergedTypeConfig<any, any, TContext>>;
25+
public merge?: Record<string, MergedTypeConfig<any, TContext>>;
3126

3227
constructor(config: SubschemaConfig<K, V, C, TContext>) {
3328
this.schema = config.schema;

‎packages/delegate/src/Transformer.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { DelegationContext, Transform } from './types';
44

55
import { prepareGatewayDocument } from './prepareGatewayDocument';
66
import { finalizeGatewayRequest } from './finalizeGatewayRequest';
7-
import { externalValueFromResult } from './externalValues';
87

98
interface Transformation {
109
transform: Transform;
@@ -48,7 +47,7 @@ export class Transformer<TContext = Record<string, any>> {
4847
return finalizeGatewayRequest(request, this.delegationContext);
4948
}
5049

51-
public transformResult(originalResult: ExecutionResult) {
50+
public transformResult(originalResult: ExecutionResult): ExecutionResult {
5251
let result = originalResult;
5352

5453
// from rigth to left
@@ -59,6 +58,6 @@ export class Transformer<TContext = Record<string, any>> {
5958
}
6059
}
6160

62-
return externalValueFromResult(result, this.delegationContext);
61+
return result;
6362
}
6463
}

‎packages/delegate/src/delegateToSchema.ts

+63-14
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
DocumentNode,
1111
GraphQLOutputType,
1212
ExecutionArgs,
13+
GraphQLError,
14+
isSchema,
1315
} from 'graphql';
1416

1517
import { ValueOrPromise } from 'value-or-promise';
@@ -34,18 +36,18 @@ import {
3436
SubschemaConfig,
3537
} from './types';
3638

37-
import { isSubschemaConfig } from './subschemaConfig';
3839
import { Subschema } from './Subschema';
3940
import { createRequestFromInfo, getDelegatingOperation } from './createRequest';
4041
import { Transformer } from './Transformer';
42+
import { externalValueFromResult } from './externalValues';
4143

4244
export function delegateToSchema<TContext = Record<string, any>, TArgs = any>(
4345
options: IDelegateToSchemaOptions<TContext, TArgs>
4446
): any {
4547
const {
4648
info,
4749
schema,
48-
rootValue,
50+
rootValue = (schema as SubschemaConfig).rootValue,
4951
operationName,
5052
operation = getDelegatingOperation(info.parentType, info.schema),
5153
fieldName = info.fieldName,
@@ -60,14 +62,16 @@ export function delegateToSchema<TContext = Record<string, any>, TArgs = any>(
6062
fieldName,
6163
selectionSet,
6264
fieldNodes,
63-
rootValue: rootValue ?? (schema as SubschemaConfig).rootValue,
65+
rootValue,
6466
operationName,
6567
context,
6668
});
6769

6870
return delegateRequest({
6971
...options,
7072
request,
73+
operation,
74+
fieldName,
7175
});
7276
}
7377

@@ -83,13 +87,43 @@ function getDelegationReturnType(
8387
export function delegateRequest<TContext = Record<string, any>, TArgs = any>(
8488
options: IDelegateRequestOptions<TContext, TArgs>
8589
) {
86-
const delegationContext = getDelegationContext(options);
90+
let operationDefinition: Maybe<OperationDefinitionNode>;
91+
let targetFieldName: string;
92+
93+
const { document, operationName } = options.request;
94+
if (options.fieldName == null) {
95+
operationDefinition = getOperationAST(document, operationName);
96+
if (operationDefinition == null) {
97+
throw new Error('Cannot infer main operation from the provided document.');
98+
}
99+
targetFieldName = (operationDefinition?.selectionSet.selections[0] as unknown as FieldDefinitionNode).name.value;
100+
} else {
101+
targetFieldName = options.fieldName;
102+
}
103+
104+
const {
105+
schema,
106+
info,
107+
operation = getDelegatingOperation(info.parentType, info.schema),
108+
returnType = info?.returnType ??
109+
getDelegationReturnType(schema instanceof GraphQLSchema ? schema : schema.schema, operation, targetFieldName),
110+
context,
111+
onLocatedError = (error: GraphQLError) => error,
112+
validateRequest: shouldValidateRequest,
113+
} = options;
114+
115+
const delegationContext = getDelegationContext({
116+
...options,
117+
operation,
118+
fieldName: targetFieldName,
119+
returnType,
120+
});
87121

88122
const transformer = new Transformer<TContext>(delegationContext);
89123

90124
const processedRequest = transformer.transformRequest(options.request);
91125

92-
if (options.validateRequest) {
126+
if (shouldValidateRequest) {
93127
validateRequest(delegationContext, processedRequest.document);
94128
}
95129

@@ -99,14 +133,32 @@ export function delegateRequest<TContext = Record<string, any>, TArgs = any>(
99133
.then(originalResult => {
100134
if (isAsyncIterable(originalResult)) {
101135
// "subscribe" to the subscription result and map the result through the transforms
102-
return mapAsyncIterator(originalResult, result => transformer.transformResult(result));
136+
return mapAsyncIterator(originalResult, result =>
137+
externalValueFromResult({
138+
result: transformer.transformResult(result),
139+
schema,
140+
info,
141+
context,
142+
fieldName: targetFieldName,
143+
returnType,
144+
onLocatedError,
145+
})
146+
);
103147
}
104-
return transformer.transformResult(originalResult);
148+
return externalValueFromResult({
149+
result: transformer.transformResult(originalResult),
150+
schema,
151+
info,
152+
context,
153+
fieldName: targetFieldName,
154+
returnType,
155+
onLocatedError,
156+
});
105157
})
106158
.resolve();
107159
}
108160

109-
function getDelegationContext<TContext>({
161+
export function getDelegationContext<TContext>({
110162
request,
111163
schema,
112164
fieldName,
@@ -115,7 +167,6 @@ function getDelegationContext<TContext>({
115167
info,
116168
transforms = [],
117169
transformedSchema,
118-
skipTypeMerging = false,
119170
}: IDelegateRequestOptions<TContext>): DelegationContext<TContext> {
120171
const { operationType: operation, context, operationName, document } = request;
121172
let operationDefinition: Maybe<OperationDefinitionNode>;
@@ -136,7 +187,7 @@ function getDelegationContext<TContext>({
136187
const subschemaOrSubschemaConfig: GraphQLSchema | SubschemaConfig<any, any, any, any> =
137188
stitchingInfo?.subschemaMap.get(schema) ?? schema;
138189

139-
if (isSubschemaConfig(subschemaOrSubschemaConfig)) {
190+
if (!isSchema(subschemaOrSubschemaConfig)) {
140191
const targetSchema = subschemaOrSubschemaConfig.schema;
141192
return {
142193
subschema: schema,
@@ -155,7 +206,6 @@ function getDelegationContext<TContext>({
155206
transformedSchema:
156207
transformedSchema ??
157208
(subschemaOrSubschemaConfig instanceof Subschema ? subschemaOrSubschemaConfig.transformedSchema : targetSchema),
158-
skipTypeMerging,
159209
};
160210
}
161211

@@ -172,11 +222,10 @@ function getDelegationContext<TContext>({
172222
returnType ?? info?.returnType ?? getDelegationReturnType(subschemaOrSubschemaConfig, operation, targetFieldName),
173223
transforms,
174224
transformedSchema: transformedSchema ?? subschemaOrSubschemaConfig,
175-
skipTypeMerging,
176225
};
177226
}
178227

179-
function validateRequest(delegationContext: DelegationContext<any>, document: DocumentNode) {
228+
export function validateRequest(delegationContext: DelegationContext<any>, document: DocumentNode) {
180229
const errors = validate(delegationContext.targetSchema, document);
181230
if (errors.length > 0) {
182231
if (errors.length > 1) {
@@ -188,7 +237,7 @@ function validateRequest(delegationContext: DelegationContext<any>, document: Do
188237
}
189238
}
190239

191-
function getExecutor<TContext>(delegationContext: DelegationContext<TContext>): Executor<TContext> {
240+
export function getExecutor<TContext>(delegationContext: DelegationContext<TContext>): Executor<TContext> {
192241
const { subschemaConfig, targetSchema, context } = delegationContext;
193242

194243
let executor: Executor = subschemaConfig?.executor || createDefaultExecutor(targetSchema);

‎packages/delegate/src/externalObjects.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ export function isExternalObject(data: any): data is ExternalObject {
1515
return data[UNPATHED_ERRORS_SYMBOL] !== undefined;
1616
}
1717

18-
export function createExternalObject(
18+
export function createExternalObject<TContext = Record<string, any>>(
1919
object: any,
2020
errors: Array<GraphQLError>,
2121
initialPath: Array<string | number>,
22-
subschema: GraphQLSchema | SubschemaConfig,
22+
subschema: GraphQLSchema | SubschemaConfig<any, any, any, TContext>,
2323
info?: GraphQLResolveInfo
2424
): ExternalObject {
2525
const schema =

‎packages/delegate/src/externalValues.ts

+28-24
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,39 @@ import {
99
GraphQLType,
1010
locatedError,
1111
GraphQLOutputType,
12-
ExecutionResult,
1312
responsePathAsArray,
1413
} from 'graphql';
1514

16-
import { AggregateError, getResponseKeyFromInfo, relocatedError } from '@graphql-tools/utils';
15+
import { AggregateError, relocatedError } from '@graphql-tools/utils';
1716

18-
import { DelegationContext, SubschemaConfig } from './types';
17+
import { ExternalValueFromResultOptions, SubschemaConfig } from './types';
1918
import { createExternalObject } from './externalObjects';
2019
import { mergeDataAndErrors } from './mergeDataAndErrors';
2120

22-
export function externalValueFromResult(result: ExecutionResult, delegationContext: DelegationContext): any {
23-
const {
24-
context,
25-
info,
26-
fieldName: responseKey = getResponseKey(info),
27-
subschema,
28-
returnType = getReturnType(info),
29-
} = delegationContext;
30-
31-
const data = result.data?.[responseKey];
21+
export function externalValueFromResult<TContext = Record<string, any>>({
22+
result,
23+
schema,
24+
info,
25+
context,
26+
fieldName = getFieldName(info),
27+
returnType = getReturnType(info),
28+
onLocatedError = (error: GraphQLError) => error,
29+
}: ExternalValueFromResultOptions<TContext>): any {
30+
const data = result.data?.[fieldName];
3231
const errors = result.errors ?? [];
3332
const initialPath = info ? responsePathAsArray(info.path) : [];
3433

35-
const { data: newData, unpathedErrors } = mergeDataAndErrors(data, errors);
34+
const { data: newData, unpathedErrors } = mergeDataAndErrors(data, errors, onLocatedError);
3635

37-
return createExternalValue(newData, unpathedErrors, initialPath, subschema, context, info, returnType);
36+
return createExternalValue(newData, unpathedErrors, initialPath, schema, context, info, returnType);
3837
}
3938

40-
export function createExternalValue(
39+
export function createExternalValue<TContext = Record<string, any>>(
4140
data: any,
4241
unpathedErrors: Array<GraphQLError>,
4342
initialPath: Array<string | number>,
44-
subschema: GraphQLSchema | SubschemaConfig,
45-
context?: Record<string, any>,
43+
subschema: GraphQLSchema | SubschemaConfig<any, any, any, TContext>,
44+
context?: TContext,
4645
info?: GraphQLResolveInfo,
4746
returnType = getReturnType(info)
4847
): any {
@@ -68,12 +67,13 @@ export function createExternalValue(
6867
return createExternalList(type, data, unpathedErrors, initialPath, subschema, context, info);
6968
}
7069
}
71-
function createExternalList(
70+
71+
function createExternalList<TContext = Record<string, any>>(
7272
type: GraphQLList<any>,
7373
list: Array<any>,
7474
unpathedErrors: Array<GraphQLError>,
7575
initialPath: Array<string | number>,
76-
subschema: GraphQLSchema | SubschemaConfig,
76+
subschema: GraphQLSchema | SubschemaConfig<any, any, any, TContext>,
7777
context?: Record<string, any>,
7878
info?: GraphQLResolveInfo
7979
) {
@@ -90,15 +90,19 @@ function createExternalList(
9090
);
9191
}
9292

93-
function createExternalListMember(
93+
function createExternalListMember<TContext = Record<string, any>>(
9494
type: GraphQLType,
9595
listMember: any,
9696
unpathedErrors: Array<GraphQLError>,
9797
initialPath: Array<string | number>,
98-
subschema: GraphQLSchema | SubschemaConfig,
98+
subschema: GraphQLSchema | SubschemaConfig<any, any, any, TContext>,
9999
context?: Record<string, any>,
100100
info?: GraphQLResolveInfo
101101
): any {
102+
if (listMember instanceof GraphQLError) {
103+
return relocatedError(listMember, listMember.path ? initialPath.concat(listMember.path) : initialPath);
104+
}
105+
102106
if (listMember instanceof Error) {
103107
return listMember;
104108
}
@@ -145,11 +149,11 @@ function reportUnpathedErrorsViaNull(unpathedErrors: Array<GraphQLError>) {
145149
return null;
146150
}
147151

148-
function getResponseKey(info: GraphQLResolveInfo | undefined): string {
152+
function getFieldName(info: GraphQLResolveInfo | undefined): string {
149153
if (info == null) {
150154
throw new Error(`Data cannot be extracted from result without an explicit key or source schema.`);
151155
}
152-
return getResponseKeyFromInfo(info);
156+
return info.fieldName;
153157
}
154158

155159
function getReturnType(info: GraphQLResolveInfo | undefined): GraphQLOutputType {

‎packages/delegate/src/getFieldsNotInSubschema.ts

-74
This file was deleted.

‎packages/delegate/src/getMergedParent.ts

+21-23
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ import { collectFields, ExecutionContext } from 'graphql/execution/execute';
1313

1414
import { Repeater } from '@repeaterjs/repeater';
1515
import DataLoader from 'dataloader';
16-
import isPromise from 'is-promise';
1716

1817
import { getResponseKeyFromInfo, Maybe, relocatedError } from '@graphql-tools/utils';
1918

2019
import { ExternalObject, MergedTypeInfo, StitchingInfo } from './types';
2120
import { memoize4, memoize3, memoize2 } from './memoize';
2221
import { Subschema } from './Subschema';
2322
import { getInfo, getInitialPath, getObjectSubchema, getSubschemaMap, isExternalObject } from './externalObjects';
23+
import { ValueOrPromise } from 'value-or-promise';
2424

2525
const loaders: WeakMap<any, DataLoader<GraphQLResolveInfo, Promise<ExternalObject>>> = new WeakMap();
2626

@@ -85,7 +85,7 @@ async function getMergedParentsFromInfos(
8585
}
8686
}
8787

88-
infos.forEach(info => {
88+
for (const info of infos) {
8989
const responseKey = getResponseKeyFromInfo(info);
9090
const fieldName = info.fieldName;
9191
if (subschemaFields[fieldName] !== undefined) {
@@ -114,8 +114,8 @@ async function getMergedParentsFromInfos(
114114

115115
const dynamicSelectionSets = typeDynamicSelectionSets?.[fieldName];
116116
if (dynamicSelectionSets !== undefined) {
117-
info.fieldNodes.forEach(fieldNode => {
118-
dynamicSelectionSets.forEach(dynamicSelectionSet => {
117+
for (const fieldNode of info.fieldNodes) {
118+
for (const dynamicSelectionSet of dynamicSelectionSets) {
119119
const responseMap = collectFields(
120120
parentInfo as unknown as ExecutionContext,
121121
sourceSubschemaParentType,
@@ -128,8 +128,8 @@ async function getMergedParentsFromInfos(
128128
keyFieldNodes.add(fieldNode);
129129
}
130130
}
131-
});
132-
});
131+
}
132+
}
133133
}
134134

135135
if (keyResponseKeys[responseKey] !== undefined) {
@@ -142,7 +142,7 @@ async function getMergedParentsFromInfos(
142142
for (const fieldNode of keyFieldNodes) {
143143
fieldNodes.add(fieldNode);
144144
}
145-
});
145+
}
146146

147147
const mergedParents = getMergedParentsFromFieldNodes(
148148
mergedTypeInfo,
@@ -316,33 +316,30 @@ function getMergedParentsFromFieldNodes(
316316

317317
if (!delegationMap.size) {
318318
const mergedParentMap = Object.create(null);
319-
unproxiableFieldNodes.forEach(fieldNode => {
319+
for (const fieldNode of unproxiableFieldNodes) {
320320
const responseKey = fieldNode.alias?.value ?? fieldNode.name.value;
321321
mergedParentMap[responseKey] = Promise.resolve(object);
322-
});
322+
}
323323
return mergedParentMap;
324324
}
325325

326-
const resultMap: Map<Promise<any> | any, SelectionSetNode> = new Map();
327-
328326
const mergedParentMap = Object.create(null);
329327
const schema = parentInfo.schema;
330328
const type = schema.getType(object.__typename) as GraphQLObjectType;
331329
const parentPath = responsePathAsArray(parentInfo.path);
332330
const initialPath = getInitialPath(object);
333331
const newSubschemaMap = getSubschemaMap(object);
332+
const promises: Array<Promise<unknown>> = [];
334333

335334
for (const [s, fieldNodes] of delegationMap) {
336335
const resolver = mergedTypeInfo.resolvers.get(s);
337336
if (resolver) {
338337
const selectionSet: SelectionSetNode = { kind: Kind.SELECTION_SET, selections: fieldNodes };
339-
let maybePromise = resolver(object, context, parentInfo, s, selectionSet);
340-
if (isPromise(maybePromise)) {
341-
maybePromise = maybePromise.then(undefined, error => error);
342-
}
343-
resultMap.set(maybePromise, selectionSet);
338+
const result = new ValueOrPromise(() => resolver(object, context, parentInfo, s, selectionSet))
339+
.catch(error => error)
340+
.resolve();
344341

345-
const promise = Promise.resolve(maybePromise).then(result => {
342+
const promise = Promise.resolve(result).then(result => {
346343
if (result instanceof Error || result === null) {
347344
const fieldNodes = collectFields(
348345
{
@@ -364,7 +361,7 @@ function getMergedParentsFromFieldNodes(
364361
const newPath = basePath.concat(tailPath);
365362
object[responseKey] = relocatedError(result, newPath);
366363
}
367-
} else if (object instanceof Error) {
364+
} else if (result instanceof Error) {
368365
const basePath = parentPath.slice(initialPath.length);
369366
for (const responseKey in fieldNodes) {
370367
const newPath = basePath.concat([responseKey]);
@@ -393,14 +390,15 @@ function getMergedParentsFromFieldNodes(
393390
return object;
394391
});
395392

396-
fieldNodes.forEach(fieldNode => {
393+
for (const fieldNode of fieldNodes) {
397394
const responseKey = fieldNode.alias?.value ?? fieldNode.name.value;
398395
mergedParentMap[responseKey] = promise;
399-
});
396+
}
397+
promises.push(promise);
400398
}
401399
}
402400

403-
const nextPromise = Promise.all(resultMap.keys()).then(() =>
401+
const nextPromise = Promise.all(promises).then(() =>
404402
getMergedParentsFromFieldNodes(
405403
mergedTypeInfo,
406404
object,
@@ -412,10 +410,10 @@ function getMergedParentsFromFieldNodes(
412410
)
413411
);
414412

415-
unproxiableFieldNodes.forEach(fieldNode => {
413+
for (const fieldNode of unproxiableFieldNodes) {
416414
const responseKey = fieldNode.alias?.value ?? fieldNode.name.value;
417415
mergedParentMap[responseKey] = nextPromise.then(nextParent => nextParent[responseKey]);
418-
});
416+
}
419417

420418
return mergedParentMap;
421419
}

‎packages/delegate/src/mergeDataAndErrors.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { AggregateError, relocatedError } from '@graphql-tools/utils';
55
export function mergeDataAndErrors(
66
data: any,
77
errors: ReadonlyArray<GraphQLError> = [],
8+
onLocatedError = (originalError: GraphQLError) => originalError,
89
index = 1
910
): { data: any; unpathedErrors: Array<GraphQLError> } {
1011
if (data == null) {
@@ -13,15 +14,16 @@ export function mergeDataAndErrors(
1314
}
1415

1516
if (errors.length === 1) {
16-
const error = errors[0];
17+
const error = onLocatedError(errors[0]);
1718
const newPath = error.path === undefined ? [] : error.path.slice(1);
1819
const newError = relocatedError(error, newPath);
1920
return { data: newError, unpathedErrors: [] };
2021
}
2122

22-
const firstError = errors[0];
23+
const newErrors = errors.map(error => onLocatedError(error));
24+
const firstError = newErrors[0];
2325
const newPath = firstError.path === undefined ? [] : firstError.path.slice(1);
24-
const newError = locatedError(new AggregateError(errors), undefined, newPath);
26+
const newError = locatedError(new AggregateError(newErrors), undefined, newPath);
2527

2628
return { data: newError, unpathedErrors: [] };
2729
}
@@ -53,6 +55,7 @@ export function mergeDataAndErrors(
5355
const { data: newData, unpathedErrors: newErrors } = mergeDataAndErrors(
5456
data[pathSegment],
5557
pathSegmentErrors,
58+
onLocatedError,
5659
index + 1
5760
);
5861
data[pathSegment] = newData;

‎packages/delegate/src/types.ts

+15-9
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ export interface DelegationContext<TContext = Record<string, any>> {
6363
rootValue?: any;
6464
transforms: Array<Transform<any, TContext>>;
6565
transformedSchema: GraphQLSchema;
66-
skipTypeMerging: boolean;
6766
}
6867

6968
export interface IDelegateToSchemaOptions<TContext = Record<string, any>, TArgs = Record<string, any>> {
@@ -72,6 +71,7 @@ export interface IDelegateToSchemaOptions<TContext = Record<string, any>, TArgs
7271
operation?: OperationTypeNode;
7372
fieldName?: string;
7473
returnType?: GraphQLOutputType;
74+
onLocatedError?: (originalError: GraphQLError) => GraphQLError;
7575
args?: TArgs;
7676
selectionSet?: SelectionSetNode;
7777
fieldNodes?: ReadonlyArray<FieldNode>;
@@ -81,7 +81,6 @@ export interface IDelegateToSchemaOptions<TContext = Record<string, any>, TArgs
8181
transforms?: Array<Transform<any, TContext>>;
8282
transformedSchema?: GraphQLSchema;
8383
validateRequest?: boolean;
84-
skipTypeMerging?: boolean;
8584
}
8685

8786
export interface IDelegateRequestOptions<TContext = Record<string, any>, TArgs = Record<string, any>>
@@ -117,6 +116,16 @@ export interface ICreateRequest {
117116
info?: GraphQLResolveInfo;
118117
}
119118

119+
export interface ExternalValueFromResultOptions<TContext = Record<string, any>> {
120+
result: ExecutionResult;
121+
schema: GraphQLSchema | SubschemaConfig<any, any, any, TContext>;
122+
fieldName?: string;
123+
context?: TContext;
124+
info?: GraphQLResolveInfo;
125+
returnType?: GraphQLOutputType;
126+
onLocatedError?: (error: GraphQLError) => GraphQLError;
127+
}
128+
120129
export interface MergedTypeInfo<TContext = Record<string, any>> {
121130
typeName: string;
122131
selectionSet?: SelectionSetNode;
@@ -151,32 +160,29 @@ export interface SubschemaConfig<K = any, V = any, C = K, TContext = Record<stri
151160
createProxyingResolver?: CreateProxyingResolverFn<TContext>;
152161
rootValue?: any;
153162
transforms?: Array<Transform<any, TContext>>;
154-
merge?: Record<string, MergedTypeConfig<any, any, TContext>>;
163+
merge?: Record<string, MergedTypeConfig<any, TContext>>;
155164
executor?: Executor<TContext>;
156165
batch?: boolean;
157166
batchingOptions?: BatchingOptions<K, V, C>;
158167
}
159168

160-
export interface MergedTypeConfig<K = any, V = any, TContext = Record<string, any>>
161-
extends MergedTypeEntryPoint<K, V, TContext> {
169+
export interface MergedTypeConfig<K = any, TContext = Record<string, any>> extends MergedTypeEntryPoint<K, TContext> {
162170
entryPoints?: Array<MergedTypeEntryPoint>;
163171
fields?: Record<string, MergedFieldConfig>;
164172
computedFields?: Record<string, { selectionSet?: string }>;
165173
canonical?: boolean;
166174
}
167175

168-
export interface MergedTypeEntryPoint<K = any, V = any, TContext = Record<string, any>>
169-
extends MergedTypeResolverOptions<K, V> {
176+
export interface MergedTypeEntryPoint<K = any, TContext = Record<string, any>> extends MergedTypeResolverOptions<K> {
170177
selectionSet?: string;
171178
key?: (originalResult: any) => K;
172179
resolve?: MergedTypeResolver<TContext>;
173180
}
174181

175-
export interface MergedTypeResolverOptions<K = any, V = any> {
182+
export interface MergedTypeResolverOptions<K = any> {
176183
fieldName?: string;
177184
args?: (originalResult: any) => Record<string, any>;
178185
argsFromKeys?: (keys: ReadonlyArray<K>) => Record<string, any>;
179-
valuesFromResults?: (results: any, keys: ReadonlyArray<K>) => Array<V>;
180186
}
181187

182188
export interface MergedFieldConfig {

‎packages/delegate/tests/errors.test.ts

+17-33
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { GraphQLError, GraphQLResolveInfo, locatedError, graphql } from 'graphql';
1+
import { GraphQLError, GraphQLResolveInfo, locatedError, graphql, GraphQLSchema } from 'graphql';
22

33
import { makeExecutableSchema } from '@graphql-tools/schema';
44
import { ExecutionResult } from '@graphql-tools/utils';
55
import { stitchSchemas } from '@graphql-tools/stitch';
66

77
import { UNPATHED_ERRORS_SYMBOL } from '../src/symbols';
88
import { getUnpathedErrors } from '../src/externalObjects';
9-
import { delegateToSchema, defaultMergedResolver, DelegationContext, externalValueFromResult } from '../src';
9+
import { delegateToSchema, defaultMergedResolver, externalValueFromResult } from '../src';
1010

1111
class ErrorWithExtensions extends GraphQLError {
1212
constructor(message: string, code: string) {
@@ -32,31 +32,17 @@ describe('Errors', () => {
3232
});
3333

3434
describe('externalValueFromResult', () => {
35-
const fakeInfo: GraphQLResolveInfo = {
36-
fieldName: "foo",
37-
fieldNodes: [],
38-
returnType: {} as any,
39-
parentType: {} as any,
40-
path: {prev: undefined, key: "foo", typename: undefined } as any,
41-
schema: {} as any,
42-
fragments: {},
43-
rootValue: {},
44-
operation: {} as any,
45-
variableValues: {}
46-
}
47-
4835
test('persists single error', () => {
4936
const result = {
5037
errors: [new GraphQLError('Test error')],
5138
};
5239
try {
53-
externalValueFromResult(
40+
externalValueFromResult({
5441
result,
55-
{
56-
fieldName: 'responseKey',
57-
info: fakeInfo,
58-
} as DelegationContext,
59-
);
42+
schema: {} as GraphQLSchema,
43+
fieldName: 'responseKey',
44+
info: { fieldName: 'foo' } as GraphQLResolveInfo,
45+
});
6046
} catch (e) {
6147
expect(e.message).toEqual('Test error');
6248
expect(e.originalError.errors).toBeUndefined();
@@ -68,13 +54,12 @@ describe('Errors', () => {
6854
errors: [new ErrorWithExtensions('Test error', 'UNAUTHENTICATED')],
6955
};
7056
try {
71-
externalValueFromResult(
57+
externalValueFromResult({
7258
result,
73-
{
74-
fieldName: 'responseKey',
75-
info: fakeInfo,
76-
} as DelegationContext,
77-
);
59+
schema: {} as GraphQLSchema,
60+
fieldName: 'responseKey',
61+
info: { fieldName: 'foo' } as GraphQLResolveInfo,
62+
});
7863
} catch (e) {
7964
expect(e.message).toEqual('Test error');
8065
expect(e.extensions && e.extensions.code).toEqual('UNAUTHENTICATED');
@@ -87,13 +72,12 @@ describe('Errors', () => {
8772
errors: [new GraphQLError('Error1'), new GraphQLError('Error2')],
8873
};
8974
try {
90-
externalValueFromResult(
75+
externalValueFromResult({
9176
result,
92-
{
93-
fieldName: 'responseKey',
94-
info: fakeInfo,
95-
} as DelegationContext,
96-
);
77+
schema: {} as GraphQLSchema,
78+
fieldName: 'responseKey',
79+
info: { fieldName: 'foo' } as GraphQLResolveInfo,
80+
});
9781
} catch (e) {
9882
expect(e.message).toEqual('Error1\nError2');
9983
expect(e.originalError).toBeDefined();

‎packages/stitch/src/createMergedTypeResolver.ts

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
1-
import { getNamedType, GraphQLOutputType, GraphQLList } from 'graphql';
1+
import { getNamedType, GraphQLOutputType } from 'graphql';
22
import { delegateToSchema, MergedTypeResolver, MergedTypeResolverOptions } from '@graphql-tools/delegate';
33
import { batchDelegateToSchema } from '@graphql-tools/batch-delegate';
44

55
export function createMergedTypeResolver<TContext = any>(
66
mergedTypeResolverOptions: MergedTypeResolverOptions
77
): MergedTypeResolver<TContext> | undefined {
8-
const { fieldName, argsFromKeys, valuesFromResults, args } = mergedTypeResolverOptions;
8+
const { fieldName, argsFromKeys, args } = mergedTypeResolverOptions;
99

1010
if (argsFromKeys != null) {
1111
return (originalResult, context, info, subschema, selectionSet, key) =>
1212
batchDelegateToSchema({
1313
schema: subschema,
1414
operation: 'query',
1515
fieldName,
16-
returnType: new GraphQLList(
17-
getNamedType(info.schema.getType(originalResult.__typename) ?? info.returnType) as GraphQLOutputType
18-
),
16+
returnType: getNamedType(
17+
info.schema.getType(originalResult.__typename) ?? info.returnType
18+
) as GraphQLOutputType,
1919
key,
2020
argsFromKeys,
21-
valuesFromResults,
2221
selectionSet,
2322
context,
2423
info,
25-
skipTypeMerging: true,
2624
});
2725
}
2826

@@ -39,7 +37,6 @@ export function createMergedTypeResolver<TContext = any>(
3937
selectionSet,
4038
context,
4139
info,
42-
skipTypeMerging: true,
4340
});
4441
}
4542

‎packages/stitch/src/subschemaConfigTransforms/splitMergedTypeEntryPointsTransformer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export function splitMergedTypeEntryPointsTransformer(subschemaConfig: Subschema
1313

1414
for (let i = 0; i < maxEntryPoints; i += 1) {
1515
const subschemaPermutation = cloneSubschemaConfig(subschemaConfig);
16-
const mergedTypesCopy: Record<string, MergedTypeConfig<any, any, any>> = subschemaPermutation.merge ??
16+
const mergedTypesCopy: Record<string, MergedTypeConfig<any, any>> = subschemaPermutation.merge ??
1717
Object.create(null);
1818
let currentMerge = mergedTypesCopy;
1919

‎packages/stitch/src/types.ts

-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ export type OnTypeConflict<TContext = Record<string, any>> = (
107107

108108
declare module '@graphql-tools/utils' {
109109
interface IFieldResolverOptions<TSource = any, TContext = any, TArgs = any> {
110-
fragment?: string;
111110
selectionSet?: string | ((node: FieldNode) => SelectionSetNode);
112111
}
113112
}

‎packages/stitch/tests/alternateStitchSchemas.test.ts

-3
Original file line numberDiff line numberDiff line change
@@ -2027,7 +2027,6 @@ describe('basic type merging', () => {
20272027
selectionSet,
20282028
context,
20292029
info,
2030-
skipTypeMerging: true,
20312030
}),
20322031
},
20332032
},
@@ -2047,7 +2046,6 @@ describe('basic type merging', () => {
20472046
selectionSet,
20482047
context,
20492048
info,
2050-
skipTypeMerging: true,
20512049
}),
20522050
},
20532051
},
@@ -2171,7 +2169,6 @@ describe('unidirectional type merging', () => {
21712169
selectionSet,
21722170
context,
21732171
info,
2174-
skipTypeMerging: true,
21752172
}),
21762173
},
21772174
},

‎packages/stitch/tests/unknownType.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ describe('test delegateToSchema() with type renaming', () => {
105105
data: {
106106
itemByVariant: null,
107107
},
108-
errors: [new GraphQLError(`Unable to resolve type 'Item'. Did you forget to include a transform that renames types? Did you delegate to the original subschema rather that the subschema config object containing the transform?`)],
108+
errors: [new GraphQLError(`Abstract type "ClassicItemInterface" was resolve to a type "Item" that does not exist inside schema.`)],
109109
});
110110
});
111111

‎packages/stitching-directives/src/stitchingDirectivesTransformer.ts

+4-8
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,7 @@ export function stitchingDirectivesTransformer(
349349

350350
for (const typeName in selectionSetsByType) {
351351
const selectionSet = selectionSetsByType[typeName];
352-
const mergeConfig: Record<string, MergedTypeConfig<any, any, any>> = newSubschemaConfig.merge ??
353-
Object.create(null);
352+
const mergeConfig: Record<string, MergedTypeConfig<any, any>> = newSubschemaConfig.merge ?? Object.create(null);
354353
newSubschemaConfig.merge = mergeConfig;
355354

356355
if (mergeConfig[typeName] == null) {
@@ -364,8 +363,7 @@ export function stitchingDirectivesTransformer(
364363

365364
for (const typeName in computedFieldSelectionSets) {
366365
const selectionSets = computedFieldSelectionSets[typeName];
367-
const mergeConfig: Record<string, MergedTypeConfig<any, any, any>> = newSubschemaConfig.merge ??
368-
Object.create(null);
366+
const mergeConfig: Record<string, MergedTypeConfig<any, any>> = newSubschemaConfig.merge ?? Object.create(null);
369367
newSubschemaConfig.merge = mergeConfig;
370368

371369
if (mergeConfig[typeName] == null) {
@@ -389,8 +387,7 @@ export function stitchingDirectivesTransformer(
389387
for (const typeName in mergedTypesResolversInfo) {
390388
const mergedTypeResolverInfo = mergedTypesResolversInfo[typeName];
391389

392-
const mergeConfig: Record<string, MergedTypeConfig<any, any, any>> = newSubschemaConfig.merge ??
393-
Object.create(null);
390+
const mergeConfig: Record<string, MergedTypeConfig<any, any>> = newSubschemaConfig.merge ?? Object.create(null);
394391
newSubschemaConfig.merge = mergeConfig;
395392

396393
if (newSubschemaConfig.merge[typeName] == null) {
@@ -411,8 +408,7 @@ export function stitchingDirectivesTransformer(
411408

412409
for (const typeName in canonicalTypesInfo) {
413410
const canonicalTypeInfo = canonicalTypesInfo[typeName];
414-
const mergeConfig: Record<string, MergedTypeConfig<any, any, any>> = newSubschemaConfig.merge ??
415-
Object.create(null);
411+
const mergeConfig: Record<string, MergedTypeConfig<any, any>> = newSubschemaConfig.merge ?? Object.create(null);
416412
newSubschemaConfig.merge = mergeConfig;
417413

418414
if (newSubschemaConfig.merge[typeName] == null) {

0 commit comments

Comments
 (0)
Please sign in to comment.