@apollo/federation-internals
Advanced tools
Comparing version 2.8.3 to 2.8.4
@@ -180,3 +180,22 @@ "use strict"; | ||
const subgraphsUsingInterfaceObject = []; | ||
const objectTypeMap = new Map(); | ||
for (const subgraph of inputs.values()) { | ||
for (const t of subgraph.schema.objectTypes()) { | ||
let entry = objectTypeMap.get(t.name); | ||
if (!entry) { | ||
entry = new Map(); | ||
objectTypeMap.set(t.name, entry); | ||
} | ||
entry.set(subgraph.name, [t, subgraph.metadata()]); | ||
} | ||
for (const t of subgraph.schema.interfaceTypes()) { | ||
let entry = objectTypeMap.get(t.name); | ||
if (!entry) { | ||
entry = new Map(); | ||
objectTypeMap.set(t.name, entry); | ||
} | ||
entry.set(subgraph.name, [t, subgraph.metadata()]); | ||
} | ||
} | ||
for (const subgraph of inputs.values()) { | ||
if (subgraph.isFed2Subgraph()) { | ||
@@ -189,4 +208,3 @@ subgraphs.add(subgraph); | ||
else { | ||
const otherSubgraphs = inputs.values().filter((s) => s.name !== subgraph.name); | ||
const res = new SchemaUpgrader(subgraph, otherSubgraphs).upgrade(); | ||
const res = new SchemaUpgrader(subgraph, inputs.values(), objectTypeMap).upgrade(); | ||
if (res.errors) { | ||
@@ -224,11 +242,2 @@ errors = errors.concat(res.errors); | ||
} | ||
function resolvesField(subgraph, field) { | ||
const metadata = subgraph.metadata(); | ||
const t = subgraph.schema.type(field.parent.name); | ||
if (!t || !(0, definitions_1.isObjectType)(t)) { | ||
return false; | ||
} | ||
const f = t.field(field.name); | ||
return !!f && (!metadata.isFieldExternal(f) || metadata.isFieldPartiallyExternal(f)); | ||
} | ||
function getField(schema, typeName, fieldName) { | ||
@@ -239,5 +248,6 @@ const type = schema.type(typeName); | ||
class SchemaUpgrader { | ||
constructor(originalSubgraph, otherSubgraphs) { | ||
constructor(originalSubgraph, allSubgraphs, objectTypeMap) { | ||
this.originalSubgraph = originalSubgraph; | ||
this.otherSubgraphs = otherSubgraphs; | ||
this.allSubgraphs = allSubgraphs; | ||
this.objectTypeMap = objectTypeMap; | ||
this.changes = new utils_1.MultiMap(); | ||
@@ -287,4 +297,5 @@ this.errors = []; | ||
const extensionAST = (_a = (0, utils_1.firstOf)(type.extensions().values())) === null || _a === void 0 ? void 0 : _a.sourceAST; | ||
for (const subgraph of this.otherSubgraphs) { | ||
const otherType = subgraph.schema.type(type.name); | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name).entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
for (let i = 0; i < typeInOtherSubgraphs.length; i += 1) { | ||
const otherType = typeInOtherSubgraphs[i][1][0]; | ||
if (otherType && otherType.hasNonExtensionElements()) { | ||
@@ -433,9 +444,7 @@ return; | ||
else { | ||
for (const other of this.otherSubgraphs) { | ||
const typeInOther = other.schema.type(type.name); | ||
if (!typeInOther) { | ||
continue; | ||
} | ||
(0, utils_1.assert)((0, definitions_1.isCompositeType)(typeInOther), () => `Type ${type} is of kind ${type.kind} in ${this.subgraph.name} but ${typeInOther.kind} in ${other.name}`); | ||
const keysInOther = typeInOther.appliedDirectivesOf(other.metadata().keyDirective()); | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name).entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
for (const [otherSubgraphName, v] of typeInOtherSubgraphs) { | ||
const [typeInOther, metadata] = v; | ||
(0, utils_1.assert)((0, definitions_1.isCompositeType)(typeInOther), () => `Type ${type} is of kind ${type.kind} in ${this.subgraph.name} but ${typeInOther.kind} in ${otherSubgraphName}`); | ||
const keysInOther = typeInOther.appliedDirectivesOf(metadata.keyDirective()); | ||
if (keysInOther.length === 0) { | ||
@@ -532,3 +541,6 @@ continue; | ||
for (const type of this.schema.objectTypes()) { | ||
if (type.hasAppliedDirective(keyDirective) || type.isRootType()) { | ||
if (type.isSubscriptionRootType()) { | ||
continue; | ||
} | ||
if (type.hasAppliedDirective(keyDirective) || (type.isRootType())) { | ||
for (const field of type.fields()) { | ||
@@ -538,6 +550,13 @@ if (originalMetadata.isFieldShareable(field)) { | ||
} | ||
const otherResolvingSubgraphs = this.otherSubgraphs.filter((s) => resolvesField(s, field)); | ||
if (otherResolvingSubgraphs.length > 0 && !field.hasAppliedDirective(shareableDirective)) { | ||
const entries = Array.from(this.objectTypeMap.get(type.name).entries()); | ||
const typeInOtherSubgraphs = entries.filter(([subgraphName, v]) => { | ||
if (subgraphName === this.subgraph.name) { | ||
return false; | ||
} | ||
const f = v[0].field(field.name); | ||
return !!f && (!v[1].isFieldExternal(f) || v[1].isFieldPartiallyExternal(f)); | ||
}); | ||
if (typeInOtherSubgraphs.length > 0 && !field.hasAppliedDirective(shareableDirective)) { | ||
field.applyDirective(shareableDirective); | ||
this.addChange(new ShareableFieldAddition(field.coordinate, otherResolvingSubgraphs.map((s) => s.name))); | ||
this.addChange(new ShareableFieldAddition(field.coordinate, typeInOtherSubgraphs.map(([s]) => s))); | ||
} | ||
@@ -547,6 +566,6 @@ } | ||
else { | ||
const otherDeclaringSubgraphs = this.otherSubgraphs.filter((s) => s.schema.type(type.name)); | ||
if (otherDeclaringSubgraphs.length > 0 && !type.hasAppliedDirective(shareableDirective)) { | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name).entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
if (typeInOtherSubgraphs.length > 0 && !type.hasAppliedDirective(shareableDirective)) { | ||
type.applyDirective(shareableDirective); | ||
this.addChange(new ShareableTypeAddition(type.coordinate, otherDeclaringSubgraphs.map((s) => s.name))); | ||
this.addChange(new ShareableTypeAddition(type.coordinate, typeInOtherSubgraphs.map(([s]) => s))); | ||
} | ||
@@ -567,4 +586,4 @@ } | ||
if (this.external(element)) { | ||
const tagIsUsedInOtherDefinition = this.otherSubgraphs | ||
.map((s) => getField(s.schema, element.parent.name, element.name)) | ||
const tagIsUsedInOtherDefinition = this.allSubgraphs | ||
.map((s) => s.name === this.originalSubgraph.name ? undefined : getField(s.schema, element.parent.name, element.name)) | ||
.filter((f) => !(f && f.hasAppliedDirective('external'))) | ||
@@ -571,0 +590,0 @@ .some((f) => f && f.appliedDirectivesOf('tag').some((d) => (0, values_1.valueEquals)(application.arguments(), d.arguments()))); |
{ | ||
"name": "@apollo/federation-internals", | ||
"version": "2.8.3", | ||
"version": "2.8.4", | ||
"description": "Apollo Federation internal utilities", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -14,2 +14,3 @@ import { | ||
FieldDefinition, | ||
InterfaceType, | ||
isCompositeType, | ||
@@ -234,3 +235,25 @@ isInterfaceType, | ||
const subgraphsUsingInterfaceObject = []; | ||
// build a data structure to help us do computation only once | ||
const objectTypeMap = new Map<string, Map<string, [ObjectType | InterfaceType, FederationMetadata]>>(); | ||
for (const subgraph of inputs.values()) { | ||
for (const t of subgraph.schema.objectTypes()) { | ||
let entry = objectTypeMap.get(t.name); | ||
if (!entry) { | ||
entry = new Map(); | ||
objectTypeMap.set(t.name, entry); | ||
} | ||
entry.set(subgraph.name, [t, subgraph.metadata()]); | ||
} | ||
for (const t of subgraph.schema.interfaceTypes()) { | ||
let entry = objectTypeMap.get(t.name); | ||
if (!entry) { | ||
entry = new Map(); | ||
objectTypeMap.set(t.name, entry); | ||
} | ||
entry.set(subgraph.name, [t, subgraph.metadata()]); | ||
} | ||
} | ||
for (const subgraph of inputs.values()) { | ||
if (subgraph.isFed2Subgraph()) { | ||
@@ -242,4 +265,3 @@ subgraphs.add(subgraph); | ||
} else { | ||
const otherSubgraphs = inputs.values().filter((s) => s.name !== subgraph.name); | ||
const res = new SchemaUpgrader(subgraph, otherSubgraphs).upgrade(); | ||
const res = new SchemaUpgrader(subgraph, inputs.values(), objectTypeMap).upgrade(); | ||
if (res.errors) { | ||
@@ -297,12 +319,2 @@ errors = errors.concat(res.errors); | ||
function resolvesField(subgraph: Subgraph, field: FieldDefinition<ObjectType>): boolean { | ||
const metadata = subgraph.metadata(); | ||
const t = subgraph.schema.type(field.parent.name); | ||
if (!t || !isObjectType(t)) { | ||
return false; | ||
} | ||
const f = t.field(field.name); | ||
return !!f && (!metadata.isFieldExternal(f) || metadata.isFieldPartiallyExternal(f)); | ||
} | ||
function getField(schema: Schema, typeName: string, fieldName: string): FieldDefinition<CompositeType> | undefined { | ||
@@ -320,3 +332,3 @@ const type = schema.type(typeName); | ||
constructor(private readonly originalSubgraph: Subgraph, private readonly otherSubgraphs: Subgraph[]) { | ||
constructor(private readonly originalSubgraph: Subgraph, private readonly allSubgraphs: readonly Subgraph[], private readonly objectTypeMap: Map<string, Map<string, [ObjectType | InterfaceType, FederationMetadata]>>) { | ||
// Note that as we clone the original schema, the 'sourceAST' values in the elements of the new schema will be those of the original schema | ||
@@ -388,4 +400,5 @@ // and those won't be updated as we modify the schema to make it fed2-enabled. This is _important_ for us here as this is what ensures that | ||
const extensionAST = firstOf<Extension<any>>(type.extensions().values())?.sourceAST; | ||
for (const subgraph of this.otherSubgraphs) { | ||
const otherType = subgraph.schema.type(type.name); | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name)!.entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
for (let i = 0; i < typeInOtherSubgraphs.length; i += 1) { | ||
const otherType = typeInOtherSubgraphs[i][1][0]; | ||
if (otherType && otherType.hasNonExtensionElements()) { | ||
@@ -598,9 +611,8 @@ return; | ||
// not good enough). | ||
for (const other of this.otherSubgraphs) { | ||
const typeInOther = other.schema.type(type.name); | ||
if (!typeInOther) { | ||
continue; | ||
} | ||
assert(isCompositeType(typeInOther), () => `Type ${type} is of kind ${type.kind} in ${this.subgraph.name} but ${typeInOther.kind} in ${other.name}`); | ||
const keysInOther = typeInOther.appliedDirectivesOf(other.metadata().keyDirective()); | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name)!.entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
for (const [otherSubgraphName, v] of typeInOtherSubgraphs) { | ||
const [typeInOther, metadata] = v; | ||
assert(isCompositeType(typeInOther), () => `Type ${type} is of kind ${type.kind} in ${this.subgraph.name} but ${typeInOther.kind} in ${otherSubgraphName}`); | ||
const keysInOther = typeInOther.appliedDirectivesOf(metadata.keyDirective()); | ||
if (keysInOther.length === 0) { | ||
@@ -712,3 +724,6 @@ continue; | ||
for (const type of this.schema.objectTypes()) { | ||
if (type.hasAppliedDirective(keyDirective) || type.isRootType()) { | ||
if(type.isSubscriptionRootType()) { | ||
continue; | ||
} | ||
if (type.hasAppliedDirective(keyDirective) || (type.isRootType())) { | ||
for (const field of type.fields()) { | ||
@@ -721,13 +736,22 @@ // To know if the field is a "key" field which doesn't need shareable, we rely on whether the field is shareable in the original | ||
} | ||
const otherResolvingSubgraphs = this.otherSubgraphs.filter((s) => resolvesField(s, field)); | ||
if (otherResolvingSubgraphs.length > 0 && !field.hasAppliedDirective(shareableDirective)) { | ||
const entries = Array.from(this.objectTypeMap.get(type.name)!.entries()); | ||
const typeInOtherSubgraphs = entries.filter(([subgraphName, v]) => { | ||
if (subgraphName === this.subgraph.name) { | ||
return false; | ||
} | ||
const f = v[0].field(field.name); | ||
return !!f && (!v[1].isFieldExternal(f) || v[1].isFieldPartiallyExternal(f)); | ||
}); | ||
if (typeInOtherSubgraphs.length > 0 && !field.hasAppliedDirective(shareableDirective)) { | ||
field.applyDirective(shareableDirective); | ||
this.addChange(new ShareableFieldAddition(field.coordinate, otherResolvingSubgraphs.map((s) => s.name))); | ||
this.addChange(new ShareableFieldAddition(field.coordinate, typeInOtherSubgraphs.map(([s]) => s))); | ||
} | ||
} | ||
} else { | ||
const otherDeclaringSubgraphs = this.otherSubgraphs.filter((s) => s.schema.type(type.name)); | ||
if (otherDeclaringSubgraphs.length > 0 && !type.hasAppliedDirective(shareableDirective)) { | ||
const typeInOtherSubgraphs = Array.from(this.objectTypeMap.get(type.name)!.entries()).filter(([subgraphName, _]) => subgraphName !== this.subgraph.name); | ||
if (typeInOtherSubgraphs.length > 0 && !type.hasAppliedDirective(shareableDirective)) { | ||
type.applyDirective(shareableDirective); | ||
this.addChange(new ShareableTypeAddition(type.coordinate, otherDeclaringSubgraphs.map((s) => s.name))); | ||
this.addChange(new ShareableTypeAddition(type.coordinate, typeInOtherSubgraphs.map(([s]) => s))); | ||
} | ||
@@ -751,4 +775,4 @@ } | ||
if (this.external(element)) { | ||
const tagIsUsedInOtherDefinition = this.otherSubgraphs | ||
.map((s) => getField(s.schema, element.parent.name, element.name)) | ||
const tagIsUsedInOtherDefinition = this.allSubgraphs | ||
.map((s) => s.name === this.originalSubgraph.name ? undefined : getField(s.schema, element.parent.name, element.name)) | ||
.filter((f) => !(f && f.hasAppliedDirective('external'))) | ||
@@ -755,0 +779,0 @@ .some((f) => f && f.appliedDirectivesOf('tag').some((d) => valueEquals(application.arguments(), d.arguments()))); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2227490
35343