Skip to content
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
53 changes: 36 additions & 17 deletions composition/src/subgraph/subgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { getNamedTypeForChild } from '../type-merging/type-merging';
import { getOrThrowError } from '../utils/utils';
import { printTypeNode } from '@graphql-tools/merge';
import { ENTITIES_FIELD, SERVICE, SERVICE_FIELD } from '../utils/string-constants';

export type Subgraph = {
definitions: DocumentNode;
Expand Down Expand Up @@ -39,10 +40,7 @@ export function validateSubgraphName(
}

// Places the object-like nodes into the multigraph including the concrete types for abstract types
export function walkSubgraphToCollectObjects(
factory: FederationFactory,
subgraph: InternalSubgraph,
) {
export function walkSubgraphToCollectObjects(factory: FederationFactory, subgraph: InternalSubgraph) {
subgraph.definitions = visit(subgraph.definitions, {
InterfaceTypeDefinition: {
enter(node) {
Expand All @@ -52,9 +50,11 @@ export function walkSubgraphToCollectObjects(
ObjectTypeDefinition: {
enter(node) {
const name = node.name.value;
if (name === SERVICE) {
return false;
}
const operationType = subgraph.operationTypes.get(name);
const parentTypeName = operationType ? getOrThrowError(operationTypeNodeToDefaultType, operationType)
: name;
const parentTypeName = operationType ? getOrThrowError(operationTypeNodeToDefaultType, operationType) : name;
factory.addConcreteTypesForInterface(node);
if (!factory.graph.hasNode(parentTypeName)) {
factory.graph.addNode(parentTypeName);
Expand All @@ -75,8 +75,7 @@ export function walkSubgraphToCollectObjects(
enter(node) {
const name = node.name.value;
const operationType = subgraph.operationTypes.get(name);
const parentTypeName = operationType ? getOrThrowError(operationTypeNodeToDefaultType, operationType)
: name;
const parentTypeName = operationType ? getOrThrowError(operationTypeNodeToDefaultType, operationType) : name;
factory.addConcreteTypesForInterface(node);
if (!factory.graph.hasNode(parentTypeName)) {
factory.graph.addNode(parentTypeName);
Expand All @@ -102,14 +101,14 @@ export function walkSubgraphToCollectObjects(
});
}

export function walkSubgraphToCollectOperationsAndFields(
factory: FederationFactory,
subgraph: Subgraph,
) {
export function walkSubgraphToCollectOperationsAndFields(factory: FederationFactory, subgraph: Subgraph) {
let isCurrentParentRootType = false;
visit(subgraph.definitions, {
ObjectTypeDefinition: {
enter(node) {
if (node.name.value === SERVICE) {
return false;
}
isCurrentParentRootType = factory.isObjectRootType(node);
factory.isCurrentParentEntity = isObjectLikeNodeEntity(node);
factory.parentTypeName = node.name.value;
Expand All @@ -133,6 +132,11 @@ export function walkSubgraphToCollectOperationsAndFields(
FieldDefinition: {
enter(node) {
const fieldName = node.name.value;
if(isCurrentParentRootType){
if(fieldName === SERVICE_FIELD || fieldName === ENTITIES_FIELD){
return false
}
}
const fieldPath = `${factory.parentTypeName}.${fieldName}`;
const fieldRootTypeName = getNamedTypeForChild(fieldPath, node.type);
// If a node exists in the multigraph, it's a concrete object type
Expand Down Expand Up @@ -169,7 +173,10 @@ export function walkSubgraphToCollectOperationsAndFields(
// This also records the appearance of this field in the current subgraph
if (factory.graph.hasNode(fieldRootTypeName)) {
factory.upsertConcreteObjectLikeOperationFieldNode(
fieldName, fieldRootTypeName, fieldPath, printTypeNode(node.type),
fieldName,
fieldRootTypeName,
fieldPath,
printTypeNode(node.type),
);
return false;
}
Expand All @@ -186,7 +193,11 @@ export function walkSubgraphToCollectOperationsAndFields(
}
// Upsert response types and add edges from the operation to each possible concrete type for the abstract field
factory.upsertAbstractObjectLikeOperationFieldNode(
fieldName, fieldRootTypeName, fieldPath, printTypeNode(node.type), concreteTypes
fieldName,
fieldRootTypeName,
fieldPath,
printTypeNode(node.type),
concreteTypes,
);
return false;
},
Expand Down Expand Up @@ -232,7 +243,13 @@ export function walkSubgraphToFederate(subgraph: DocumentNode, factory: Federati
},
FieldDefinition: {
enter(node) {
factory.childName = node.name.value;
const name = node.name.value;
if (factory.isParentRootType) {
if (name === SERVICE_FIELD || name === ENTITIES_FIELD) {
return false;
}
}
factory.childName = name;
factory.upsertFieldNode(node);
},
leave() {
Expand Down Expand Up @@ -276,6 +293,9 @@ export function walkSubgraphToFederate(subgraph: DocumentNode, factory: Federati
},
ObjectTypeDefinition: {
enter(node) {
if (node.name.value === SERVICE) {
return false;
}
factory.areFieldsShareable = !factory.isCurrentSubgraphVersionTwo || isNodeShareable(node);
factory.isCurrentParentEntity = isObjectLikeNodeEntity(node);
factory.isParentRootType = factory.isObjectRootType(node);
Expand All @@ -295,8 +315,7 @@ export function walkSubgraphToFederate(subgraph: DocumentNode, factory: Federati
factory.isCurrentParentExtensionType = true;
factory.isCurrentParentEntity = isObjectLikeNodeEntity(node);
factory.parentTypeName = name;
factory.areFieldsShareable =
!factory.isCurrentSubgraphVersionTwo || isNodeShareable(node);
factory.areFieldsShareable = !factory.isCurrentSubgraphVersionTwo || isNodeShareable(node);
factory.isParentRootType = factory.isObjectRootType(node);
factory.upsertExtensionNode(node);
},
Expand Down
3 changes: 3 additions & 0 deletions composition/src/utils/string-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const DEFAULT_MUTATION = 'Mutation';
export const DEFAULT_QUERY = 'Query';
export const DEFAULT_SUBSCRIPTION = 'Subscription';
export const DEPRECATED = 'deprecated';
export const ENTITIES_FIELD = '_entities';
export const ENUM_UPPER = 'ENUM';
export const ENUM_VALUE_UPPER = 'ENUM_VALUE';
export const EXTERNAL = 'external';
Expand Down Expand Up @@ -31,6 +32,8 @@ export const REQUIRES = 'requires';
export const SCALAR_UPPER = 'SCALAR';
export const SCHEMA = 'schema';
export const SCHEMA_UPPER = 'SCHEMA';
export const SERVICE = '_Service';
export const SERVICE_FIELD = '_service';
export const SHAREABLE = 'shareable';
export const STRING_TYPE = 'String';
export const SUBSCRIPTION = 'Subscription';
Expand Down
73 changes: 72 additions & 1 deletion composition/tests/federation-factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,29 @@ describe('FederationFactory tests', () => {
),
);
});

test('that service object, entities and service fields are not included in the federated graph', () => {
const { errors, federatedGraphAST } = federateSubgraphs([subgraphG, subgraphH]);
expect(errors).toBeUndefined();
expect(documentNodeToNormalizedString(federatedGraphAST!)).toBe(
normalizeString(
versionOneBaseSchema +
`
union _Entity = User

type Query {
string: String
}

type User {
id: String
}

scalar _Any
`,
),
);
});
});

const subgraphA = {
Expand Down Expand Up @@ -449,4 +472,52 @@ const subgraphF: Subgraph = {
string: String
}
`),
};
};

const subgraphG: Subgraph = {
name: 'subgraph-g',
url: '',
definitions: parse(`
type Query {
string: String
_service: _Service
_entities(representations: [_Any!]!): [_Entity]!
}

type _Service{
sdl: String
}

union _Entity = User

type User @key(fields: "id"){
id: String
}

scalar _Any
`),
};

const subgraphH: Subgraph = {
name: 'subgraph-h',
url: '',
definitions: parse(`
type Query {
string: String
_service: _Service
_entities(representations: [_Any!]!): [_Entity]!
}

type _Service{
sdl: String
}

union _Entity = User

type User @key(fields: "id"){
id: String
}

scalar _Any
`),
};
2 changes: 1 addition & 1 deletion router/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.14.4
github.com/tidwall/sjson v1.2.5
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.2.0.20230822083323-a115bc0c7af6
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.2.0.20230829102818-e2553cf069d3
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0
go.opentelemetry.io/otel v1.16.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.39.0
Expand Down
4 changes: 2 additions & 2 deletions router/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,8 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/vektah/gqlparser/v2 v2.5.1 h1:ZGu+bquAY23jsxDRcYpWjttRZrUz07LbiY77gUOHcr4=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.2.0.20230822083323-a115bc0c7af6 h1:LRQ/s+rdZhVBpOJ2wlIk7vq60VAlanbdzRGZP5ViIeE=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.2.0.20230822083323-a115bc0c7af6/go.mod h1:jOEQFeTIDSAEWA//qrpSNjGYcCjMylvc/R/W8eM7+gY=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.2.0.20230829102818-e2553cf069d3 h1:BZRss0FCEDbQL04kxX0YPsJghx6Y5Zzemf40BAxlRQM=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.2.0.20230829102818-e2553cf069d3/go.mod h1:jOEQFeTIDSAEWA//qrpSNjGYcCjMylvc/R/W8eM7+gY=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down