예제 #1
0
        /// <summary>
        /// Instantiates the graph field according to the data provided.
        /// </summary>
        /// <param name="formatter">The formatter.</param>
        /// <param name="template">The template.</param>
        /// <param name="securityGroups">The security groups.</param>
        /// <returns>MethodGraphField.</returns>
        protected virtual MethodGraphField InstantiateField(
            GraphNameFormatter formatter,
            IGraphTypeFieldTemplate template,
            List <FieldSecurityGroup> securityGroups)
        {
            switch (template.FieldSource)
            {
            case GraphFieldTemplateSource.Method:
            case GraphFieldTemplateSource.Action:
                return(new MethodGraphField(
                           formatter.FormatFieldName(template.Name),
                           template.TypeExpression.CloneTo(formatter.FormatGraphTypeName(template.TypeExpression.TypeName)),
                           template.Route,
                           template.Mode,
                           template.CreateResolver(),
                           securityGroups));

            case GraphFieldTemplateSource.Property:
                return(new PropertyGraphField(
                           formatter.FormatFieldName(template.Name),
                           template.TypeExpression.CloneTo(formatter.FormatGraphTypeName(template.TypeExpression.TypeName)),
                           template.Route,
                           template.DeclaredReturnType,
                           template.DeclaredName,
                           template.Mode,
                           template.CreateResolver(),
                           securityGroups));

            default:
                throw new ArgumentOutOfRangeException($"Template field source of {template.FieldSource.ToString()} is not supported by {this.GetType().FriendlyName()}.");
            }
        }
예제 #2
0
        private IGraphField MakeGraphField(IGraphTypeFieldTemplate fieldTemplate)
        {
            var testServer = new TestServerBuilder().Build();
            var maker      = new GraphFieldMaker(testServer.Schema);

            return(maker.CreateField(fieldTemplate).Field);
        }
예제 #3
0
        /// <summary>
        /// Adds the type extension to the schema for the configured concrete type. If the type
        /// is not registered to the schema the field extension is queued for when it is added (if ever).
        /// </summary>
        /// <param name="extension">The extension to add.</param>
        private void AddTypeExtension(IGraphTypeFieldTemplate extension)
        {
            var fieldMaker  = new GraphFieldMaker(this.Schema);
            var fieldResult = fieldMaker.CreateField(extension);

            if (fieldResult != null)
            {
                this.Schema.KnownTypes.EnsureGraphFieldExtension(extension.SourceObjectType, fieldResult.Field);
                this.EnsureDependents(fieldResult);
            }
        }
        /// <summary>
        /// Inspects the root and ensures that any intermediate, virtual fields
        /// are accounted for and returns a reference to the immediate parent this action should be added to.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <returns>IGraphField.</returns>
        private IObjectGraphType AddOrRetrieveControllerRoutePath(IGraphTypeFieldTemplate action)
        {
            var pathSegments = action.Route.GenerateParentPathSegments();

            // loop through all parent path parts of this action
            // creating virtual fields as necessary or using existing ones and adding on to them
            IObjectGraphType parentType = this.Schema.OperationTypes[action.Route.RootCollection];

            for (var i = 0; i < pathSegments.Count; i++)
            {
                var segment       = pathSegments[i];
                var formattedName = _formatter.FormatFieldName(segment.Name);
                if (parentType.Fields.ContainsKey(formattedName))
                {
                    var field     = parentType[formattedName];
                    var foundType = Schema.KnownTypes.FindGraphType(field.TypeExpression.TypeName);

                    var ogt = foundType as IObjectGraphType;
                    if (ogt != null)
                    {
                        if (ogt.IsVirtual)
                        {
                            parentType = ogt;
                            continue;
                        }

                        throw new GraphTypeDeclarationException(
                                  $"The action '{action.Route}' attempted to nest itself under the {foundType.Kind} graph type '{foundType.Name}', which is returned by " +
                                  $"the route '{field.Route}'.  Actions can only be added to virtual graph types created by their parent controller.");
                    }

                    if (foundType != null)
                    {
                        throw new GraphTypeDeclarationException(
                                  $"The action '{action.Route.Path}' attempted to nest itself under the graph type '{foundType.Name}'. {foundType.Kind} graph types cannot " +
                                  "accept fields.");
                    }
                    else
                    {
                        throw new GraphTypeDeclarationException(
                                  $"The action '{action.Route.Path}' attempted to nest itself under the field '{field.Route}' but no graph type was found " +
                                  "that matches its type.");
                    }
                }

                parentType = this.CreateVirtualFieldOnParent(
                    parentType,
                    formattedName,
                    segment,
                    i == 0 ? action.Parent : null);
            }

            return(parentType);
        }
