zf

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

schema.ex (8191B)


      1 defmodule Absinthe.Blueprint.Schema do
      2   @moduledoc false
      3 
      4   alias __MODULE__
      5 
      6   alias Absinthe.Blueprint
      7 
      8   @type directive_t :: Schema.DirectiveDefinition.t()
      9 
     10   @type type_t ::
     11           Blueprint.Schema.EnumTypeDefinition.t()
     12           | Blueprint.Schema.InputObjectTypeDefinition.t()
     13           | Blueprint.Schema.InterfaceTypeDefinition.t()
     14           | Blueprint.Schema.ObjectTypeDefinition.t()
     15           | Blueprint.Schema.ScalarTypeDefinition.t()
     16           | Blueprint.Schema.UnionTypeDefinition.t()
     17 
     18   @type t ::
     19           Blueprint.Schema.EnumValueDefinition.t()
     20           | Blueprint.Schema.InputValueDefinition.t()
     21           | Blueprint.Schema.SchemaDeclaration.t()
     22           | Blueprint.Schema.SchemaDefinition.t()
     23           | type_t()
     24           | directive_t()
     25 
     26   @doc """
     27   Lookup a type definition that is part of a schema.
     28   """
     29   @spec lookup_type(Blueprint.t(), atom) :: nil | Blueprint.Schema.t()
     30   def lookup_type(blueprint, identifier) do
     31     blueprint.schema_definitions
     32     |> List.first()
     33     |> Map.get(:type_definitions)
     34     |> Enum.find(fn
     35       %{identifier: ^identifier} ->
     36         true
     37 
     38       _ ->
     39         false
     40     end)
     41   end
     42 
     43   @doc """
     44   Lookup a directive definition that is part of a schema.
     45   """
     46   @spec lookup_directive(Blueprint.t(), atom) :: nil | Blueprint.Schema.directive_t()
     47   def lookup_directive(blueprint, identifier) do
     48     blueprint.schema_definitions
     49     |> List.first()
     50     |> Map.get(:directive_definitions)
     51     |> Enum.find(fn
     52       %{identifier: ^identifier} ->
     53         true
     54 
     55       _ ->
     56         false
     57     end)
     58   end
     59 
     60   def functions(module) do
     61     if function_exported?(module, :functions, 0) do
     62       module.functions
     63     else
     64       []
     65     end
     66   end
     67 
     68   def build([%Absinthe.Blueprint{} = bp | attrs]) do
     69     build_types(attrs, [bp], [])
     70   end
     71 
     72   defp build_types([], [bp], buffer) do
     73     if buffer != [] do
     74       raise """
     75       Unused buffer! #{inspect(buffer)}
     76       """
     77     end
     78 
     79     Map.update!(bp, :schema_definitions, &Enum.reverse/1)
     80   end
     81 
     82   # this rather insane scheme lets interior macros get back out to exterior
     83   # scopes so that they can define top level entities as necessary, and then
     84   # return to the regularly scheduled programming.
     85   defp build_types([:stash | rest], [head | tail], buff) do
     86     build_types(rest, tail, [head | buff])
     87   end
     88 
     89   defp build_types([:pop | rest], remaining, [head | buff]) do
     90     build_types(rest, [head | remaining], buff)
     91   end
     92 
     93   defp build_types([%Schema.SchemaDefinition{} = schema | rest], stack, buff) do
     94     build_types(rest, [schema | stack], buff)
     95   end
     96 
     97   @simple_open [
     98     Schema.ScalarTypeDefinition,
     99     Schema.ObjectTypeDefinition,
    100     Schema.FieldDefinition,
    101     Schema.EnumTypeDefinition,
    102     Schema.DirectiveDefinition,
    103     Schema.InputObjectTypeDefinition,
    104     Schema.InputValueDefinition,
    105     Schema.InterfaceTypeDefinition,
    106     Schema.UnionTypeDefinition,
    107     Schema.EnumValueDefinition
    108   ]
    109 
    110   defp build_types([%module{} = type | rest], stack, buff) when module in @simple_open do
    111     build_types(rest, [type | stack], buff)
    112   end
    113 
    114   defp build_types([{:import_fields, criterion} | rest], [obj | stack], buff) do
    115     build_types(rest, [push(obj, :imports, criterion) | stack], buff)
    116   end
    117 
    118   defp build_types([{:desc, desc} | rest], [item | stack], buff) do
    119     build_types(rest, [%{item | description: desc} | stack], buff)
    120   end
    121 
    122   defp build_types([{:middleware, middleware} | rest], [field, obj | stack], buff) do
    123     field = Map.update!(field, :middleware, &(middleware ++ &1))
    124     build_types(rest, [field, obj | stack], buff)
    125   end
    126 
    127   defp build_types([{:config, config} | rest], [field | stack], buff) do
    128     field = %{field | config: config}
    129     build_types(rest, [field | stack], buff)
    130   end
    131 
    132   defp build_types([{:directive, trigger} | rest], [field | stack], buff) do
    133     field = Map.update!(field, :directives, &[trigger | &1])
    134     build_types(rest, [field | stack], buff)
    135   end
    136 
    137   defp build_types([{:trigger, trigger} | rest], [field | stack], buff) do
    138     field = Map.update!(field, :triggers, &[trigger | &1])
    139     build_types(rest, [field | stack], buff)
    140   end
    141 
    142   defp build_types([{:interface, interface} | rest], [obj | stack], buff) do
    143     obj = Map.update!(obj, :interfaces, &[interface | &1])
    144     build_types(rest, [obj | stack], buff)
    145   end
    146 
    147   defp build_types([{:__private__, private} | rest], [entity | stack], buff) do
    148     entity = Map.update!(entity, :__private__, &update_private(&1, private))
    149     build_types(rest, [entity | stack], buff)
    150   end
    151 
    152   defp build_types([{:values, values} | rest], [enum | stack], buff) do
    153     enum = Map.update!(enum, :values, &(List.wrap(values) ++ &1))
    154     build_types(rest, [enum | stack], buff)
    155   end
    156 
    157   defp build_types([{:sdl, sdl_definitions} | rest], [schema | stack], buff) do
    158     # TODO: Handle directives, etc
    159     build_types(rest, [concat(schema, :type_definitions, sdl_definitions) | stack], buff)
    160   end
    161 
    162   defp build_types([{:locations, locations} | rest], [directive | stack], buff) do
    163     directive = Map.update!(directive, :locations, &(locations ++ &1))
    164     build_types(rest, [directive | stack], buff)
    165   end
    166 
    167   defp build_types([{attr, value} | rest], [entity | stack], buff) do
    168     entity = %{entity | attr => value}
    169     build_types(rest, [entity | stack], buff)
    170   end
    171 
    172   defp build_types([:close | rest], [%Schema.EnumValueDefinition{} = value, enum | stack], buff) do
    173     build_types(rest, [push(enum, :values, value) | stack], buff)
    174   end
    175 
    176   defp build_types([:close | rest], [%Schema.InputValueDefinition{} = arg, field | stack], buff) do
    177     build_types(rest, [push(field, :arguments, arg) | stack], buff)
    178   end
    179 
    180   defp build_types([:close | rest], [%Schema.FieldDefinition{} = field, obj | stack], buff) do
    181     field =
    182       field
    183       |> Map.update!(:middleware, &Enum.reverse/1)
    184       |> Map.update!(:arguments, &Enum.reverse/1)
    185       |> Map.update!(:triggers, &{:%{}, [], &1})
    186       |> Map.put(:function_ref, {obj.identifier, field.identifier})
    187 
    188     build_types(rest, [push(obj, :fields, field) | stack], buff)
    189   end
    190 
    191   defp build_types([:close | rest], [%Schema.ObjectTypeDefinition{} = obj, schema | stack], buff) do
    192     obj = Map.update!(obj, :fields, &Enum.reverse/1)
    193     build_types(rest, [push(schema, :type_definitions, obj) | stack], buff)
    194   end
    195 
    196   defp build_types(
    197          [:close | rest],
    198          [%Schema.InputObjectTypeDefinition{} = obj, schema | stack],
    199          buff
    200        ) do
    201     obj = Map.update!(obj, :fields, &Enum.reverse/1)
    202     build_types(rest, [push(schema, :type_definitions, obj) | stack], buff)
    203   end
    204 
    205   defp build_types(
    206          [:close | rest],
    207          [%Schema.InterfaceTypeDefinition{} = iface, schema | stack],
    208          buff
    209        ) do
    210     iface = Map.update!(iface, :fields, &Enum.reverse/1)
    211     build_types(rest, [push(schema, :type_definitions, iface) | stack], buff)
    212   end
    213 
    214   defp build_types([:close | rest], [%Schema.UnionTypeDefinition{} = union, schema | stack], buff) do
    215     build_types(rest, [push(schema, :type_definitions, union) | stack], buff)
    216   end
    217 
    218   defp build_types([:close | rest], [%Schema.DirectiveDefinition{} = dir, schema | stack], buff) do
    219     build_types(rest, [push(schema, :directive_definitions, dir) | stack], buff)
    220   end
    221 
    222   defp build_types([:close | rest], [%Schema.EnumTypeDefinition{} = type, schema | stack], buff) do
    223     type = Map.update!(type, :values, &Enum.reverse/1)
    224     schema = push(schema, :type_definitions, type)
    225     build_types(rest, [schema | stack], buff)
    226   end
    227 
    228   defp build_types([:close | rest], [%Schema.ScalarTypeDefinition{} = type, schema | stack], buff) do
    229     schema = push(schema, :type_definitions, type)
    230     build_types(rest, [schema | stack], buff)
    231   end
    232 
    233   defp build_types([:close | rest], [%Schema.SchemaDefinition{} = schema, bp], buff) do
    234     bp = push(bp, :schema_definitions, schema)
    235     build_types(rest, [bp], buff)
    236   end
    237 
    238   defp push(entity, key, value) do
    239     Map.update!(entity, key, &[value | &1])
    240   end
    241 
    242   defp concat(entity, key, value) do
    243     Map.update!(entity, key, &(&1 ++ value))
    244   end
    245 
    246   defp update_private(existing_private, private) do
    247     Keyword.merge(existing_private, private, fn
    248       _, v1, v2 ->
    249         update_private(v1, v2)
    250     end)
    251   end
    252 end