Packages
absinthe
1.6.0-rc.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/blueprint/schema.ex
defmodule Absinthe.Blueprint.Schema do
@moduledoc false
alias __MODULE__
alias Absinthe.Blueprint
@type directive_t :: Schema.DirectiveDefinition.t()
@type type_t ::
Blueprint.Schema.EnumTypeDefinition.t()
| Blueprint.Schema.InputObjectTypeDefinition.t()
| Blueprint.Schema.InterfaceTypeDefinition.t()
| Blueprint.Schema.ObjectTypeDefinition.t()
| Blueprint.Schema.ScalarTypeDefinition.t()
| Blueprint.Schema.UnionTypeDefinition.t()
@type t ::
Blueprint.Schema.EnumValueDefinition.t()
| Blueprint.Schema.InputValueDefinition.t()
| Blueprint.Schema.SchemaDeclaration.t()
| Blueprint.Schema.SchemaDefinition.t()
| type_t()
| directive_t()
@doc """
Lookup a type definition that is part of a schema.
"""
@spec lookup_type(Blueprint.t(), atom) :: nil | Blueprint.Schema.t()
def lookup_type(blueprint, identifier) do
blueprint.schema_definitions
|> List.first()
|> Map.get(:type_definitions)
|> Enum.find(fn
%{identifier: ^identifier} ->
true
_ ->
false
end)
end
@doc """
Lookup a directive definition that is part of a schema.
"""
@spec lookup_directive(Blueprint.t(), atom) :: nil | Blueprint.Schema.directive_t()
def lookup_directive(blueprint, identifier) do
blueprint.schema_definitions
|> List.first()
|> Map.get(:directive_definitions)
|> Enum.find(fn
%{identifier: ^identifier} ->
true
_ ->
false
end)
end
def functions(module) do
if function_exported?(module, :functions, 0) do
module.functions
else
[]
end
end
def build([%Absinthe.Blueprint{} = bp | attrs]) do
build_types(attrs, [bp], [])
end
defp build_types([], [bp], buffer) do
if buffer != [] do
raise """
Unused buffer! #{inspect(buffer)}
"""
end
Map.update!(bp, :schema_definitions, &Enum.reverse/1)
end
# this rather insane scheme lets interior macros get back out to exterior
# scopes so that they can define top level entities as necessary, and then
# return to the regularly scheduled programming.
defp build_types([:stash | rest], [head | tail], buff) do
build_types(rest, tail, [head | buff])
end
defp build_types([:pop | rest], remaining, [head | buff]) do
build_types(rest, [head | remaining], buff)
end
defp build_types([%Schema.SchemaDefinition{} = schema | rest], stack, buff) do
build_types(rest, [schema | stack], buff)
end
@simple_open [
Schema.ScalarTypeDefinition,
Schema.ObjectTypeDefinition,
Schema.FieldDefinition,
Schema.EnumTypeDefinition,
Schema.DirectiveDefinition,
Schema.InputObjectTypeDefinition,
Schema.InputValueDefinition,
Schema.InterfaceTypeDefinition,
Schema.UnionTypeDefinition,
Schema.EnumValueDefinition
]
defp build_types([%module{} = type | rest], stack, buff) when module in @simple_open do
build_types(rest, [type | stack], buff)
end
defp build_types([{:import_fields, criterion} | rest], [obj | stack], buff) do
build_types(rest, [push(obj, :imports, criterion) | stack], buff)
end
defp build_types([{:desc, desc} | rest], [item | stack], buff) do
build_types(rest, [%{item | description: desc} | stack], buff)
end
defp build_types([{:middleware, middleware} | rest], [field, obj | stack], buff) do
field = Map.update!(field, :middleware, &(middleware ++ &1))
build_types(rest, [field, obj | stack], buff)
end
defp build_types([{:config, config} | rest], [field | stack], buff) do
field = %{field | config: config}
build_types(rest, [field | stack], buff)
end
defp build_types([{:trigger, trigger} | rest], [field | stack], buff) do
field = Map.update!(field, :triggers, &[trigger | &1])
build_types(rest, [field | stack], buff)
end
defp build_types([{:interface, interface} | rest], [obj | stack], buff) do
obj = Map.update!(obj, :interfaces, &[interface | &1])
build_types(rest, [obj | stack], buff)
end
defp build_types([{:__private__, private} | rest], [entity | stack], buff) do
entity = Map.update!(entity, :__private__, &update_private(&1, private))
build_types(rest, [entity | stack], buff)
end
defp build_types([{:values, values} | rest], [enum | stack], buff) do
enum = Map.update!(enum, :values, &(values ++ &1))
build_types(rest, [enum | stack], buff)
end
defp build_types([{:sdl, sdl_definitions} | rest], [schema | stack], buff) do
# TODO: Handle directives, etc
build_types(rest, [concat(schema, :type_definitions, sdl_definitions) | stack], buff)
end
defp build_types([{:locations, locations} | rest], [directive | stack], buff) do
directive = Map.update!(directive, :locations, &(locations ++ &1))
build_types(rest, [directive | stack], buff)
end
defp build_types([{attr, value} | rest], [entity | stack], buff) do
entity = %{entity | attr => value}
build_types(rest, [entity | stack], buff)
end
defp build_types([:close | rest], [%Schema.EnumValueDefinition{} = value, enum | stack], buff) do
build_types(rest, [push(enum, :values, value) | stack], buff)
end
defp build_types([:close | rest], [%Schema.InputValueDefinition{} = arg, field | stack], buff) do
arg = Map.update!(arg, :default_value, fn val -> {:unquote, [], [val]} end)
build_types(rest, [push(field, :arguments, arg) | stack], buff)
end
defp build_types([:close | rest], [%Schema.FieldDefinition{} = field, obj | stack], buff) do
field =
field
|> Map.update!(:middleware, &Enum.reverse/1)
|> Map.update!(:arguments, &Enum.reverse/1)
|> Map.update!(:triggers, &{:%{}, [], &1})
|> Map.put(:function_ref, {obj.identifier, field.identifier})
build_types(rest, [push(obj, :fields, field) | stack], buff)
end
defp build_types([:close | rest], [%Schema.ObjectTypeDefinition{} = obj, schema | stack], buff) do
obj = Map.update!(obj, :fields, &Enum.reverse/1)
build_types(rest, [push(schema, :type_definitions, obj) | stack], buff)
end
defp build_types(
[:close | rest],
[%Schema.InputObjectTypeDefinition{} = obj, schema | stack],
buff
) do
obj = Map.update!(obj, :fields, &Enum.reverse/1)
build_types(rest, [push(schema, :type_definitions, obj) | stack], buff)
end
defp build_types(
[:close | rest],
[%Schema.InterfaceTypeDefinition{} = iface, schema | stack],
buff
) do
iface = Map.update!(iface, :fields, &Enum.reverse/1)
build_types(rest, [push(schema, :type_definitions, iface) | stack], buff)
end
defp build_types([:close | rest], [%Schema.UnionTypeDefinition{} = union, schema | stack], buff) do
build_types(rest, [push(schema, :type_definitions, union) | stack], buff)
end
defp build_types([:close | rest], [%Schema.DirectiveDefinition{} = dir, schema | stack], buff) do
build_types(rest, [push(schema, :directive_definitions, dir) | stack], buff)
end
defp build_types([:close | rest], [%Schema.EnumTypeDefinition{} = type, schema | stack], buff) do
type = Map.update!(type, :values, &Enum.reverse/1)
schema = push(schema, :type_definitions, type)
build_types(rest, [schema | stack], buff)
end
defp build_types([:close | rest], [%Schema.ScalarTypeDefinition{} = type, schema | stack], buff) do
schema = push(schema, :type_definitions, type)
build_types(rest, [schema | stack], buff)
end
defp build_types([:close | rest], [%Schema.SchemaDefinition{} = schema, bp], buff) do
bp = push(bp, :schema_definitions, schema)
build_types(rest, [bp], buff)
end
defp push(entity, key, value) do
Map.update!(entity, key, &[value | &1])
end
defp concat(entity, key, value) do
Map.update!(entity, key, &(&1 ++ value))
end
defp update_private(existing_private, private) do
Keyword.merge(existing_private, private, fn
_, v1, v2 ->
update_private(v1, v2)
end)
end
end