예제 #5
0
        /// <summary>
        /// Iterates the given <see cref="ControllerActionGraphFieldTemplate" /> and adds
        /// all found types to the type system for this <see cref="ISchema" />. Generates
        /// a field reference on the provided parent with a resolver pointing to the provided graph action.
        /// </summary>
        /// <param name="parentField">The parent which will own the generated action field.</param>
        /// <param name="action">The action.</param>
        private void AddActionAsField(IObjectGraphType parentField, IGraphTypeFieldTemplate action)
        {
            // apend the action as a field on the parent
            var maker       = new GraphFieldMaker(this.Schema);
            var fieldResult = maker.CreateField(action);

            if (fieldResult != null)
            {
                parentField.Extend(fieldResult.Field);
                this.EnsureDependents(fieldResult);
            }
        }
예제 #6
0
        /// <summary>
        /// Creates a single graph field from the provided template using hte rules of this maker and the contained schema.
        /// </summary>
        /// <param name="template">The template to generate a field from.</param>
        /// <returns>IGraphField.</returns>
        public GraphFieldCreationResult CreateField(IGraphTypeFieldTemplate template)
        {
            var formatter = _schema.Configuration.DeclarationOptions.GraphNamingFormatter;
            var result    = new GraphFieldCreationResult();

            // if the owner of this field declared top level objects append them to the
            // field for evaluation
            var securityGroups = new List <FieldSecurityGroup>();

            if (template.Parent?.SecurityPolicies?.Count > 0)
            {
                securityGroups.Add(template.Parent.SecurityPolicies);
            }

            if (template.SecurityPolicies?.Count > 0)
            {
                securityGroups.Add(template.SecurityPolicies);
            }

            MethodGraphField field = this.InstantiateField(formatter, template, securityGroups);

            field.Description       = template.Description;
            field.IsDeprecated      = template.IsDeprecated;
            field.DeprecationReason = template.DeprecationReason;
            field.Complexity        = template.Complexity;
            field.FieldSource       = template.FieldSource;

            if (template.Arguments != null)
            {
                var argumentMaker = new GraphArgumentMaker(_schema);
                foreach (var argTemplate in template.Arguments)
                {
                    var argumentResult = argumentMaker.CreateArgument(argTemplate);
                    field.Arguments.AddArgument(argumentResult.Argument);

                    result.MergeDependents(argumentResult);
                }
            }

            result.AddDependentRange(template.RetrieveRequiredTypes());

            if (template.UnionProxy != null)
            {
                var unionMaker = new UnionGraphTypeMaker(_schema);
                result.AddDependent(unionMaker.CreateGraphType(template.UnionProxy, template.Kind));
            }

            result.Field = field;
            return(result);
        }
 /// <summary>
 /// Adds the <see cref="ControllerActionGraphFieldTemplate"/> to the schema. Any required parent fields
 /// will be automatically created if necessary to ensure proper nesting.
 /// </summary>
 /// <param name="action">The action to add to the schema.</param>
 private void AddAction(IGraphTypeFieldTemplate action)
 {
     if (this.Schema.Configuration.DeclarationOptions.AllowedOperations.Contains(action.Route.RootCollection))
     {
         this.EnsureGraphOperationType(action.Route.RootCollection);
         var parentField = this.AddOrRetrieveControllerRoutePath(action);
         this.AddActionAsField(parentField, action);
     }
     else
     {
         throw new ArgumentOutOfRangeException(
                   nameof(action),
                   $"The '{action.InternalFullName}' action's operation root ({action.Route.RootCollection}) is not " +
                   $"allowed by the schema's current configuration (Schema: {this.Schema.Name}).");
     }
 }
