private MappedFragmentSpread MapFragmentSpread(FragmentSpread fs, ObjectTypeDef objectTypeDef, bool isForUnion) { // if it is not inline fragment, it might need to map to FragmentDef; inline fragments are auto-mapped at construction if (fs.Fragment == null) { fs.Fragment = GetFragmentDef(fs.Name); } if (fs.Fragment == null) { AddError($"Fragment {fs.Name} not defined.", fs); return(null); } // inline fragments are mapped in-place, here. // we need to map them here, once we know the target type if (fs.IsInline) { var onTypeRef = fs.Fragment.OnTypeRef; var skip = onTypeRef != null && onTypeRef.TypeDef != objectTypeDef; if (skip) { return(null); } MapObjectSelectionSubset(fs.Fragment.SelectionSubset, objectTypeDef, fs.Directives, isForUnion); } // there must be mapped field set now var mappedFragmItemSet = fs.Fragment.SelectionSubset.MappedItemSets.FirstOrDefault(fset => fset.ObjectTypeDef == objectTypeDef); if (mappedFragmItemSet == null) { AddError($"FATAL: Could not retrieve mapped item list for fragment spread {fs.Name}", fs, ErrorCodes.ServerError); return(null); } var mappedSpread = new MappedFragmentSpread(fs, mappedFragmItemSet.Items); return(mappedSpread); }
// Might be called for ObjectType or Interface (for intf - just to check fields exist) private void MapObjectSelectionSubset(SelectionSubset selSubset, ObjectTypeDef objectTypeDef, bool isForUnion = false) { // Map arguments on fields, add directives, map fragments foreach (var item in selSubset.Items) { AddRuntimeRequestDirectives(item); switch (item) { case SelectionField selFld: var fldDef = objectTypeDef.Fields[selFld.Name]; if (fldDef == null) { // if field not found, the behavior depends if it is a union; it is error for a union if (!isForUnion) { AddError($"Field '{selFld.Name}' not found on type '{objectTypeDef.Name}'.", selFld); } continue; } selFld.MappedArgs = MapArguments(selFld.Args, fldDef.Args, selFld); AddRuntimeModelDirectives(fldDef); MapSelectionFieldSubsetIfPresent(selFld, fldDef.TypeRef.TypeDef); break; case FragmentSpread fspread: // Named fragment refs are NOT set by parser; parser sets only Inline fragmDefs; we need to match named fragms here if (!fspread.IsInline && fspread.Fragment == null) { fspread.Fragment = GetFragmentDef(fspread.Name); if (fspread.Fragment == null) { AddError($"Fragment {fspread.Name} not defined.", fspread); } } break; } //switch } //foreach item if (_requestContext.Failed) { return; } // Now create mappings for all possible entity types foreach (var typeMapping in objectTypeDef.Mappings) { // It is possible mapped set already exists (with unions and especially fragments) var existing = selSubset.MappedSubSets.FirstOrDefault(ms => ms.Mapping == typeMapping); if (existing != null) { continue; } var mappedItems = new List <MappedSelectionItem>(); foreach (var item in selSubset.Items) { switch (item) { case SelectionField selFld: var fldDef = typeMapping.TypeDef.Fields[selFld.Name]; if (fldDef == null) { // it is not error, it should have been caught earlier; it is unmatch for union continue; } var fldResolver = typeMapping.GetResolver(fldDef); //.FirstOrDefault(fr => fr.Field.Name == selFld.Name); var mappedFld = new MappedSelectionField(selFld, fldResolver); mappedItems.Add(mappedFld); break; case FragmentSpread fs: var onType = fs.Fragment.OnTypeRef?.TypeDef; var skip = onType != null && onType.Kind == TypeKind.Object && onType != objectTypeDef; if (skip) { continue; } if (fs.IsInline) // only inline fragments should be mapped from here; named fragments are mapped separately, upfront { MapObjectSelectionSubset(fs.Fragment.SelectionSubset, objectTypeDef, isForUnion); } var mappedSpread = new MappedFragmentSpread(fs); mappedItems.Add(mappedSpread); break; } //switch } //foreach item selSubset.MappedSubSets.Add(new MappedSelectionSubSet() { Mapping = typeMapping, MappedItems = mappedItems }); } //foreach typeMapping }