Packages
absinthe
1.7.2
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
def struct_to_kind(%struct{}), do: struct_to_kind(struct)
def struct_to_kind(Blueprint.Schema.DirectiveDefinition), do: "directive"
def struct_to_kind(Blueprint.Schema.EnumTypeDefinition), do: "enum type"
def struct_to_kind(Blueprint.Schema.EnumValueDefinition), do: "enum value"
def struct_to_kind(Blueprint.Schema.FieldDefinition), do: "field"
def struct_to_kind(Blueprint.Schema.InputObjectTypeDefinition), do: "input object"
def struct_to_kind(Blueprint.Schema.InputValueDefinition), do: "argument"
def struct_to_kind(Blueprint.Schema.InterfaceTypeDefinition), do: "interface"
def struct_to_kind(Blueprint.Schema.ObjectTypeDefinition), do: "object"
def struct_to_kind(Blueprint.Schema.ScalarTypeDefinition), do: "scalar"
def struct_to_kind(Blueprint.Schema.UnionTypeDefinition), do: "union"
def struct_to_kind(Blueprint.Schema.TypeExtensionDefinition), do: "type extension"
def struct_to_kind(_), do: "type"
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,
Schema.TypeExtensionDefinition,
Schema.SchemaDeclaration
]
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([{:directive, trigger} | rest], [field | stack], buff) do
field = Map.update!(field, :directives, &[trigger | &1])
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([{:type, type} | rest], [obj | stack], buff) do
obj = Map.update!(obj, :types, &[type | &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
@extendable_types [
Schema.EnumTypeDefinition,
Schema.InputObjectTypeDefinition,
Schema.InterfaceTypeDefinition,
Schema.ObjectTypeDefinition,
Schema.ScalarTypeDefinition,
Schema.SchemaDeclaration,
Schema.UnionTypeDefinition
]
defp build_types(
[:close | rest],
[
%extendable_type{} = def,
%Schema.TypeExtensionDefinition{} = extend | stack
],
buff
)
when extendable_type in @extendable_types do
build_types(rest, [%{extend | definition: def} | stack], buff)
end
defp build_types(
[:close | rest],
[%Schema.FieldDefinition{} = field, %Schema.SchemaDeclaration{} = declaration | stack],
buff
) do
build_types(rest, [push(declaration, :field_definitions, field) | 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.TypeExtensionDefinition{} = extension, schema | stack],
buff
) do
build_types(rest, [push(schema, :type_extensions, extension) | 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
union = Map.update!(union, :types, &Enum.reverse/1)
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.SchemaDeclaration{} = schema_declaration, schema | stack],
buff
) do
# The declaration is pushed into the :type_definitions instead of the :schema_declaration
# as it will be split off later in the ApplyDeclaration phase
schema = push(schema, :type_definitions, schema_declaration)
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