/// <summary>
        /// Validates the completed document context to ensure it is "correct" against the specification before generating
        /// the final document.
        /// </summary>
        /// <param name="context">The context containing the parsed sections of a query document..</param>
        /// <returns><c>true</c> if the rule passes, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node           = (VariableValueNode)context.ActiveNode;
            var queryOperation = context.FindContextItem <QueryOperation>();
            var queryValue     = context.FindContextItem <QueryInputValue>() as QueryVariableReferenceInputValue;

            var variable = queryOperation.Variables[node.Value.ToString()];

            variable.MarkAsReferenced();
            queryValue?.AssignVariableReference(variable);
            return(true);
        }
Example #2
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var variable = context.FindContextItem <QueryVariable>();
            var kind     = variable.GraphType?.Kind ?? TypeKind.NONE;

            switch (kind)
            {
            case TypeKind.SCALAR:
            case TypeKind.ENUM:
            case TypeKind.INPUT_OBJECT:
                return(true);

            default:
                var errorName = variable.GraphType?.Name ?? "{null}";
                var errorKind = variable.GraphType == null ? string.Empty : ", which is of kind  '{variable.GraphType.Kind.ToString()}'";
                this.ValidationError(
                    context,
                    $"Invalid Variable Graph Type. The variable named '${variable.Name}' references the graph type " +
                    $"'{errorName}'{errorKind}.  Only " +
                    $"{TypeKind.SCALAR.ToString()}, {TypeKind.ENUM.ToString()} and '{TypeKind.INPUT_OBJECT.ToString()}' are allowed for " +
                    "variable declarations.");

                return(false);
            }
        }
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var fragmnet = context.FindContextItem <QueryFragment>();

            if (string.IsNullOrEmpty(fragmnet.TargetGraphTypeName))
            {
                return(true);
            }

            // shouldn't be false at this step, but just in case fail out
            if (fragmnet.GraphType == null)
            {
                return(false);
            }

            if (!ALLOWED_TYPE_KINDS.Contains(fragmnet.GraphType.Kind))
            {
                this.ValidationError(
                    context,
                    $"The fragment declares a target graph type of '{fragmnet.GraphType.Name}' " +
                    $"of kind '{fragmnet.GraphType.Kind.ToString()}' but " +
                    $"fragments can only target graph types of kind {ALLOWED_TYPE_KIND_STRING}.");

                return(false);
            }

            return(true);
        }
Example #4
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var fragment = context.FindContextItem <QueryFragment>();

            // allow inline fragments to not have a target graph type (they inherit their parent's type)
            if (fragment.TargetGraphTypeName == string.Empty)
            {
                this.ValidationError(
                    context,
                    "Invalid Fragment. Fragments must declare a target type using the 'on' keyword.");
                return(false);
            }

            if (context.DocumentContext.Schema.KnownTypes.Contains(fragment.TargetGraphTypeName))
            {
                return(true);
            }

            this.ValidationError(
                context,
                $"The fragment declares a target type of '{fragment.TargetGraphTypeName}' but no graph type exists " +
                $"on the target schema by that name.");

            return(false);
        }
        /// <summary>
        /// Executes the construction step the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            // at this stage we know thta we've encountered a complexvalue node
            // we can also garuntee that the active input value on the request is going to be the value container
            // for that ComplexvalueNode. It is to that container that we are adding a new argument.
            //
            // take for instance this sequence:
            //
            //      field(arg1: {childArg1: "value"  childArg2: value} )
            //
            // we are pointing at the argument "arg1"
            // which is a complexargument type having a value of QueryComplexInputValue which is a container of arguments
            // it is to that container that we are adding this new argument "childArg1" indicated by this InputItemNode
            // on the context.
            //
            // Note: this operation could be nested N levels deep such as with
            //       field(arg1: { childArg1:  {subChildArg1: value, subChildArg1: value} childArg2: 5} )
            // the scenario would be valid for:
            //      adding childArg1 or childArg2 to arg1
            //      adding subChildArg1 or subChildArg2 to childArg1
            var node        = (InputItemNode)context.ActiveNode;
            var inputObject = context.FindContextItem <QueryInputValue>() as QueryComplexInputValue;

            var ownerGraphType = inputObject.OwnerArgument.GraphType as IInputObjectGraphType;
            var field          = ownerGraphType.Fields[node.InputName.ToString()];
            var graphType      = context.DocumentContext.Schema.KnownTypes.FindGraphType(field);

            var argument = new QueryInputArgument(node, graphType, field.TypeExpression);

            context.AddDocumentPart(argument);
            return(true);
        }
