private void FragmentIterator(AnalysisContext context, INode node, FragmentComplexity qDepthComplexity, double avgImpact, double currentSubSelectionImpact, double currentEndNodeImpact) { context.AssertRecursion(); if (node.Children != null && node.Children.Any( n => n is Field || (n is SelectionSet set && set.Children.Any()) || n is Operation)) { if (node is Field) { qDepthComplexity.Depth++; var impactFromArgs = GetImpactFromArgs(node); qDepthComplexity.Complexity += currentEndNodeImpact = impactFromArgs / avgImpact * currentSubSelectionImpact ?? currentSubSelectionImpact; foreach (var nodeChild in node.Children.Where(n => n is SelectionSet)) { FragmentIterator(context, nodeChild, qDepthComplexity, avgImpact, currentSubSelectionImpact * (impactFromArgs ?? avgImpact), currentEndNodeImpact); } } else { foreach (var nodeChild in node.Children) { FragmentIterator(context, nodeChild, qDepthComplexity, avgImpact, currentSubSelectionImpact, currentEndNodeImpact); } } }
private void FragmentIterator(AnalysisContext context, INode node, FragmentComplexity qDepthComplexity, double avgImpact, double currentSubSelectionImpact, double currentEndNodeImpact) { if (context.LoopCounter++ > _maxRecursionCount) { throw new InvalidOperationException("Query is too complex to validate."); } if (node.Children != null && node.Children.Any( n => n is Field || (n is SelectionSet set && set.Children.Any()) || n is Operation)) { if (node is Field) { qDepthComplexity.Depth++; var impactFromArgs = GetImpactFromArgs(node); qDepthComplexity.Complexity += currentEndNodeImpact = impactFromArgs / avgImpact * currentSubSelectionImpact ?? currentSubSelectionImpact; foreach (var nodeChild in node.Children.Where(n => n is SelectionSet)) { FragmentIterator(context, nodeChild, qDepthComplexity, avgImpact, currentSubSelectionImpact * (impactFromArgs ?? avgImpact), currentEndNodeImpact); } } else { foreach (var nodeChild in node.Children) { FragmentIterator(context, nodeChild, qDepthComplexity, avgImpact, currentSubSelectionImpact, currentEndNodeImpact); } } }
/// <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)); } var context = new AnalysisContext(); foreach (var node in doc.Children.OfType <FragmentDefinition>()) { var fragResult = new FragmentComplexity(); FragmentIterator(context, node, fragResult, avgImpact, avgImpact, 1d); context.FragmentMap[node.Name] = fragResult; } TreeIterator(context, doc, avgImpact, avgImpact, 1d); return(context.Result); }
/// <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); }