예제 #8
0
        /// <summary>
        /// Adds the <see cref="ControllerActionGraphFieldTemplate"/> to the schema. Any required parent fields
        /// will be automatically created if necessary to ensure proper nesting.
        /// </summary>
        /// <param name="action">The action to add to the schema.</param>
        private void AddAction(IGraphTypeFieldTemplate action)
        {
            switch (action.Route.RootCollection)
            {
            case GraphCollection.Query:
            case GraphCollection.Mutation:
                this.EnsureGraphOperationType(action.Route.RootCollection);
                var parentField = this.AddOrRetrieveRoutePath(action);
                this.AddActionAsField(parentField, action);
                break;

            default:
                throw new ArgumentOutOfRangeException(
                          nameof(action),
                          $"The '{action.InternalFullName}' action's operation root ({action.Route.RootCollection}) is not " +
                          $"supported.");
            }
        }
        /// <summary>
        /// Iterates the given <see cref="ControllerActionGraphFieldTemplate" /> and adds
        /// all found types to the type system for this <see cref="ISchema" />. Generates
        /// a field reference on the provided parent with a resolver pointing to the provided graph action.
        /// </summary>
        /// <param name="parentType">The parent which will own the generated action field.</param>
        /// <param name="action">The action.</param>
        private void AddActionAsField(IObjectGraphType parentType, IGraphTypeFieldTemplate action)
        {
            // apend the action as a field on the parent
            var maker       = GraphQLProviders.GraphTypeMakerProvider.CreateFieldMaker(this.Schema);
            var fieldResult = maker.CreateField(action);

            if (fieldResult != null)
            {
                if (parentType.Fields.ContainsKey(fieldResult.Field.Name))
                {
                    throw new GraphTypeDeclarationException(
                              $"The '{parentType.Kind}' graph type '{parentType.Name}' already contains a field named '{fieldResult.Field.Name}'. " +
                              $"The action method '{action.InternalFullName}' cannot be added to the graph type with the same name.");
                }

                parentType.Extend(fieldResult.Field);
                this.EnsureDependents(fieldResult);
            }
        }
        /// <summary>
        /// Instantiates the graph field according to the data provided.
        /// </summary>
        /// <param name="formatter">The formatter.</param>
        /// <param name="template">The template.</param>
        /// <param name="securityGroups">The security groups.</param>
        /// <returns>MethodGraphField.</returns>
        protected override MethodGraphField InstantiateField(
            GraphNameFormatter formatter,
            IGraphTypeFieldTemplate template,
            List <FieldSecurityGroup> securityGroups)
        {
            var subTemplate = template as ControllerSubscriptionActionGraphFieldTemplate;

            if (subTemplate != null &&
                subTemplate.FieldSource == GraphFieldTemplateSource.Action &&
                subTemplate.Route.RootCollection == GraphCollection.Subscription)
            {
                return(new SubscriptionMethodGraphField(
                           formatter.FormatFieldName(template.Name),
                           template.TypeExpression.CloneTo(formatter.FormatGraphTypeName(template.TypeExpression.TypeName)),
                           template.Route,
                           template.Mode,
                           template.CreateResolver(),
                           securityGroups,
                           subTemplate.EventName));
            }

            return(base.InstantiateField(formatter, template, securityGroups));
        }
