in composition/src/v1/federation/federation-factory.ts [1365:1487]
handleDisparateFieldNamedTypes() {
for (const [fieldCoordinates, subgraphNamesByNamedTypeName] of this.subgraphNamesByNamedTypeNameByFieldCoords) {
const coordinates = fieldCoordinates.split(PERIOD);
if (coordinates.length !== 2) {
continue;
}
const compositeOutputData = this.parentDefinitionDataByTypeName.get(coordinates[0]);
if (!compositeOutputData) {
this.errors.push(undefinedTypeError(coordinates[0]));
continue;
}
// This error should never happen
if (
compositeOutputData.kind !== Kind.INTERFACE_TYPE_DEFINITION &&
compositeOutputData.kind !== Kind.OBJECT_TYPE_DEFINITION
) {
this.errors.push(
unexpectedNonCompositeOutputTypeError(coordinates[0], kindToTypeString(compositeOutputData.kind)),
);
continue;
}
const fieldData = compositeOutputData.fieldDataByFieldName.get(coordinates[1]);
// This error should never happen
if (!fieldData) {
this.errors.push(unknownFieldDataError(fieldCoordinates));
continue;
}
const interfaceDataByTypeName = new Map<string, InterfaceDefinitionData>();
const objectTypeNames = new Set<string>();
let unionTypeName = '';
for (const namedTypeName of subgraphNamesByNamedTypeName.keys()) {
if (BASE_SCALARS.has(namedTypeName)) {
this.errors.push(incompatibleFederatedFieldNamedTypeError(fieldCoordinates, subgraphNamesByNamedTypeName));
break;
}
const namedTypeData = this.parentDefinitionDataByTypeName.get(namedTypeName);
// This error should never happen
if (!namedTypeData) {
this.errors.push(unknownNamedTypeError(fieldCoordinates, namedTypeName));
break;
}
switch (namedTypeData.kind) {
case Kind.INTERFACE_TYPE_DEFINITION: {
interfaceDataByTypeName.set(namedTypeData.name, namedTypeData);
break;
}
case Kind.OBJECT_TYPE_DEFINITION: {
objectTypeNames.add(namedTypeData.name);
/* Multiple shared Field instances can explicitly return the same Object named type across subgraphs.
* However, the Field is invalid if *any* of the other shared Field instances return a different Object named
* type, even if each of those Objects named types could be coerced into the same mutual abstract type.
* This is because it would be impossible to return identical data from each subgraph if one shared Field
* instance explicitly returns a different Object named type to another shared Field instance.
*/
if (objectTypeNames.size > 1) {
this.errors.push(
incompatibleFederatedFieldNamedTypeError(fieldCoordinates, subgraphNamesByNamedTypeName),
);
continue;
}
break;
}
case Kind.UNION_TYPE_DEFINITION: {
if (unionTypeName) {
this.errors.push(
incompatibleFederatedFieldNamedTypeError(fieldCoordinates, subgraphNamesByNamedTypeName),
);
continue;
}
unionTypeName = namedTypeName;
break;
}
default: {
this.errors.push(incompatibleFederatedFieldNamedTypeError(fieldCoordinates, subgraphNamesByNamedTypeName));
break;
}
}
}
if (interfaceDataByTypeName.size < 0 && !unionTypeName) {
this.errors.push(incompatibleFederatedFieldNamedTypeError(fieldCoordinates, subgraphNamesByNamedTypeName));
continue;
}
/* Default to the Union type name.
* If more than one type of abstract type is returned, an error will be propagated.
*/
let abstractTypeName = unionTypeName;
if (interfaceDataByTypeName.size > 0) {
if (unionTypeName) {
this.errors.push(incompatibleFederatedFieldNamedTypeError(fieldCoordinates, subgraphNamesByNamedTypeName));
continue;
}
/* If there is more than one Interface, there must be an origin Interface.
* This is the "mutual Interface" that all the other Interfaces implement.
*/
for (const interfaceTypeName of interfaceDataByTypeName.keys()) {
abstractTypeName = interfaceTypeName;
for (const [comparisonTypeName, comparisonData] of interfaceDataByTypeName) {
if (interfaceTypeName === comparisonTypeName) {
continue;
}
if (!comparisonData.implementedInterfaceTypeNames.has(interfaceTypeName)) {
abstractTypeName = '';
break;
}
}
if (abstractTypeName) {
break;
}
}
}
/* If the abstract type is:
* 1. An Interface: each returned Object types must implement that origin Interface.
* 2. A Union: all returned Object types must be Member of that Union.
* 3. Invalid (empty string): return an error
*/
if (!this.shouldUpdateFederatedFieldAbstractNamedType(abstractTypeName, objectTypeNames)) {
this.errors.push(incompatibleFederatedFieldNamedTypeError(fieldCoordinates, subgraphNamesByNamedTypeName));
continue;
}
fieldData.namedTypeName = abstractTypeName;
this.updateTypeNodeNamedType(fieldData.type, abstractTypeName);
}
}