Skip to content

Commit 943ce44

Browse files
committed
Fix issue with empty array, set up test cases with arbitrary variables for simplicity
1 parent 1e7b946 commit 943ce44

File tree

2 files changed

+134
-40
lines changed

2 files changed

+134
-40
lines changed

packages/plugins/typescript/resolvers/tests/ts-resolvers.federation.spec.ts

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -268,19 +268,25 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => {
268268
users: [User]
269269
}
270270
271+
type Account @key(fields: "id") {
272+
id: ID!
273+
key: String!
274+
}
275+
271276
type User @key(fields: "id") {
272277
id: ID!
273278
274-
name: String @external
275-
age: Int! @external
276-
username: String @requires(fields: "name age")
279+
a: String @external
280+
aRequires: String @requires(fields: "a")
281+
282+
b: String! @external
283+
bRequires: String! @requires(fields: "b")
277284
278-
publicName: String! @requires(fields: "name")
285+
c: String! @external
286+
cRequires: String! @requires(fields: "c")
279287
280-
birthDay: String! @external
281-
birthMonth: String! @external
282-
birthYear: String! @external
283-
birthDate: String! @requires(fields: "birthDay birthMonth birthYear")
288+
d: String! @external
289+
dRequires: String! @requires(fields: "d")
284290
}
285291
`;
286292

@@ -294,19 +300,29 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => {
294300
expect(content).toBeSimilarStringTo(`
295301
export type ResolversParentTypes = {
296302
Query: {};
303+
Account: Account |
304+
( { __typename: 'Account' }
305+
& GraphQLRecursivePick<FederationTypes['Account'], {"id":true}> );
306+
ID: Scalars['ID']['output'];
307+
String: Scalars['String']['output'];
297308
User: User |
298309
( { __typename: 'User' }
299310
& GraphQLRecursivePick<FederationTypes['User'], {"id":true}>
300311
& ( {}
301-
| GraphQLRecursivePick<FederationTypes['User'], {"name":true,"age":true}>
302-
| GraphQLRecursivePick<FederationTypes['User'], {"name":true,"age":true}>
303-
| GraphQLRecursivePick<FederationTypes['User'], {"name":true,"age":true,"birthDay":true,"birthMonth":true,"birthYear":true}>
304-
| GraphQLRecursivePick<FederationTypes['User'], {"name":true}>
305-
| GraphQLRecursivePick<FederationTypes['User'], {"name":true,"birthDay":true,"birthMonth":true,"birthYear":true}>
306-
| GraphQLRecursivePick<FederationTypes['User'], {"birthDay":true,"birthMonth":true,"birthYear":true}> ) );
307-
ID: Scalars['ID']['output'];
308-
String: Scalars['String']['output'];
309-
Int: Scalars['Int']['output'];
312+
| GraphQLRecursivePick<FederationTypes['User'], {"a":true}>
313+
| GraphQLRecursivePick<FederationTypes['User'], {"a":true,"b":true}>
314+
| GraphQLRecursivePick<FederationTypes['User'], {"a":true,"c":true}>
315+
| GraphQLRecursivePick<FederationTypes['User'], {"a":true,"d":true}>
316+
| GraphQLRecursivePick<FederationTypes['User'], {"a":true,"b":true,"c":true}>
317+
| GraphQLRecursivePick<FederationTypes['User'], {"a":true,"b":true,"d":true}>
318+
| GraphQLRecursivePick<FederationTypes['User'], {"a":true,"b":true,"c":true,"d":true}>
319+
| GraphQLRecursivePick<FederationTypes['User'], {"b":true}>
320+
| GraphQLRecursivePick<FederationTypes['User'], {"b":true,"c":true}>
321+
| GraphQLRecursivePick<FederationTypes['User'], {"b":true,"d":true}>
322+
| GraphQLRecursivePick<FederationTypes['User'], {"b":true,"c":true,"d":true}>
323+
| GraphQLRecursivePick<FederationTypes['User'], {"c":true}>
324+
| GraphQLRecursivePick<FederationTypes['User'], {"c":true,"d":true}>
325+
| GraphQLRecursivePick<FederationTypes['User'], {"d":true}> ) );
310326
Boolean: Scalars['Boolean']['output'];
311327
};
312328
`);
@@ -318,16 +334,25 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => {
318334
( { __typename: 'User' }
319335
& GraphQLRecursivePick<FederationType, {"id":true}>
320336
& ( {}
321-
| GraphQLRecursivePick<FederationType, {"name":true,"age":true}>
322-
| GraphQLRecursivePick<FederationType, {"name":true,"age":true}>
323-
| GraphQLRecursivePick<FederationType, {"name":true,"age":true,"birthDay":true,"birthMonth":true,"birthYear":true}>
324-
| GraphQLRecursivePick<FederationType, {"name":true}>
325-
| GraphQLRecursivePick<FederationType, {"name":true,"birthDay":true,"birthMonth":true,"birthYear":true}>
326-
| GraphQLRecursivePick<FederationType, {"birthDay":true,"birthMonth":true,"birthYear":true}> ) ), ContextType>;
337+
| GraphQLRecursivePick<FederationType, {"a":true}>
338+
| GraphQLRecursivePick<FederationType, {"a":true,"b":true}>
339+
| GraphQLRecursivePick<FederationType, {"a":true,"c":true}>
340+
| GraphQLRecursivePick<FederationType, {"a":true,"d":true}>
341+
| GraphQLRecursivePick<FederationType, {"a":true,"b":true,"c":true}>
342+
| GraphQLRecursivePick<FederationType, {"a":true,"b":true,"d":true}>
343+
| GraphQLRecursivePick<FederationType, {"a":true,"b":true,"c":true,"d":true}>
344+
| GraphQLRecursivePick<FederationType, {"b":true}>
345+
| GraphQLRecursivePick<FederationType, {"b":true,"c":true}>
346+
| GraphQLRecursivePick<FederationType, {"b":true,"d":true}>
347+
| GraphQLRecursivePick<FederationType, {"b":true,"c":true,"d":true}>
348+
| GraphQLRecursivePick<FederationType, {"c":true}>
349+
| GraphQLRecursivePick<FederationType, {"c":true,"d":true}>
350+
| GraphQLRecursivePick<FederationType, {"d":true}> ) ), ContextType>;
327351
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
328-
username?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
329-
publicName?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
330-
birthDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
352+
aRequires?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
353+
bRequires?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
354+
cRequires?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
355+
dRequires?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
331356
};
332357
`);
333358
});

