zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

no_circular_field_imports.ex (2283B)


      1 defmodule Absinthe.Phase.Schema.Validation.NoCircularFieldImports do
      2   @moduledoc false
      3 
      4   use Absinthe.Phase
      5   alias Absinthe.Blueprint
      6   alias Absinthe.Blueprint.Schema
      7 
      8   def run(blueprint, _opts) do
      9     blueprint = Blueprint.prewalk(blueprint, &validate_schema/1)
     10     {:ok, blueprint}
     11   end
     12 
     13   def validate_schema(%Schema.SchemaDefinition{type_definitions: types} = schema) do
     14     {:halt, %{schema | type_definitions: sort_and_validate_types(types)}}
     15   end
     16 
     17   def validate_schema(node), do: node
     18 
     19   def sort_and_validate_types(types) do
     20     graph = :digraph.new([:cyclic])
     21 
     22     try do
     23       _ = build_import_graph(types, graph)
     24 
     25       {types, cycles?} =
     26         Enum.reduce(types, {%{}, false}, fn type, {types, cycles?} ->
     27           if cycle = :digraph.get_cycle(graph, type.identifier) do
     28             type = type |> put_error(error(type, cycle))
     29             {Map.put(types, type.identifier, type), true}
     30           else
     31             {Map.put(types, type.identifier, type), cycles?}
     32           end
     33         end)
     34 
     35       if cycles? do
     36         Map.values(types)
     37       else
     38         graph
     39         |> :digraph_utils.topsort()
     40         |> Enum.reverse()
     41         |> Enum.flat_map(fn identifier ->
     42           case Map.fetch(types, identifier) do
     43             {:ok, type} -> [type]
     44             _ -> []
     45           end
     46         end)
     47       end
     48     after
     49       :digraph.delete(graph)
     50     end
     51   end
     52 
     53   defp error(type, deps) do
     54     %Absinthe.Phase.Error{
     55       message:
     56         String.trim("""
     57         Field Import Cycle Error
     58 
     59         Field Import in object `#{type.identifier}' `import_fields(#{inspect(type.imports)}) forms a cycle via: (#{
     60           inspect(deps)
     61         })
     62         """),
     63       locations: [type.__reference__.location],
     64       phase: __MODULE__,
     65       extra: type.identifier
     66     }
     67   end
     68 
     69   defp build_import_graph(types, graph) do
     70     Enum.each(types, &add_to_graph(&1, graph))
     71   end
     72 
     73   defp add_to_graph(type, graph) do
     74     :digraph.add_vertex(graph, type.identifier)
     75 
     76     with %{imports: imports} <- type do
     77       for {ident, _} <- imports do
     78         :digraph.add_vertex(graph, ident)
     79 
     80         case :digraph.add_edge(graph, type.identifier, ident) do
     81           {:error, _} ->
     82             raise "edge failed"
     83 
     84           _ ->
     85             :ok
     86         end
     87       end
     88     end
     89   end
     90 end