private void MapSelectionSubSet(SelectionSubset selSubset, TypeDefBase typeDef) { switch (typeDef) { case ScalarTypeDef _: case EnumTypeDef _: // that should never happen AddError($"Scalar or Enum may not have a selection subset", selSubset); break; case ObjectTypeDef objTypeDef: MapObjectSelectionSubset(selSubset, objTypeDef); break; case InterfaceTypeDef intTypeDef: foreach (var objType in intTypeDef.PossibleTypes) { MapObjectSelectionSubset(selSubset, objType); } break; case UnionTypeDef unionTypeDef: foreach (var objType in unionTypeDef.PossibleTypes) { MapObjectSelectionSubset(selSubset, objType, isForUnion: true); } break; } }
// Might be called for ObjectType or Interface (for intf - just to check fields exist) private void MapObjectSelectionSubset(SelectionSubset selSubset, ObjectTypeDef objectTypeDef, IList <RequestDirective> directives, bool isForUnion = false) { var mappedFields = MapSelectionItems(selSubset.Items, objectTypeDef, directives, isForUnion); selSubset.MappedItemSets.Add(new MappedObjectItemSet() { ObjectTypeDef = objectTypeDef, Items = mappedFields }); }
} //method private MappedSelectionSubSet GetMappedSubset(SelectionSubset subSet, IList <ObjectTypeDef> objectTypeDefs, Type entityType, NamedRequestObject requestObj) { var mappedSubset = subSet.MappedSubSets.FirstOrDefault( ms => (ms.Mapping.EntityType == entityType || ms.Mapping.EntityType.IsAssignableFrom(entityType)) && objectTypeDefs.Contains(ms.Mapping.TypeDef)); if (mappedSubset == null) { var types = string.Join(",", objectTypeDefs); this._requestContext.AddError($"Failed to find mapping from entity type {entityType} to GraphQLType(s) [{types}].", requestObj); AbortRequest(); } return(mappedSubset); }
// 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 }
private async Task ExecuteObjectsSelectionSubsetAsync(IList <OutputObjectScope> parentScopes, ObjectTypeDef objTypeDef, SelectionSubset subSet) { var outItemSet = subSet.MappedItemSets.FirstOrDefault(fi => fi.ObjectTypeDef == objTypeDef); var mappedFields = _requestContext.GetIncludedMappedFields(outItemSet); // init scopes foreach (var scope in parentScopes) { scope.Init(objTypeDef, mappedFields); } for (int fldIndex = 0; fldIndex < mappedFields.Count; fldIndex++) { var mappedField = mappedFields[fldIndex]; var returnsComplexType = mappedField.FieldDef.Flags.IsSet(FieldFlags.ReturnsComplexType); var fieldContext = new FieldContext(_requestContext, this, mappedField, fldIndex, parentScopes); foreach (var scope in fieldContext.AllParentScopes) { if (fieldContext.BatchResultWasSet && scope.HasValue(fldIndex)) { continue; } fieldContext.CurrentScope = scope; object result = null; switch (mappedField.FieldDef.ExecutionType) { case FieldExecutionType.Reader: result = InvokeFieldReader(fieldContext, fieldContext.CurrentScope.Entity); break; case FieldExecutionType.Resolver: result = await InvokeResolverAsync(fieldContext); break; } var outValue = fieldContext.ConvertToOuputValue(result); if (!fieldContext.BatchResultWasSet) { scope.SetValue(fldIndex, outValue); } } //foreach scope // if there are any non-null object-type results, add this field context to this special list // to execute selection subsets in the next round. if (returnsComplexType && fieldContext.AllResultScopes.Count > 0) { _executedObjectFieldContexts.Add(fieldContext); } } //foreach fldIndex } //method