diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index 3bc9d7a94..9dded7c5d 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -857,10 +857,15 @@ and so that fields are grouped according to the set of deferred fragments that include them. Information derived from the presence of a `@defer` directive on a fragment is -returned as a Defer Usage record, unique to the label, a structure containing -only: +returned as a Defer Usage record, unique to the label, a structure containing: - {label}: value of the corresponding argument to the `@defer` directive. +- {ancestors}: a list, where the first entry is the parent Defer Usage record + corresponding to the deferred fragment enclosing this deferred fragment and + the remaining entries are the values included within the {ancestors} entry of + that parent Defer Usage record, or, if this Defer Usage record is deferred + directly by the initial result, a list containing the single value + {undefined}. A Field Group record is a structure containing: @@ -943,7 +948,13 @@ parentTarget, newTarget): - If {deferDirective} is defined: - Let {label} be the value or the variable to {deferDirective}'s {label} argument. - - Let {target} be a new Defer Usage record created from {label}. + - Let {ancestors} be an empty list. + - Append {parentTarget} to {ancestors}. + - If {parentTarget} is defined: + - Let {parentAncestors} be the {ancestor} entry on {parentTarget}. + - Append all items in {parentAncestors} to {ancestors}. + - Let {target} be a new Defer Usage record created from {label} and + {ancestors}. - Append {target} to {newDeferUsages}. - Otherwise: - Let {target} be {newTarget}. @@ -978,7 +989,13 @@ parentTarget, newTarget): - If {deferDirective} is defined: - Let {label} be the value or the variable to {deferDirective}'s {label} argument. - - Let {target} be a new Defer Usage record created from {label}. + - Let {ancestors} be an empty list. + - Append {parentTarget} to {ancestors}. + - If {parentTarget} is defined: + - Let {parentAncestors} be {ancestor} on {parentTarget}. + - Append all items in {parentAncestors} to {ancestors}. + - Let {target} be a new Defer Usage record created from {label} and + {ancestors}. - Append {target} to {newDeferUsages}. - Otherwise: - Let {target} be {newTarget}. @@ -1033,31 +1050,84 @@ BuildGroupedFieldSets(fieldsByTarget, targetsByKey, parentTargets) - Let {fieldDetails} be a new Field Details record created from {node} and {target}. - Append {fieldDetails} to the {fields} entry on {fieldGroup}. - - Continue to the next entry in {targetsByKey}. - - For each {key} in {groupDetailsMap}: - - If {IsSameSet(targets, key)} is {true}: - - Let {details} be the map in {groupDetailsMap} for {targets}. - - Let {newGroupedFieldSet} be the corresponding entry on {details}. - - If {details} is not defined: - - Initialize {newGroupedFieldSet} to an empty ordered map. - - Initialize {shouldInitiateDefer} to {false}. +- Initialize {groupDetailsMap} to an empty unordered map. +- For each {maskingTargets} and {targetSetDetails} in {targetSetDetailsMap}: + - Initialize {newGroupedFieldSet} to an empty ordered map. + - Let {keys} be the corresponding entry on {targetSetDetails}. + - Let {orderedResponseKeys} be the result of + {GetOrderedResponseKeys(maskingTargets, remainingFieldsByTarget)}. + - For each {responseKey} in {orderedResponseKeys}: + - If {keys} does not contain {responseKey}, continue to the next member of + {orderedResponseKeys}. + - Let {fieldGroup} be the Field Group record in {newGroupedFieldSet} for + {responseKey}; if no such record exists, create a new such record from the + empty list {fields} and the set of {parentTargets}. + - Let {targets} be the entry in {targetsByKeys} for {responseKey}. - For each {target} in {targets}: + - Let {remainingFieldsForTarget} be the entry in {remainingFieldsByTarget} + for {target}. + - Let {nodes} be the list in {remainingFieldsByTarget} for {responseKey}. + - Remove the entry for {responseKey} from {remainingFieldsByTarget}. + - For each {node} of {nodes}: + - Let {fieldDetails} be a new Field Details record created from {node} + and {target}. + - Append {fieldDetails} to the {fields} entry on {fieldGroup}. + - Let {shouldInitiateDefer} be the corresponding entry on {targetSetDetails}. + - Initialize {details} to an empty unordered map. + - Set the entry for {groupedFieldSet} in {details} to {newGroupedFieldSet}. + - Set the corresponding entry in {details} to {shouldInitiateDefer}. + - Set the entry for {maskingTargets} in {groupDetailsMap} to {details}. +- Return {groupedFieldSet} and {groupDetailsMap}. + +Note: entries are always added to Grouped Field Set records in the order in +which they appear for the first target. Field order for deferred grouped field +sets never alters the field order for the parent. + +GetOrderedResponseKeys(targets, fieldsByTarget): + +- Let {firstTarget} be the first entry in {targets}. +- Assert that {firstTarget} is defined. +- Let {firstFields} be the entry for {firstTarget} in {fieldsByTarget}. +- Assert that {firstFields} is defined. +- Let {responseKeys} be the keys of {firstFields}. +- Return {responseKeys}. + +GetTargetSetDetails(targetsByKey, parentTargets): + +- Initialize {keysWithParentTargets} to the empty set. +- Initialize {targetSetDetailsMap} to an empty unordered map. +- For each {responseKey} and {targets} in {targetsByKey}: + - Initialize {maskingTargets} to an empty set. + - For each {target} in {targets}: + - If {target} is not defined: + - Add {target} to {maskingTargets}. + - Continue to the next entry in {targets}. + - Let {ancestors} be the corresponding entry on {target}. + - For each {ancestor} of {ancestors}: + - If {targets} contains {ancestor}, continue to the next member of + {targets}. + - Add {target} to {maskingTargets}. + - If {IsSameSet(maskingTargets, parentTargets)} is {true}: + - Append {responseKey} to {keysWithParentTargets}. + - Continue to the next entry in {targetsByKey}. + - For each {key} in {targetSetDetailsMap}: + - If {IsSameSet(maskingTargets, key)} is {true}, let {targetSetDetails} be + the map in {targetSetDetailsMap} for {maskingTargets}. + - If {targetSetDetails} is defined: + - Let {keys} be the corresponding entry on {targetSetDetails}. + - Add {responseKey} to {keys}. + - Otherwise: + - Initialize {keys} to the empty set. + - Add {responseKey} to {keys}. + - Let {shouldInitiateDefer} be {false}. + - For each {target} in {maskingTargets}: - If {parentTargets} does not contain {target}: - Set {shouldInitiateDefer} equal to {true}. - - Initialize {details} to an empty unordered map consisting of - {newGroupedFieldSet} and {shouldInitiateDefer}. - - Set the entry for {targets} in {groupDetailsMap} to {groupDetails}. - - Let {fieldGroup} be the Field Group record in {newGroupedFieldSet} for - {responseKey}; if no such record exists, create a new such record from the - empty list {fields} and the set of {parentTargets}. - - For each {target} in {targets}: - - Let {fields} be the entry in {fieldsByTarget} for {target}. - - Let {nodes} be the list in {fields} for {responseKey}. - - For each {node} of {nodes}: - - Let {fieldDetails} be a new Field Details record created from {node} and - {target}. - - Append {fieldDetails} to the {fields} entry on {fieldGroup}. -- Return {groupedFieldSet} and {groupDetailsMap}. + - Create {newTargetSetDetails} as an map containing {keys} and + {shouldInitiateDefer}. + - Set the entry in {targetSetDetailsMap} for {maskingTargets} to + {newTargetSetDetails}. +- Return {keysWithParentTargets} and {targetSetDetailsMap}. IsSameSet(setA, setB):