Packages
absinthe
1.2.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/document/validation/scalar_leafs.ex
defmodule Absinthe.Phase.Document.Validation.ScalarLeafs do # [sic]
@moduledoc false
# Validates that all leaf nodes are scalars.
#
# # Examples:
# Assume `user` field is an object, and `email` is a scalar.
#
# ## DO NOT
# ```
# {
# user
# }
# ```
#
# ## DO
# ```
# {
# user {name email}
# }
# ```
#
# ## DO NOT
# ```
# {
# email { fields on scalar }
# }
# ```
#
# ## DO
# ```
# {
# email
# }
# ```
alias Absinthe.{Blueprint, Phase, Type}
use Absinthe.Phase
use Absinthe.Phase.Validation
@doc """
Run the validation.
"""
@spec run(Blueprint.t, Keyword.t) :: Phase.result_t
def run(input, _options \\ []) do
result = Blueprint.prewalk(input, &handle_node(&1, input.schema))
{:ok, result}
end
defp handle_node(%{schema_node: nil} = node, _schema), do: {:halt, node}
defp handle_node(%Blueprint.Document.Field{schema_node: schema_node} = node, schema) do
type = Type.expand(schema_node.type, schema)
process(node, Type.unwrap(type), type)
end
defp handle_node(node, _) do
node
end
@has_subfields [
Type.Object,
Type.Union,
Type.Interface
]
defp process(%{selections: []} = node, %unwrapped{}, type) when unwrapped in @has_subfields do
bad_node(node, type, :missing_subfields)
end
defp process(%{selections: s} = node, %unwrapped{}, type) when s != [] and not unwrapped in @has_subfields do
bad_node(node, type, :bad_subfields)
end
defp process(node, _, _) do
node
end
defp bad_node(node, type, :bad_subfields = flag) do
node
|> flag_invalid(flag)
|> put_error(error(node, no_subselection_allowed_message(node.name, Type.name(type))))
end
defp bad_node(node, type, :missing_subfields = flag) do
node
|> flag_invalid(flag)
|> put_error(error(node, required_subselection_message(node.name, Type.name(type))))
end
# Generate the error
@spec error(Blueprint.Document.Field.t, String.t) :: Phase.Error.t
defp error(node, message) do
Phase.Error.new(
__MODULE__,
message,
location: node.source_location
)
end
@doc """
Generate the error message for an extraneous field subselection.
"""
@spec no_subselection_allowed_message(String.t, String.t) :: String.t
def no_subselection_allowed_message(field_name, type_name) do
~s(Field "#{field_name}" must not have a selection since type "#{type_name}" has no subfields.)
end
@doc """
Generate the error message for a missing field subselection.
"""
@spec required_subselection_message(String.t, String.t) :: String.t
def required_subselection_message(field_name, type_name) do
~s(Field "#{field_name}" of type "#{type_name}" must have a selection of subfields. Did you mean "#{field_name} { ... }"?)
end
end