Packages
absinthe
1.3.0-beta.0
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/traversal.ex
defmodule Absinthe.Traversal do
# Graph traversal utilities for dealing with ASTs and schemas using the
# `Absinthe.Traversal.Node` protocol.
# Note this really only exists to handle some Schema rules stuff and is generally
# considered legacy code. See `Absinthe.Blueprint.Transform` for information
# on how to walk blueprint trees.
@moduledoc false
alias __MODULE__
alias Absinthe.Traversal.Node
@type t :: %__MODULE__{context: any, seen: [Node.t], path: [Node.t]}
defstruct context: nil, seen: [], path: []
# Instructions defining behavior during traversal
# * `{:ok, value, traversal}`: The value of the node is `value`, and traversal
# should continue to children (using `traversal`)
# * `{:prune, value, traversal}`: The value of the node is `value` and
# traversal should NOT continue to children, but to siblings (using
# `traversal`)
# * `{:error, message}`: Bad stuff happened, explained by `message`
@type instruction_t :: {:ok, any, t} | {:prune, any, t} | {:error, any}
# Traverse, reducing nodes using a given function to evaluate their value.
@doc false
@spec reduce(Node.t, any, acc, (Node.t, t, acc -> instruction_t)) :: acc when acc: var
def reduce(node, context, initial_value, node_evaluator) do
{result, _traversal} = do_reduce(node, %Traversal{context: context}, initial_value, node_evaluator)
result
end
# Reduce using a traversal struct
@spec do_reduce(Node.t, t, acc, (Node.t, t, acc -> instruction_t)) :: {acc, t} when acc: var
defp do_reduce(node, traversal, initial_value, node_evaluator) do
if seen?(traversal, node) do
{initial_value, traversal}
else
case node_evaluator.(node, traversal, initial_value) do
{:ok, value, next_traversal} ->
reduce_children(node, next_traversal |> put_seen(node), value, node_evaluator)
{:prune, value, next_traversal} ->
{value, next_traversal |> put_seen(node)}
end
end
end
# Traverse a node's children
@spec reduce_children(Node.t, t, acc, (Node.t, t, acc -> instruction_t)) :: {acc, t} when acc: var
defp reduce_children(node, traversal, initial, node_evalator) do
Enum.reduce(Node.children(node, traversal), {initial, traversal}, fn
child, {this_value, this_traversal} ->
do_reduce(child, this_traversal, this_value, node_evalator)
end)
end
@spec seen?(t, Node.t) :: boolean
defp seen?(traversal, node), do: traversal.seen |> Enum.member?(node)
@spec put_seen(t, Node.t) :: t
defp put_seen(traversal, node) do
%{traversal | seen: [node | traversal.seen]}
end
end