private static void RecordFieldComplexity(INode node, ComplexityResult result, double impact)
 {
     result.Complexity += impact;
     if (result.ComplexityMap.ContainsKey(node))
     {
         result.ComplexityMap[node] += impact;
     }
     else
     {
         result.ComplexityMap.Add(node, impact);
     }
 }
Exemple #2
0
        private void TreeIterator(INode node, ComplexityResult result, double avgImpact, double currentSubSelectionImpact, double currentEndNodeImpact)
        {
            if (_loopCounter++ > _maxRecursionCount)
            {
                _loopCounter = 0;
                throw new InvalidOperationException("Query is too complex to validate.");
            }
            if (node is FragmentDefinition)
            {
                return;
            }

            if (node.Children != null &&
                node.Children.Any(n => n is Field || n is FragmentSpread || (n is SelectionSet && ((SelectionSet)n).Children.Any()) || n is Operation))
            {
                if (node is Field)
                {
                    result.TotalQueryDepth++;
                    var impactFromArgs = GetImpactFromArgs(node);
                    RecordFieldComplexity(node, result, currentEndNodeImpact = impactFromArgs / avgImpact * currentSubSelectionImpact ?? currentSubSelectionImpact);
                    foreach (var nodeChild in node.Children.Where(n => n is SelectionSet))
                    {
                        TreeIterator(nodeChild, result, avgImpact, currentSubSelectionImpact * (impactFromArgs ?? avgImpact), currentEndNodeImpact);
                    }
                }
                else
                {
                    foreach (var nodeChild in node.Children)
                    {
                        TreeIterator(nodeChild, result, avgImpact, currentSubSelectionImpact, currentEndNodeImpact);
                    }
                }
            }
            else if (node is Field)
            {
                RecordFieldComplexity(node, result, currentEndNodeImpact);
            }
            else if (node is FragmentSpread)
            {
                var fragmentComplexity = _fragmentMap[((FragmentSpread)node).Name];
                RecordFieldComplexity(node, result, currentSubSelectionImpact / avgImpact * fragmentComplexity.Complexity);
                result.TotalQueryDepth += fragmentComplexity.Depth;
            }
        }
        /// <summary>
        /// Analyzes the complexity of a document.
        /// </summary>
        internal ComplexityResult Analyze(Document doc, double avgImpact = 2.0d)
        {
            if (avgImpact <= 1)
            {
                throw new ArgumentOutOfRangeException(nameof(avgImpact));
            }

            doc.Children.Where(node => node is FragmentDefinition).Apply(node =>
            {
                var fragResult = new FragmentComplexity();
                FragmentIterator(node, fragResult, avgImpact, avgImpact, 1d);
                _fragmentMap[(node as FragmentDefinition)?.Name] = fragResult;
            });

            TreeIterator(doc, _result, avgImpact, avgImpact, 1d);

            // Cleanup in case Analyze is called again
            _loopCounter = 0;
            var retVal = _result;

            _result = new ComplexityResult();

            return(retVal);
        }
        protected virtual void Analyzed(Document document, ComplexityConfiguration complexityParameters, ComplexityResult complexityResult)
        {
#if DEBUG
            Debug.WriteLine($"Complexity: {complexityResult.Complexity}");
            Debug.WriteLine($"Sum(Query depth across all subqueries) : {complexityResult.TotalQueryDepth}");
            foreach (var node in complexityResult.ComplexityMap)
            {
                Debug.WriteLine($"{node.Key} : {node.Value}");
            }
#endif
        }