Packages
absinthe
1.5.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/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