}         //method

        private bool SetupFieldResolverMethod(ObjectTypeDef typeDef, FieldDef field, MethodInfo resolverMethod, Attribute sourceAttr)
        {
            var retType     = resolverMethod.ReturnType;
            var returnsTask = retType.IsGenericType && retType.GetGenericTypeDefinition() == typeof(Task <>);
            Func <object, object> taskResultReader = null;

            if (returnsTask)
            {
                retType          = retType.GetGenericArguments()[0];
                taskResultReader = ReflectionHelper.CompileTaskResultReader(retType);
            }
            // validate return type
            if (!CheckReturnTypeCompatible(retType, field, resolverMethod))
            {
                return(false);
            }

            field.Resolver = new ResolverMethodInfo()
            {
                SourceAttribute = sourceAttr, Method = resolverMethod,
                ResolverClass   = resolverMethod.DeclaringType,
                ReturnsTask     = returnsTask, TaskResultReader = taskResultReader
            };
            if (returnsTask)
            {
                field.Flags |= FieldFlags.ReturnsTask;
            }
            if (typeDef is ObjectTypeDef otd && otd.TypeRole == ObjectTypeRole.Data)
            {
                field.Flags |= FieldFlags.HasParentArg;
            }
            ValidateResolverMethodArguments(typeDef, field);
            return(!_model.HasErrors);
        }
示例#2
0
        public static ObjectTypeMapping FindObjectTypeMapping(this ObjectTypeDef typeDef, Type fromType)
        {
            var mapping = typeDef.Mappings.FirstOrDefault(m => m.EntityType == fromType ||
                                                          m.EntityType.IsAssignableFrom(fromType));

            return(mapping);
        }
示例#3
0
 internal void Init(ObjectTypeDef objectTypeDef, IList <MappedField> fields)
 {
     MappedTypeDef = objectTypeDef;
     Fields        = fields;
     _values       = new object[fields.Count];
     _valuesMask   = BitSet.Create(fields.Count);
 }
 private void ReassignFieldIndexes(ObjectTypeDef typeDef)
 {
     for (int i = 0; i < typeDef.Fields.Count; i++)
     {
         typeDef.Fields[i].Index = i;
     }
 }
示例#5
0
        // 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 void RegisterSpecialObjectTypeIfProvided(Type type, ObjectTypeRole typeRole, GraphQLModule module)
        {
            if (type == null)
            {
                return;
            }
            var typeName = $"{module.Name}_{type.Name}";
            var typeDef  = new ObjectTypeDef(typeName, type, GraphQLModelObject.EmptyAttributeList, module, typeRole);

            _model.Types.Add(typeDef);
        }
        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
示例#8
0
        private ObjectTypeDef BuildRootSchemaObject(string name, ObjectTypeRole typeRole, ObjectTypeRole moduleTypeRole)
        {
            var allFields = _model.Types.OfType <ObjectTypeDef>()
                            .Where(t => t.TypeRole == moduleTypeRole)
                            .SelectMany(t => t.Fields).ToList();

            if (allFields.Count == 0)
            {
                return(null);
            }
            // TODO: add check for name duplicates
            var rootObj = new ObjectTypeDef(name, null, GraphQLModelObject.EmptyAttributeList, null, typeRole);

            rootObj.Fields.AddRange(allFields);
            RegisterTypeDef(rootObj);
            rootObj.Hidden = false;
            return(rootObj);
        }
示例#9
0
        }         //method

        private void AddTypeNameField(ObjectTypeDef objTypeDef)
        {
            var fld = new FieldDef(objTypeDef, "__typename", _stringNotNull);

            fld.Flags |= FieldFlags.Hidden;
            objTypeDef.Fields.Add(fld);
            // field mappings
            var typeName = objTypeDef.Name;
            Func <object, object> reader = obj => typeName;

            foreach (var mp in objTypeDef.Mappings)
            {
                mp.FieldResolvers.Add(new FieldResolverInfo()
                {
                    TypeMapping = mp, Field = fld, ResolverFunc = reader
                });
            }
        }
