Packages
absinthe
1.6.5
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, &(List.wrap(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
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