defmodule Absinthe.Type.Field do
alias Absinthe.Type
@moduledoc """
Used to define a field.
Usually these are defined using `Absinthe.Schema.Notation.field/4`
See the `t` type below for details and examples of how to define a field.
"""
alias Absinthe.Type
alias Absinthe.Type.Deprecation
@typedoc """
A resolver function.
See the `Absinthe.Type.Field.t` explanation of `:resolve` for more information.
"""
@type resolver_t ::
(Absinthe.Resolution.arguments(), Absinthe.Resolution.t() -> result)
| (Absinthe.Resolution.source(),
Absinthe.Resolution.arguments(),
Absinthe.Resolution.t() ->
result)
| {module(), atom()}
@typedoc """
The result of a resolver.
"""
@type result :: ok_result | error_result | middleware_result
@typedoc """
A complexity function.
See the `Absinthe.Type.Field/t` explanation of `:complexity` for more
information.
"""
@type complexity_t ::
(%{atom => any}, non_neg_integer -> non_neg_integer)
| (%{atom => any}, non_neg_integer, Absinthe.Complexity.t() -> non_neg_integer)
| {module, atom}
| non_neg_integer
@type ok_result :: {:ok, any}
@type error_result :: {:error, error_value}
@type middleware_result :: {:middleware, Absinthe.Middleware.spec(), term}
@typedoc """
An error message is a human-readable string describing the error that occurred.
"""
@type error_message :: String.t()
@typedoc """
Any serializable value.
"""
@type serializable :: any
@typedoc """
A custom error may be a `map` or a `Keyword.t`, but must contain a `:message` key.
Note that the values that make up a custom error must be serializable.
"""
@type custom_error ::
%{required(:message) => error_message, optional(atom) => serializable} | Keyword.t()
@typedoc """
An error value is a simple error message, a custom error, or a list of either/both of them.
"""
@type error_value ::
error_message | custom_error | [error_message | custom_error] | serializable
@typedoc """
The configuration for a field.
* `:name` - The name of the field, usually assigned automatically by
the `Absinthe.Schema.Notation.field/4`. Including this option will bypass the snake_case to camelCase conversion.
* `:description` - Description of a field, useful for introspection.
* `:deprecation` - Deprecation information for a field, usually
set-up using `Absinthe.Schema.Notation.deprecate/1`.
* `:type` - The type the value of the field should resolve to
* `:args` - The arguments of the field, usually created by using `Absinthe.Schema.Notation.arg/2`.
* `:resolve` - The resolution function. See below for more information.
* `:complexity` - The complexity function. See below for more information.
* `:default_value` - The default value of a field. Note this is not used during resolution; only fields that are part of an `Absinthe.Type.InputObject` should set this value.
## Resolution Functions
### Default
If no resolution function is given, the default resolution function is used,
which is roughly equivalent to this:
{:ok, Map.get(parent_object, field_name)}
This is commonly use when listing the available fields on a
`Absinthe.Type.Object` that models a data record. For instance:
```
object :person do
description "A person"
field :first_name, :string
field :last_name, :string
end
```
### Custom Resolution
When accepting arguments, however, you probably need to use them for
something. Here's an example of defining a field that looks up a list of
users for a given `location_id`:
```
query do
field :users, :person do
arg :location_id, non_null(:id)
resolve fn %{location_id: id}, _ ->
{:ok, MyApp.users_for_location_id(id)}
end
end
end
```
Custom resolution functions are passed two arguments:
1. A map of the arguments for the field, filled in with values from the
provided query document/variables.
2. An `Absinthe.Resolution` struct, containing the execution environment
for the field (and useful for complex resolutions using the resolved source
object, etc)
## Complexity function
### Default
If no complexity function is given, the default complexity function is used,
which is equivalent to:
fn(_, child_complexity) -> 1 + child_complexity end
### Custom Complexity
When accepting arguments, however, you probably need to use them for
something. Here's an example of defining a field that looks up at most
`limit` users:
```
query do
field :users, :person do
arg :limit, :integer
complexity fn %{limit: limit}, child_complexity ->
10 + limit * child_complexity
end
end
end
```
An optional third argument, `Absinthe.Complexity` struct, provides extra
information. Here's an example of changing the complexity using the context:
```
query do
field :users, :person do
arg :limit, :integer
complexity fn _, child_complexity, %{context: %{admin: admin?}} ->
if admin?, do: 0, else: 10 + limit * child_complexity
end
end
end
```
Custom complexity functions are passed two or three arguments:
1. A map of the arguments for the field, filled in with values from the
provided query document/variables.
2. A non negative integer, which is total complexity of the child fields.
3. An `Absinthe.Complexity` struct with information about the context of the
field. This argument is optional when using an anonymous function.
Alternatively complexity can be an integer greater than or equal to 0:
```
query do
field :users, :person do
complexity 10
end
end
```
"""
@type t :: %__MODULE__{
identifier: atom,
name: binary,
description: binary | nil,
type: Type.identifier_t(),
deprecation: Deprecation.t() | nil,
default_value: any,
args: %{(binary | atom) => Absinthe.Type.Argument.t()} | nil,
middleware: [],
complexity: complexity_t | nil,
__private__: Keyword.t(),
definition: module,
__reference__: Type.Reference.t()
}
defstruct identifier: nil,
name: nil,
description: nil,
type: nil,
deprecation: nil,
args: %{},
# used by subscription fields
config: nil,
# used by mutation fields
triggers: [],
middleware: [],
complexity: nil,
default_value: nil,
__private__: [],
definition: nil,
__reference__: nil
@doc false
defdelegate functions, to: Absinthe.Blueprint.Schema.FieldDefinition
end