示例#10
0
        private bool AssignOperationDef(GraphQLOperation op)
        {
            ObjectTypeDef opDef = null;

            switch (op.OperationType)
            {
            case OperationType.Query: opDef = _model.QueryType; break;

            case OperationType.Mutation: opDef = _model.MutationType; break;

            case OperationType.Subscription: opDef = _model.SubscriptionType; break;
            }
            if (opDef == null)
            {
                AddError($"Operation '{op.OperationType}' is not defined in schema. Operation: '{op.Name}'.", op);
                return(false);
            }
            op.OperationTypeDef = opDef;
            return(true);
        }
示例#11
0
        private ObjectTypeDef BuildRootSchemaObject(string name, TypeRole typeRole, TypeRole moduleTypeRole)
        {
            var allModuleAggrTypes = _model.Types.OfType <ObjectTypeDef>()
                                     .Where(t => t.TypeRole == moduleTypeRole)
                                     .ToList();

            if (allModuleAggrTypes.Count == 0)
            {
                return(null);
            }
            // create root object (ex: Query type)
            var rootObjTypeDef = new ObjectTypeDef(name, null, GraphQLModelObject.EmptyAttributeList, null, typeRole);

            RegisterTypeDef(rootObjTypeDef);
            var mapping = new ObjectTypeMapping(rootObjTypeDef, null);

            rootObjTypeDef.Mappings.Add(mapping);
            // copy resolvers
            foreach (var aggrType in allModuleAggrTypes)
            {
                mapping.FieldResolvers.AddRange(aggrType.Mappings[0].FieldResolvers);
            }
            // collect all fields from collected resolvers
            var allFields = mapping.FieldResolvers.Select(fr => fr.Field).ToList();

            rootObjTypeDef.Fields.AddRange(allFields);
            // check for name duplicates
            var fieldNameDupes = rootObjTypeDef.Fields.Select(f => f.Name).GroupBy(fn => fn).Where(g => g.Count() > 1).ToList();

            if (fieldNameDupes.Count > 0)
            {
                string dupesAll = string.Join(",", fieldNameDupes.Select(g => g.Key));
                AddError($"Duplicate fields defined at top-level type {typeRole}, field names: {dupesAll}");
            }
            // important: re-assign Index value for all fields; we moved fields to aggregate Query, Mutation
            //  objects, so their indexes changed
            ReassignFieldIndexes(rootObjTypeDef);
            return(rootObjTypeDef);
        }
示例#12
0
        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);
        }
示例#13
0
        // 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
        }
示例#14
0
        // Might be called for ObjectType or Interface (for intf - just to check fields exist)
        private List <MappedSelectionItem> MapSelectionItems(IList <SelectionItem> selItems, ObjectTypeDef objectTypeDef,
                                                             IList <RequestDirective> ownerDirectives = null, bool isForUnion = false)
        {
            var mappedItems = new List <MappedSelectionItem>();

            foreach (var item in selItems)
            {
                switch (item)
                {
                case SelectionField selFld:
                    var fldDef = objectTypeDef.Fields.FirstOrDefault(f => f.Name == 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;
                    }
                    var mappedArgs = MapArguments(selFld.Args, fldDef.Args, selFld);
                    var mappedFld  = new MappedField(selFld, fldDef, mappedArgs);
                    AddRuntimeModelDirectives(mappedFld);
                    AddRuntimeRequestDirectives(mappedFld);
                    mappedItems.Add(mappedFld);
                    ValidateMappedFieldAndProcessSubset(mappedFld);
                    break;

                case FragmentSpread fs:
                    var mappedSpread = MapFragmentSpread(fs, objectTypeDef, isForUnion);
                    if (mappedSpread != null)// null is indicator of error
                    {
                        AddRuntimeRequestDirectives(mappedSpread);
                        mappedItems.Add(mappedSpread);
                    }
                    break;
                }//switch

                var allDirs = ownerDirectives.MergeLists(item.Directives);
            } //foreach item
            return(mappedItems);
        }