Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix aliased shared root fields #6619

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/tricky-jars-wink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@graphql-tools/delegate': minor
'@graphql-tools/federation': patch
---

Handle shared root field queries with aliases
1 change: 1 addition & 0 deletions packages/delegate/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './subschemaConfig.js';
export * from './types.js';
export * from './extractUnavailableFields.js';
export * from './leftOver.js';
export * from './symbols.js';
19 changes: 17 additions & 2 deletions packages/federation/src/supergraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@
BatchingOptions,
delegateToSchema,
extractUnavailableFieldsFromSelectionSet,
isExternalObject,
MergedFieldConfig,
MergedTypeConfig,
SubschemaConfig,
subtractSelectionSets,
Transform,
UNPATHED_ERRORS_SYMBOL,
} from '@graphql-tools/delegate';
import { buildHTTPExecutor, HTTPExecutorOptions } from '@graphql-tools/executor-http';
import {
Expand Down Expand Up @@ -1320,6 +1322,13 @@

const specifiedTypeNames = ['ID', 'String', 'Float', 'Int', 'Boolean', '_Any', '_Entity'];

function makeExternalObject(data: unknown, errors: Error[]) {

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 3 Products

'errors' is declared but its value is never read.

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / Type Check on GraphQL v15

'errors' is declared but its value is never read.

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 10 Products

'errors' is declared but its value is never read.

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 50 Products

'errors' is declared but its value is never read.

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / Type Check on GraphQL v16

'errors' is declared but its value is never read.

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 100 Products

'errors' is declared but its value is never read.

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / Federation Benchmark with 1000 Products

'errors' is declared but its value is never read.

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / Type Check on GraphQL v17.0.0-alpha.1

'errors' is declared but its value is never read.

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / Browser Test

'errors' is declared but its value is never read.

Check failure on line 1325 in packages/federation/src/supergraph.ts

View workflow job for this annotation

GitHub Actions / ESM Test

'errors' is declared but its value is never read.
if (!isExternalObject(data) && typeof data === 'object' && data != null) {
data[UNPATHED_ERRORS_SYMBOL] = [];
}
return data;
}

function mergeResults(results: unknown[]) {
const errors: Error[] = [];
const datas: unknown[] = [];
Expand All @@ -1328,14 +1337,20 @@
errors.push(...result.errors);
} else if (result instanceof Error) {
errors.push(result);
} else {
} else if (result != null) {
datas.push(result);
}
}
if (datas.length) {
return mergeDeep(datas, false, true, true);
if (datas.length === 1) {
return makeExternalObject(datas[0], errors);
}
return makeExternalObject(mergeDeep(datas), errors);
}
if (errors.length) {
if (errors.length === 1) {
throw errors[0];
}
return new AggregateError(errors, errors.map(error => error.message).join(', \n'));
}
return null;
Expand Down
111 changes: 111 additions & 0 deletions packages/federation/test/aliased-shared-root.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { parse } from 'graphql';
import { buildSubgraphSchema } from '@apollo/subgraph';
import { normalizedExecutor } from '@graphql-tools/executor';
import { getStitchedSchemaFromLocalSchemas } from './getStitchedSchemaFromLocalSchemas';

describe('Aliased Shared Root Fields', () => {
it('issue #6613', async () => {
const query = /* GraphQL */ `
query {
testNestedField {
subgraph1 {
id
email
sub1
}
testUserAlias: subgraph2 {
id
email
sub2
}
}
}
`;

const expectedResult = {
data: {
testNestedField: {
subgraph1: {
id: 'user1',
email: '[email protected]',
sub1: true,
},
testUserAlias: {
id: 'user2',
email: '[email protected]',
sub2: true,
},
},
},
};

const subgraph1 = buildSubgraphSchema({
typeDefs: parse(/* GraphQL */ `
type Query {
testNestedField: TestNestedField
}

type TestNestedField {
subgraph1: TestUser1!
}

type TestUser1 {
id: String!
email: String!
sub1: Boolean!
}
`),
resolvers: {
Query: {
testNestedField: () => ({
subgraph1: () => ({
id: 'user1',
email: '[email protected]',
sub1: true,
}),
}),
},
},
});
const subgraph2 = buildSubgraphSchema({
typeDefs: parse(/* GraphQL */ `
type Query {
testNestedField: TestNestedField
}

type TestNestedField {
subgraph2: TestUser2!
}

type TestUser2 {
id: String!
email: String!
sub2: Boolean!
}
`),
resolvers: {
Query: {
testNestedField: () => ({
subgraph2: () => ({
id: 'user2',
email: '[email protected]',
sub2: true,
}),
}),
},
},
});

const gatewaySchema = await getStitchedSchemaFromLocalSchemas({
subgraph1,
subgraph2,
});

const result = await normalizedExecutor({
schema: gatewaySchema,
document: parse(query),
});

expect(result).toEqual(expectedResult);
});
});
Loading