예제 #11
0
        /// <summary>
        /// Inspects the root and ensures that any intermediate, virtual fields
        /// are accounted for and returns a reference to the immediate parent this action should be added to.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <returns>IGraphField.</returns>
        private IObjectGraphType AddOrRetrieveRoutePath(IGraphTypeFieldTemplate action)
        {
            var pathSegments = action.Route.GenerateParentPathSegments();

            // loop through all parent path parts of this action
            // creating virtual fields as necessary or using existing ones and adding on to them
            IObjectGraphType parentType = this.Schema.OperationTypes[action.Route.RootCollection];

            for (var i = 0; i < pathSegments.Count; i++)
            {
                var segment       = pathSegments[i];
                var formattedName = _formatter.FormatFieldName(segment.Name);
                if (parentType.Fields.ContainsKey(formattedName))
                {
                    var field     = parentType[formattedName];
                    var foundType = Schema.KnownTypes.FindGraphType(field.TypeExpression.TypeName);
                    if (foundType is IObjectGraphType ogt)
                    {
                        parentType = ogt;
                        continue;
                    }

                    throw new GraphTypeDeclarationException(
                              $"The action '{action.Name}' attempted to nest itself under the grpah type '{foundType?.Name}' but the graph type " +
                              "does not exist or does not accept fields.");
                }

                var fieldType = this.CreateVirtualFieldOnParent(
                    parentType,
                    formattedName,
                    segment,
                    i == 0 ? action.Parent : null);
                parentType = fieldType;
            }

            return(parentType);
        }
예제 #12
0
        /// <summary>
        /// Creates a single graph field from the provided template using hte rules of this maker and the contained schema.
        /// </summary>
        /// <param name="template">The template to generate a field from.</param>
        /// <returns>IGraphField.</returns>
        public GraphFieldCreationResult CreateField(IGraphTypeFieldTemplate template)
        {
            var formatter = _schema.Configuration.DeclarationOptions.GraphNamingFormatter;
            var result    = new GraphFieldCreationResult();

            // if the owner of this field declared top level objects append them to the
            // field for evaluation
            var securityGroups = new List <FieldSecurityGroup>();

            if (template.Parent?.SecurityPolicies?.Count > 0)
            {
                securityGroups.Add(template.Parent.SecurityPolicies);
            }

            if (template.SecurityPolicies?.Count > 0)
            {
                securityGroups.Add(template.SecurityPolicies);
            }

            MethodGraphField field = null;

            switch (template.FieldSource)
            {
            case GraphFieldTemplateSource.Method:
            case GraphFieldTemplateSource.Action:
                field = new MethodGraphField(
                    formatter.FormatFieldName(template.Name),
                    template.TypeExpression.CloneTo(formatter.FormatGraphTypeName(template.TypeExpression.TypeName)),
                    template.Route,
                    template.Mode,
                    template.CreateResolver(),
                    securityGroups);
                break;

            case GraphFieldTemplateSource.Property:
                field = new PropertyGraphField(
                    formatter.FormatFieldName(template.Name),
                    template.TypeExpression.CloneTo(formatter.FormatGraphTypeName(template.TypeExpression.TypeName)),
                    template.Route,
                    template.DeclaredReturnType,
                    template.DeclaredName,
                    template.Mode,
                    template.CreateResolver(),
                    securityGroups);
                break;
            }

            field.Description       = template.Description;
            field.IsDeprecated      = template.IsDeprecated;
            field.DeprecationReason = template.DeprecationReason;
            field.Complexity        = template.Complexity;
            field.FieldSource       = template.FieldSource;

            if (template.Arguments != null)
            {
                var argumentMaker = new GraphArgumentMaker(_schema);
                foreach (var argTemplate in template.Arguments)
                {
                    var argumentResult = argumentMaker.CreateArgument(argTemplate);
                    field.Arguments.AddArgument(argumentResult.Argument);

                    result.MergeDependents(argumentResult);
                }
            }

            result.AddDependentRange(template.RetrieveRequiredTypes());

            if (template.UnionProxy != null)
            {
                var unionMaker = new UnionGraphTypeMaker(_schema);
                result.AddDependent(unionMaker.CreateGraphType(template.UnionProxy, template.Kind));
            }

            result.Field = field;
            return(result);
        }