packages/utils/plugins-helpers/src/federation.ts

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -440,15 +440,17 @@ export class ApolloFederation {
440440
return false;
441441
}
442442

443-
return `\n ( { __typename: '${typeName}' }\n & ${federationMeta.referenceSelectionSets
444-
.map(({ directive, selectionSets: originalSelectionSets }) => {
443+
const referenceSelectionSetStrings = federationMeta.referenceSelectionSets.reduce<string[]>(
444+
(acc, { directive, selectionSets: originalSelectionSets }) => {
445445
const result: string[] = [];
446446

447447
let selectionSets = originalSelectionSets;
448448
if (directive === '@requires') {
449-
result.push('{}');
450449
selectionSets = [];
451-
findAllCombinations(originalSelectionSets, selectionSets);
450+
findAllSelectionSetCombinations(originalSelectionSets, selectionSets);
451+
if (selectionSets.length > 0) {
452+
result.push('{}');
453+
}
452454
}
453455

454456
for (const referenceSelectionSet of selectionSets) {
@@ -460,9 +462,22 @@ export class ApolloFederation {
460462
);
461463
}
462464

463-
return result.length > 1 ? `( ${result.join('\n | ')} )` : result.join(' | ');
464-
})
465-
.join('\n & ')} )`;
465+
if (result.length === 0) {
466+
return acc;
467+
}
468+
469+
if (result.length === 1) {
470+
acc.push(result.join(' | '));
471+
return acc;
472+
}
473+
474+
acc.push(`( ${result.join('\n | ')} )`);
475+
return acc;
476+
},
477+
[]
478+
);
479+
480+
return `\n ( { __typename: '${typeName}' }\n & ${referenceSelectionSetStrings.join('\n & ')} )`;
466481
}
467482

468483
private createMapOfProvides() {
@@ -584,15 +599,69 @@ function extractReferenceSelectionSet(directive: DirectiveNode): ReferenceSelect
584599
});
585600
}
586601

587-
function findAllCombinations(selectionSets: ReferenceSelectionSet[], result: ReferenceSelectionSet[]): void {
588-
const [currentSelectionSet, ...rest] = selectionSets;
602+
/**
603+
* Function to find all combinations of selection sets and push them into the `result`
604+
* This is used for `@requires` directive because depending on the operation selection set, different
605+
* combination of fields are sent from the router.
606+
*
607+
* @example
608+
* Input: [
609+
* { a: true },
610+
* { b: true },
611+
* { c: true },
612+
* { d: true},
613+
* ]
614+
* Output: [
615+
* { a: true },
616+
* { a: true, b: true },
617+
* { a: true, c: true },
618+
* { a: true, d: true },
619+
* { a: true, b: true, c: true },
620+
* { a: true, b: true, d: true },
621+
* { a: true, c: true, d: true },
622+
* { a: true, b: true, c: true, d: true }
623+
*
624+
* { b: true },
625+
* { b: true, c: true },
626+
* { b: true, d: true },
627+
* { b: true, c: true, d: true }
628+
*
629+
* { c: true },
630+
* { c: true, d: true },
631+
*
632+
* { d: true },
633+
* ]
634+
* ```
635+
*/
636+
function findAllSelectionSetCombinations(
637+
selectionSets: ReferenceSelectionSet[],
638+
result: ReferenceSelectionSet[]
639+
): void {
640+
if (selectionSets.length === 0) {
641+
return;
642+
}
643+
644+
for (let baseIndex = 0; baseIndex < selectionSets.length; baseIndex++) {
645+
const base = selectionSets.slice(0, baseIndex + 1);
646+
const rest = selectionSets.slice(baseIndex + 1, selectionSets.length);
647+
648+
const currentSelectionSet = base.reduce((acc, selectionSet) => {
649+
acc = { ...acc, ...selectionSet };
650+
return acc;
651+
}, {});
652+
653+
if (baseIndex === 0) {
654+
result.push(currentSelectionSet);
655+
}
589656

590-
result.push(currentSelectionSet);
591-
for (const selectionSet of rest) {
592-
result.push({ ...currentSelectionSet, ...selectionSet });
657+
for (const selectionSet of rest) {
658+
result.push({ ...currentSelectionSet, ...selectionSet });
659+
}
593660
}
594661

595-
if (rest.length > 0) {
596-
findAllCombinations(rest, result);
662+
const next = selectionSets.slice(1, selectionSets.length);
663+
664+
if (next.length > 0) {
665+
findAllSelectionSetCombinations(next, result);
597666
}
598667
}

0 commit comments

Comments
 (0)