defmodule DataSchema.DataAccessBehaviour do
@moduledoc """
Defines how `DataSchema.to_struct/2` should access data for each given field type.
When we create a struct defined by the schema we will visit each struct field in turn
and attempt to extract values from the source data. You tell the schema _how_ to
extract that data by providing a module that implements this behaviour. Modules that
implement this behaviour are implementing how to access data in the source for each kind
of field.
### Examples
To define a schema that consumes a map to create a struct you would first create a
module that implements this behaviour like so:
defmodule DataSchema.MapAccessor do
@behaviour DataSchema.DataAccessBehaviour
@impl true
def field(data = %{}, field) do
Map.get(data, field)
end
@impl true
def list_of(data = %{}, field) do
Map.get(data, field)
end
@impl true
def has_one(data = %{}, field) do
Map.get(data, field)
end
@impl true
def has_many(data = %{}, field) do
Map.get(data, field)
end
end
Then you would pass it into the schema definition:
defmodule BlogPost do
import DataSchema, only: [data_schema: 2]
data_schema([
field: {:content, "content", &{:ok, to_string(&1)}}
], DataSchema.MapAccessor)
end
When we call `DataSchema.to_struct/2` the functions in `DataSchema.MapAccessor` will be
used to access the data from the source.
DataSchema ships with the above example (see `DataSchema.MapAccessor`) and you can use
`DataSchema.data_schema/1` to leverage it automatically.
"""
@doc """
The function that will be called when a `:field` field is encountered in the schema when
we are turning some input data into a struct.
"""
# Should these be okay tuples? What would we do in the case of error. I guess bail out.
# It would mean non_null is not field level though.
@callback field(any(), any()) :: any()
@doc """
The function that will be called when a `:list_of` field is encountered in the schema
when we are turning some input data into a struct.
"""
@callback list_of(any(), any()) :: any()
@doc """
The function that will be called when a `:has_one` field is encountered in the schema
when we are turning some input data into a struct.
"""
@callback has_one(any(), any()) :: any()
@doc """
The function that will be called when a `:has_one` field is encountered in the schema
when we are turning some input data into a struct.
"""
@callback has_many(any(), any()) :: any()
end