Example #6
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node           = (DirectiveNode)context.ActiveNode;
            var queryDirective = context.FindContextItem <QueryDirective>();

            if (queryDirective == null)
            {
                return(false);
            }

            var location = node.ParentNode?.DirectiveLocation();

            if (!location.HasValue || !queryDirective.Directive.Locations.HasFlag(location))
            {
                var locationName     = location.HasValue ? location.Value.ToString() : "unknown";
                var allowedLocations = queryDirective.Directive.Locations.GetIndividualFlags <DirectiveLocation>();

                var allowedString = string.Join(", ", allowedLocations.Select(x => x.ToString()));
                this.ValidationError(
                    context,
                    $"Invalid directive location. Attempted use of '{queryDirective.Directive.Name}' at location '{locationName}'. " +
                    $"Allowed Locations:  {allowedString}");
            }

            return(true);
        }
        /// <summary>
        /// Executes the construction step the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var variable  = context.FindContextItem <QueryVariable>();
            var graphType = context.DocumentContext.Schema.KnownTypes.FindGraphType(variable.TypeExpression.TypeName);

            variable.AttachGraphType(graphType);
            return(true);
        }
Example #8
0
        /// <summary>
        /// Executes the construction step the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node         = (InputItemNode)context.ActiveNode;
            var argument     = context.FindContextItem <QueryInputArgument>();
            var complexValue = context.FindContextItem <QueryInputValue>() as QueryComplexInputValue;

            if (complexValue.Arguments.ContainsKey(node.InputName.ToString()))
            {
                this.ValidationError(
                    context,
                    $"Fields on input objects must be unique. The supplied value for argument '{argument.Name}' " +
                    $"defines '{node.InputName.ToString()}' more than once.");

                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Executes the construction step the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node           = (InputItemNode)context.ActiveNode;
            var queryDirective = context.FindContextItem <QueryDirective>();

            var fieldArg  = queryDirective.Directive.Arguments[node.InputName.ToString()];
            var graphType = context.DocumentContext.Schema.KnownTypes.FindGraphType(fieldArg.TypeExpression.TypeName);
            var argument  = new QueryInputArgument(node, graphType, fieldArg.TypeExpression);

            context.AddDocumentPart(argument);

            return(true);
        }
Example #10
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node     = (FieldNode)context.ActiveNode;
            var newField = context.FindContextItem <FieldSelection>();

            // do a fast lookup before enumerating the field selection to determine
            // if there would even be a name collision.
            if (!context.SelectionSet.ContainsAlias(node.FieldAlias))
            {
                return(true);
            }

            var isValid        = true;
            var existingFields = context.SelectionSet.FindFieldsOfAlias(node.FieldAlias);

            foreach (var existingField in existingFields)
            {
                // we may iterate through the field we are adding, it can exist with itself
                // just skip it
                if (existingField == newField)
                {
                    continue;
                }

                // fields with the same name in a given context
                // but targeting non-intersecting types can safely co-exist
                // in the same selection set.
                if (this.CanCoExist(context.DocumentContext.Schema, context.SelectionSet, existingField, newField))
                {
                    continue;
                }

                // fields that could cause a name collision for a type
                // must be mergable (i.e. have the same shape/signature).
                if (this.AreSameShape(existingField, newField))
                {
                    continue;
                }

                this.ValidationError(
                    context,
                    $"The selection set already contains a field with a name or alias of '{newField.Node.FieldAlias.ToString()}'. " +
                    "An attempt was made to add another field with the same name or alias to the selection set but with a different " +
                    "return graph type or input arguments. Fields with the same output name must have identicial signatures " +
                    "within a single selection set.");

                isValid = false;
            }

            return(isValid);
        }
