From 4a5bbbbcd4b67e840acdbeac3cd6e0cfd976d350 Mon Sep 17 00:00:00 2001 From: Chris Lenfest Date: Wed, 19 Mar 2025 11:09:36 -0500 Subject: [PATCH 1/3] checkpoint --- composition-js/src/compose.ts | 63 ++++++++++++++++++++++++----- composition-js/src/merging/merge.ts | 4 +- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/composition-js/src/compose.ts b/composition-js/src/compose.ts index 3ec5711fc..18957e987 100644 --- a/composition-js/src/compose.ts +++ b/composition-js/src/compose.ts @@ -11,6 +11,7 @@ import { SubtypingRule, assert, Supergraph, + UpgradeResult, } from "@apollo/federation-internals"; import { GraphQLError } from "graphql"; import { buildFederatedQueryGraph, buildSupergraphAPIQueryGraph } from "@apollo/query-graphs"; @@ -25,6 +26,7 @@ export interface CompositionFailure { schema?: undefined; supergraphSdl?: undefined; hints?: undefined; + subgraphSdl?: { [subgraph: string]: string} } export interface CompositionSuccess { @@ -32,6 +34,7 @@ export interface CompositionSuccess { supergraphSdl: string; hints: CompositionHint[]; errors?: undefined; + subgraphSdl?: { [subgraph: string]: string} } export interface CompositionOptions { @@ -39,6 +42,14 @@ export interface CompositionOptions { allowedFieldTypeMergingSubtypingRules?: SubtypingRule[]; /// Flag to toggle if satisfiability should be performed during composition runSatisfiability?: boolean; + + // note that pipeline options are temporary and will be removed in the future + pipelineOptions?: { + bypassUpgradeSubgraphs?: boolean; + bypassValidateSubgraphs?: boolean; + bypassComposition?: boolean; + outputUpgradedSubgraphs?: boolean; + } } function validateCompositionOptions(options: CompositionOptions) { @@ -63,6 +74,24 @@ export function compose(subgraphs: Subgraphs, options: CompositionOptions = {}): if (mergeResult.errors) { return { errors: mergeResult.errors }; } + + let subgraphSdl: { [name: string]: string } | undefined = !!options.pipelineOptions?.outputUpgradedSubgraphs ? {} : undefined; + if (subgraphSdl !== undefined && mergeResult.subgraphs) { + for (const subgraph of mergeResult.subgraphs.values()) { + subgraphSdl[subgraph.name] = printSchema(subgraph.schema, sdlPrintOptions ?? shallowOrderPrintedDefinitions(defaultPrintOptions)); + } + } + + // if we don't have a supergraph, we're using the `bypassComposition` option. + if (!mergeResult.supergraph) { + return { + schema: undefined, + supergraphSdl: undefined, + hints: undefined, + subgraphSdl, + errors: [], + } + } let satisfiabilityResult; if (runSatisfiability) { @@ -84,11 +113,12 @@ export function compose(subgraphs: Subgraphs, options: CompositionOptions = {}): } catch (err) { return { errors: [err] }; } - + return { schema: mergeResult.supergraph, supergraphSdl, hints: [...mergeResult.hints, ...(satisfiabilityResult?.hints ?? [])], + subgraphSdl, }; } @@ -136,7 +166,7 @@ export function validateSatisfiability({ supergraphSchema, supergraphSdl} : Sati return validateGraphComposition(supergraph.schema, supergraph.subgraphNameToGraphEnumValue(), supergraphQueryGraph, federatedQueryGraph); } -type ValidateSubgraphsAndMergeResult = MergeResult | { errors: GraphQLError[] }; +type ValidateSubgraphsAndMergeResult = MergeResult | { errors: GraphQLError[] } | { subgraphs: Subgraphs, errors?: undefined, supergraph?: undefined }; /** * Upgrade subgraphs if necessary, then validates subgraphs before attempting to merge @@ -144,17 +174,28 @@ type ValidateSubgraphsAndMergeResult = MergeResult | { errors: GraphQLError[] }; * @param subgraphs * @returns ValidateSubgraphsAndMergeResult */ -function validateSubgraphsAndMerge(subgraphs: Subgraphs) : ValidateSubgraphsAndMergeResult { - const upgradeResult = upgradeSubgraphsIfNecessary(subgraphs); - if (upgradeResult.errors) { - return { errors: upgradeResult.errors }; +function validateSubgraphsAndMerge(subgraphs: Subgraphs, options: CompositionOptions = {}) : ValidateSubgraphsAndMergeResult { + let toMerge: Subgraphs; + + if (!options.pipelineOptions?.bypassUpgradeSubgraphs) { + const upgradeResult = upgradeSubgraphsIfNecessary(subgraphs); + if (upgradeResult.errors) { + return { errors: upgradeResult.errors }; + } + toMerge = upgradeResult.subgraphs; + } else { + toMerge = subgraphs; } - const toMerge = upgradeResult.subgraphs; - const validationErrors = toMerge.validate(); - if (validationErrors) { - return { errors: validationErrors }; + if (!options.pipelineOptions?.bypassValidateSubgraphs) { + const validationErrors = toMerge.validate(); + if (validationErrors) { + return { errors: validationErrors }; + } + } + + if (!options.pipelineOptions?.bypassComposition) { + return { subgraphs: toMerge }; } - return mergeSubgraphs(toMerge); } diff --git a/composition-js/src/merging/merge.ts b/composition-js/src/merging/merge.ts index 3c397a9b2..c2bdfffc1 100644 --- a/composition-js/src/merging/merge.ts +++ b/composition-js/src/merging/merge.ts @@ -220,6 +220,7 @@ export interface MergeSuccess { supergraph: Schema; hints: CompositionHint[]; errors?: undefined; + subgraphs?: Subgraphs, } export interface MergeFailure { @@ -769,7 +770,8 @@ class Merger { } else { return { supergraph: this.merged, - hints: this.hints + hints: this.hints, + subgraphs: this.subgraphs, } } } From 723a38e0b0e216caa0d57a5e989fcf506050259f Mon Sep 17 00:00:00 2001 From: Chris Lenfest Date: Tue, 8 Apr 2025 12:45:52 -0500 Subject: [PATCH 2/3] rename pipeline options to match `runSatisfiability` form. --- composition-js/src/compose.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/composition-js/src/compose.ts b/composition-js/src/compose.ts index 18957e987..c47aa40af 100644 --- a/composition-js/src/compose.ts +++ b/composition-js/src/compose.ts @@ -11,7 +11,6 @@ import { SubtypingRule, assert, Supergraph, - UpgradeResult, } from "@apollo/federation-internals"; import { GraphQLError } from "graphql"; import { buildFederatedQueryGraph, buildSupergraphAPIQueryGraph } from "@apollo/query-graphs"; @@ -45,9 +44,9 @@ export interface CompositionOptions { // note that pipeline options are temporary and will be removed in the future pipelineOptions?: { - bypassUpgradeSubgraphs?: boolean; - bypassValidateSubgraphs?: boolean; - bypassComposition?: boolean; + runUpgradeSubgraphs?: boolean; + runValidateSubgraphs?: boolean; + runComposition?: boolean; outputUpgradedSubgraphs?: boolean; } } @@ -75,14 +74,14 @@ export function compose(subgraphs: Subgraphs, options: CompositionOptions = {}): return { errors: mergeResult.errors }; } - let subgraphSdl: { [name: string]: string } | undefined = !!options.pipelineOptions?.outputUpgradedSubgraphs ? {} : undefined; + const subgraphSdl: { [name: string]: string } | undefined = !!options.pipelineOptions?.outputUpgradedSubgraphs ? {} : undefined; if (subgraphSdl !== undefined && mergeResult.subgraphs) { for (const subgraph of mergeResult.subgraphs.values()) { subgraphSdl[subgraph.name] = printSchema(subgraph.schema, sdlPrintOptions ?? shallowOrderPrintedDefinitions(defaultPrintOptions)); } } - // if we don't have a supergraph, we're using the `bypassComposition` option. + // if we don't have a supergraph, we're using the `runComposition`=false option. if (!mergeResult.supergraph) { return { schema: undefined, @@ -177,7 +176,7 @@ type ValidateSubgraphsAndMergeResult = MergeResult | { errors: GraphQLError[] } function validateSubgraphsAndMerge(subgraphs: Subgraphs, options: CompositionOptions = {}) : ValidateSubgraphsAndMergeResult { let toMerge: Subgraphs; - if (!options.pipelineOptions?.bypassUpgradeSubgraphs) { + if (options.pipelineOptions?.runUpgradeSubgraphs !== false) { const upgradeResult = upgradeSubgraphsIfNecessary(subgraphs); if (upgradeResult.errors) { return { errors: upgradeResult.errors }; @@ -187,15 +186,15 @@ function validateSubgraphsAndMerge(subgraphs: Subgraphs, options: CompositionOpt toMerge = subgraphs; } - if (!options.pipelineOptions?.bypassValidateSubgraphs) { + if (!options.pipelineOptions?.runValidateSubgraphs !== false) { const validationErrors = toMerge.validate(); if (validationErrors) { return { errors: validationErrors }; } } - if (!options.pipelineOptions?.bypassComposition) { - return { subgraphs: toMerge }; + if (!options.pipelineOptions?.runComposition !== false) { + return mergeSubgraphs(toMerge); } - return mergeSubgraphs(toMerge); + return { subgraphs: toMerge }; } From 2020c8949141b0b50f3a799a52df7aaccaf87046 Mon Sep 17 00:00:00 2001 From: Chris Lenfest Date: Wed, 9 Apr 2025 11:48:31 -0500 Subject: [PATCH 3/3] update logic --- composition-js/src/compose.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composition-js/src/compose.ts b/composition-js/src/compose.ts index c47aa40af..d1aaf563f 100644 --- a/composition-js/src/compose.ts +++ b/composition-js/src/compose.ts @@ -186,14 +186,14 @@ function validateSubgraphsAndMerge(subgraphs: Subgraphs, options: CompositionOpt toMerge = subgraphs; } - if (!options.pipelineOptions?.runValidateSubgraphs !== false) { + if (options.pipelineOptions?.runValidateSubgraphs !== false) { const validationErrors = toMerge.validate(); if (validationErrors) { return { errors: validationErrors }; } } - if (!options.pipelineOptions?.runComposition !== false) { + if (options.pipelineOptions?.runComposition !== false) { return mergeSubgraphs(toMerge); } return { subgraphs: toMerge };