Packages
absinthe
1.3.0-beta.1
1.11.0
1.10.2
1.10.1
1.10.0
1.9.1
1.9.0
1.8.0
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.8
1.6.7
retired
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-rc.1
1.6.0-rc.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.5.0-rc.5
1.5.0-rc.4
1.5.0-rc.3
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.5.0-beta.2
1.5.0-beta.1
1.5.0-beta.0
1.5.0-alpha.4
1.5.0-alpha.3
1.5.0-alpha.2
1.5.0-alpha.1
1.5.0-alpha.0
1.4.16
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
retired
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.3
1.4.0-rc.2
1.4.0-rc.1
1.4.0-rc.0
1.4.0-beta.5
1.4.0-beta.4
1.4.0-beta.3
1.4.0-beta.2
1.4.0-beta.1
1.3.2
1.3.1
1.3.0
1.3.0-rc.0
1.3.0-beta.2
1.3.0-beta.1
1.3.0-beta.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.2.0-beta.0
1.2.0-alpha0
1.2.0-alpha.2
1.2.0-alpha.1
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
0.5.2
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.2.3
0.2.2
0.2.1
0.1.0
GraphQL for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/absinthe/phase/document/complexity/analysis.ex
defmodule Absinthe.Phase.Document.Complexity.Analysis do
@moduledoc false
# Analyses document complexity.
alias Absinthe.{Blueprint, Phase, Complexity}
use Absinthe.Phase
@default_complexity 1
@doc """
Run complexity analysis.
"""
@spec run(Blueprint.t, Keyword.t) :: Phase.result_t
def run(input, options \\ []) do
if Keyword.get(options, :analyze_complexity, false) do
do_run(input, options)
else
{:ok, input}
end
end
defp do_run(input, options) do
info_data = info_boilerplate(input, options)
fun = &handle_node(&1, info_data)
{:ok, Blueprint.update_current(input, &Blueprint.postwalk(&1, fun))}
end
def handle_node(%Blueprint.Document.Field{complexity: nil,
fields: fields,
argument_data: args,
schema_node: schema_node} = node, info_data) do
child_complexity = sum_complexity(fields)
case field_complexity(schema_node, args, child_complexity, info_data, node) do
complexity when is_integer(complexity) and complexity >= 0 ->
%{node | complexity: complexity}
other ->
raise Absinthe.AnalysisError, field_value_error(node, other)
end
end
def handle_node(%Blueprint.Document.Operation{complexity: nil, fields: fields} = node, _) do
complexity = sum_complexity(fields)
%{node | complexity: complexity}
end
def handle_node(node, _) do
node
end
defp field_complexity(%{complexity: nil}, _, child_complexity, _, _) do
@default_complexity + child_complexity
end
defp field_complexity(%{complexity: complexity}, arg, child_complexity, _, _)
when is_function(complexity, 2) do
complexity.(arg, child_complexity)
end
defp field_complexity(%{complexity: complexity}, arg, child_complexity, info_data, node)
when is_function(complexity, 3) do
info = struct(Complexity, Map.put(info_data, :definition, node))
complexity.(arg, child_complexity, info)
end
defp field_complexity(%{complexity: {mod, fun}}, arg, child_complexity, info_data, node) do
info = struct(Complexity, Map.put(info_data, :definition, node))
apply(mod, fun, [arg, child_complexity, info])
end
defp field_complexity(%{complexity: complexity}, _, _, _, _) do
complexity
end
defp field_value_error(field, value) do
"""
Invalid value returned from complexity analyzer.
Analyzing field:
#{field.name}
Defined at:
#{field.schema_node.__reference__.location.file}:#{field.schema_node.__reference__.location.line}
Got value:
#{inspect value}
The complexity value must be a non negative integer.
"""
end
defp sum_complexity(fields) do
Enum.reduce(fields, 0, &sum_complexity/2)
end
defp sum_complexity(%{complexity: complexity}, acc) do
complexity + acc
end
# Execution context data that's common to all fields
defp info_boilerplate(bp_root, options) do
%{
context: Keyword.get(options, :context, %{}),
root_value: Keyword.get(options, :root_value, %{}),
schema: bp_root.schema
}
end
end