Example #11
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node      = (InputItemNode)context.ActiveNode;
            var directive = context.FindContextItem <QueryDirective>();

            if (directive.Arguments.ContainsKey(node.InputName))
            {
                this.ValidationError(
                    context,
                    $"The directive '{directive.Name}' already contains an input argument named '{node.InputName.ToString()}'. Input arguments " +
                    "must be unique per directive instance.");
                return(false);
            }

            return(true);
        }
Example #12
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node           = (InputItemNode)context.ActiveNode;
            var fieldSelection = context.FindContextItem <FieldSelection>();

            if (!fieldSelection.Field.Arguments.ContainsKey(node.InputName.ToString()))
            {
                this.ValidationError(
                    context,
                    $"The field '{fieldSelection.Name}' does not define an input argument named '{node.InputName.ToString()}'. Input arguments " +
                    $"must be defined on the field in the target schema.");
                return(false);
            }

            return(true);
        }
Example #13
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node           = (InputItemNode)context.ActiveNode;
            var fieldSelection = context.FindContextItem <FieldSelection>();

            if (fieldSelection.Arguments.ContainsKey(node.InputName))
            {
                this.ValidationError(
                    context,
                    $"The field '{fieldSelection.Name}' already contains an input argument named '{node.InputName.ToString()}'. Input arguments " +
                    $"must be unique per field instance.");
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var queryVariable = context.FindContextItem <QueryVariable>();

            if (!queryVariable.TypeExpression.IsValid)
            {
                this.ValidationError(
                    context,
                    "Unknown Graph Type. Could not determine the graph type expression of the variable " +
                    $"named '{queryVariable.Name}'. Double check that your variable declaration is correct.");

                return(false);
            }

            return(true);
        }
Example #15
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node           = (InputItemNode)context.ActiveNode;
            var queryDirective = context.FindContextItem <QueryDirective>();

            if (!queryDirective.Directive.Arguments.ContainsKey(node.InputName.ToString()))
            {
                this.ValidationError(
                    context,
                    $"The directive '{queryDirective.Name}' does not define an input argument named '{node.InputName.ToString()}'. " +
                    $"Input arguments must be defined on the directive in the target schema.");
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var field = context.FindContextItem <FieldSelection>();

            if (field.GraphType.Kind.IsLeafKind() && context.ActiveNode.Children.Any <FieldCollectionNode>())
            {
                this.ValidationError(
                    context,
                    $"The graph type '{field.GraphType.Name}' is of kind '{field.GraphType.Kind.ToString()}'. It cannot declare a fieldset " +
                    "to return.");

                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var queryFragment = context.FindContextItem <QueryFragment>();

            // ensure that the named fragment's target type (if there is one) exists in the schema nad assign it to the query
            // fragment object if it doesnt exist mark this fragment as failed
            var graphtype = context.DocumentContext.Schema.KnownTypes.FindGraphType(queryFragment.TargetGraphTypeName);

            if (graphtype == null)
            {
                return(false);
            }

            queryFragment.GraphType = graphtype;
            context.DocumentScope?.RestrictFieldsToGraphType(queryFragment.GraphType);
            return(true);
        }
        /// <summary>
        /// Executes the construction step the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node     = (InputItemNode)context.ActiveNode;
            var argument = context.FindContextItem <QueryInputArgument>();

            // represents a field on a complex object argument
            // ensures that the field exists in the graphtype of the argument
            if (!(argument.GraphType is IInputObjectGraphType inputGraphType) || !inputGraphType.Fields.ContainsKey(node.InputName.ToString()))
            {
                this.ValidationError(
                    context,
                    $"The {argument.GraphType.Kind.ToString()} type '{argument.GraphType.Name}' does not define a field named '{node.InputName.ToString()}'.");

                return(false);
            }

            return(true);
        }
