public static IReadOnlyDictionary <SelectionSetNode, PSS> Compile( ISchema schema, FragmentCollection fragments, OperationDefinitionNode operation, IEnumerable <ISelectionSetOptimizer>?optimizers = null) { var selectionSets = new Dictionary <SelectionSetNode, PSS>(); void Register(PreparedSelectionSet s) => selectionSets[s.SelectionSet] = s; SelectionSetNode selectionSet = operation.SelectionSet; ObjectType typeContext = schema.GetOperationType(operation.Operation); var root = new PSS(operation.SelectionSet); Register(root); var collector = new OperationCompiler(schema, fragments); collector.Visit( selectionSet, typeContext, new Stack <IObjectField>(), root, Register, new Dictionary <ISelectionNode, SelectionIncludeCondition>(), optimizers?.ToList() ?? new List <ISelectionSetOptimizer>()); return(selectionSets); }
private void Visit( SelectionSetNode selectionSet, ObjectType typeContext, Stack <IObjectField> fieldContext, PSS current, Action <PSS> register, IDictionary <ISelectionNode, SelectionIncludeCondition> includeConditionLookup, List <ISelectionSetOptimizer> optimizers, bool internalSelection = false) { // we first collect the fields that we find in the selection set ... IDictionary <string, PreparedSelection> fields = CollectFields(typeContext, selectionSet, includeConditionLookup, internalSelection); // ... after that is done we will check if there are query optimizer that want // to provide additional fields. OptimizeSelectionSet(fieldContext, typeContext, selectionSet, fields, optimizers); var selections = new List <PreparedSelection>(); var isConditional = false; foreach (PreparedSelection selection in fields.Values) { // we now make the selection read-only and add it to the final selection-set. selection.MakeReadOnly(); selections.Add(selection); // if one selection of a selection-set is conditional, // then the whole set is conditional. if (!isConditional && (selection.IsConditional || selection.IsInternal)) { isConditional = true; } // if the field of the selection returns a composite type we will traverse // the child selection-sets as well. INamedType fieldType = selection.Field.Type.NamedType(); if (fieldType.IsCompositeType()) { if (selection.SelectionSet is null) { // composite fields always have to have a selection-set // otherwise we need to throw. throw QueryCompiler_CompositeTypeSelectionSet(selection.Selection); } var next = new PSS(selection.SelectionSet); register(next); IReadOnlyList <ObjectType> possibleTypes = _schema.GetPossibleTypes(fieldType); for (var i = 0; i < possibleTypes.Count; i++) { // we prepare the field context and check if there are field specific // optimizers that we might want to include. fieldContext.Push(selection.Field); var initialCount = optimizers.Count; var registered = RegisterOptimizers(optimizers, selection.Field); Visit( selection.SelectionSet, possibleTypes[i], fieldContext, next, register, includeConditionLookup, optimizers, selection.IsInternal); // lets clean up the context again and move on to the next. UnregisterOptimizers(optimizers, initialCount, registered); fieldContext.Pop(); } } } current.AddSelections( typeContext, new PreparedSelectionList(selections, isConditional)); }