Packages
absinthe
1.5.0-rc.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/phase/schema/apply_declaration.ex
defmodule Absinthe.Phase.Schema.ApplyDeclaration do
@moduledoc false
use Absinthe.Phase
alias Absinthe.Blueprint
@type operation :: :query | :mutation | :subscription
@type root_mappings :: %{operation() => Blueprint.TypeReference.Name.t()}
def run(blueprint, _opts) do
blueprint = process(blueprint)
{:ok, blueprint}
end
# Apply schema declaration to each schema definition
@spec process(blueprint :: Blueprint.t()) :: Blueprint.t()
defp process(blueprint = %Blueprint{}) do
%{
blueprint
| schema_definitions: Enum.map(blueprint.schema_definitions, &process_schema_definition/1)
}
end
# Strip the schema declaration out of the schema's type definitions and apply it
@spec process_schema_definition(schema_definition :: Blueprint.Schema.SchemaDefinition.t()) ::
Blueprint.Schema.SchemaDefinition.t()
defp process_schema_definition(schema_definition) do
{declarations, type_defs} =
Enum.split_with(
schema_definition.type_definitions,
&match?(%Blueprint.Schema.SchemaDeclaration{}, &1)
)
# Remove declaration
schema_definition = %{schema_definition | type_definitions: type_defs}
case declarations do
[declaration] ->
root_mappings =
declaration
|> extract_root_mappings
%{
schema_definition
| type_definitions:
Enum.map(schema_definition.type_definitions, &maybe_mark_root(&1, root_mappings))
}
[] ->
schema_definition
[_first | extra_declarations] ->
extra_declarations
|> Enum.reduce(schema_definition, fn declaration, acc ->
acc
|> put_error(error(declaration))
end)
end
end
# Generate an error for extraneous schema declarations
@spec error(declaration :: Blueprint.Schema.SchemaDeclaration.t()) :: Absinthe.Phase.Error.t()
defp error(declaration) do
%Absinthe.Phase.Error{
message:
"More than one schema declaration found. Only one instance of `schema' should be present in SDL.",
locations: [declaration.__reference__.location],
phase: __MODULE__
}
end
# Extract the declared root type names
@spec extract_root_mappings(declaration :: Blueprint.Schema.SchemaDeclaration.t()) ::
root_mappings()
defp extract_root_mappings(declaration) do
for field_def <- declaration.field_definitions,
field_def.identifier in ~w(query mutation subscription)a,
into: %{} do
{field_def.identifier, field_def.type}
end
end
# If the type definition is declared as a root type, set the identifier appropriately
@spec maybe_mark_root(type_def :: Blueprint.Schema.t(), root_mappings :: root_mappings()) ::
Blueprint.Schema.t()
defp maybe_mark_root(%Blueprint.Schema.ObjectTypeDefinition{} = type_def, root_mappings) do
case operation_root_identifier(type_def, root_mappings) do
nil ->
type_def
identifier ->
%{type_def | identifier: identifier}
end
end
defp maybe_mark_root(type_def, _root_mappings), do: type_def
# Determine which, if any, root identifier should be applied to an object type definitiona
@spec operation_root_identifier(
type_def :: Blueprint.Schema.ObjectTypeDefinition.t(),
root_mappings :: root_mappings()
) :: nil | operation()
defp operation_root_identifier(type_def, root_mappings) do
match_name = type_def.name
Enum.find_value(root_mappings, fn
{ident, %{name: ^match_name}} ->
ident
_ ->
false
end)
end
end