Example #19
0
        /// <summary>
        /// Validates the completed document context to ensure it is "correct" against the specification before generating
        /// the final document.
        /// </summary>
        /// <param name="context">The context containing the parsed sections of a query document..</param>
        /// <returns><c>true</c> if the rule passes, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node           = (VariableValueNode)context.ActiveNode;
            var queryOperation = context.FindContextItem <QueryOperation>();

            var variableName = node.Value.ToString();

            if (queryOperation.Variables == null || !queryOperation.Variables.ContainsKey(variableName))
            {
                this.ValidationError(
                    context,
                    $"The variable named '${variableName}' is not declared for the current operation.");

                return(false);
            }

            return(true);
        }
Example #20
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var queryDirective = context.FindContextItem <QueryDirective>();

            if (context.DocumentScope.Directives.Count(x =>
                                                       x.Directive.Name == queryDirective.Directive.Name &&
                                                       x.Directive.Locations.HasFlag(queryDirective.Location)) > 1)
            {
                this.ValidationError(
                    context,
                    $"The directive '{queryDirective.Name}' is already defined in this location. Directives must be unique per " +
                    "instantiated location (e.g. once per field, once per input argument etc.).");

                return(false);
            }

            return(true);
        }
Example #21
0
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var variable = context.FindContextItem <QueryVariable>();

            var graphType = context.DocumentContext.Schema.KnownTypes.FindGraphType(variable.TypeExpression.TypeName);

            if (graphType == null)
            {
                this.ValidationError(
                    context,
                    $"Unknown Variable Graph Type. The variable named '{variable?.Name}' declares " +
                    $"itself as a graph type of '{variable.TypeExpression}' but that graph type does not " +
                    "exist in the schema.");

                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Validates the specified node to ensure it is "correct" in the context of the rule doing the valdiation.
        /// </summary>
        /// <param name="context">The validation context encapsulating a <see cref="SyntaxNode" /> that needs to be validated.</param>
        /// <returns><c>true</c> if the node is valid, <c>false</c> otherwise.</returns>
        public override bool Execute(DocumentConstructionContext context)
        {
            var node      = (VariableNode)context.ActiveNode;
            var operation = context.FindContextItem <QueryOperation>();

            if (operation?.Variables != null)
            {
                if (operation.Variables.ContainsKey(node.Name.ToString()))
                {
                    this.ValidationError(
                        context,
                        $"Duplicate Variable Name. The variable named '{node.Name.ToString()}' must be unique " +
                        "in its contained operation. Ensure that all variable names, per operation, are unique (case-sensitive).");
                    return(false);
                }
            }

            return(true);
        }
Example #23
0
 /// <summary>
 /// Determines whether this instance can process the given context. The rule will have no effect on the node if it cannot
 /// process it.
 /// </summary>
 /// <param name="context">The context that may be acted upon.</param>
 /// <returns><c>true</c> if this instance can validate the specified node; otherwise, <c>false</c>.</returns>
 public override bool ShouldExecute(DocumentConstructionContext context)
 {
     return(base.ShouldExecute(context) && context.FindContextItem <QueryOperation>().OperationType == GraphCollection.Subscription);
 }
Example #24
0
 /// <summary>
 /// Determines whether this instance can process the given context. The rule will have no effect on the input argument if it cannot
 /// process it.
 /// </summary>
 /// <param name="context">The context that may be acted upon.</param>
 /// <returns><c>true</c> if this instance can validate the specified input argument; otherwise, <c>false</c>.</returns>
 public override bool ShouldExecute(DocumentConstructionContext context)
 {
     return(base.ShouldExecute(context) &&
            context.ActiveNode.ParentNode?.ParentNode is ComplexValueNode &&
            context.FindContextItem <QueryInputValue>() is QueryComplexInputValue);
 }
 /// <summary>
 /// Determines whether this instance can process the given context. The rule will have no effect on the node if it cannot
 /// process it.
 /// </summary>
 /// <param name="context">The context that may be acted upon.</param>
 /// <returns><c>true</c> if this instance can validate the specified node; otherwise, <c>false</c>.</returns>
 public override bool ShouldExecute(DocumentConstructionContext context)
 {
     return(base.ShouldExecute(context) && context.FindContextItem <QueryInputValue>() is QueryVariableReferenceInputValue);
 }