Resourceful.Registry (Resourceful v0.1.6)
View SourceSummary
Functions
Instances of Resourceful.Type are intended to be used in conjunction with a
registry in most circumstances. The application, and even the client, will
likely understand a resource type by its string name/identifier. Types
themselves, when associated with a registry, will be able to reference each
other as well, which forms the basis for relationships.
Builds a field graph for a Resourceful.Type. Since types have a max_depth,
all possible graphed fields can be computed and cached at compile time when
using a registry. This allows nested fields to be treated like local fields in
the sense that they are available in a flat map.
A name can be optionally passed to the type/2 macro. If provided, this name
will override the name of the resource created in provided block.
Assigns the resource specified in the block and makes it part of the
registry. If name is provided, it will rename the resource and use that
name as the key.
Ensures a value is a Resourceful.Type and that no type of the same name
exists in the map. Raises an exception if both conditions are not met.
Functions
Instances of Resourceful.Type are intended to be used in conjunction with a
registry in most circumstances. The application, and even the client, will
likely understand a resource type by its string name/identifier. Types
themselves, when associated with a registry, will be able to reference each
other as well, which forms the basis for relationships.
A module using the Registry behaviour becomes a key/value store.
defresourcefultype/1 allows the types to be evaluated entirely at compile
time.
@spec build_field_graph( %{ required(String.t()) => %Resourceful.Type{ cache: term(), fields: term(), id: term(), max_depth: term(), max_filters: term(), max_sorters: term(), meta: term(), name: term(), registry: term() } }, String.t() ) :: Resourceful.Type.field_graph()
Builds a field graph for a Resourceful.Type. Since types have a max_depth,
all possible graphed fields can be computed and cached at compile time when
using a registry. This allows nested fields to be treated like local fields in
the sense that they are available in a flat map.
For example, a song type would have a title field. Once graphed, it would
also have an album.title field. If the depth was set to 2, access to a field
like album.artist.name would also be available.
This prevents a lot of recursion logic from being applied at every lookup and by instecting the field graph for a type it's easy to see all of the possible mappings.
Graphed fields are wrapped in a Resourceful.Type.GraphedField struct which
contains relational information about the field in addition to the field data
itself.
See Resourceful.Type.max_depth/2 for information about what is intended to
be included in a field graph based on the depth setting.
@spec fetch_field_graph( map(), String.t() | %Resourceful.Type{ cache: term(), fields: term(), id: term(), max_depth: term(), max_filters: term(), max_sorters: term(), meta: term(), name: term(), registry: term() } ) :: {:ok, %{ required(String.t()) => %Resourceful.Type.GraphedField{ field: term(), map_to: term(), name: term(), parent: term(), query_alias: term() } }} | Resourceful.Error.contextual()
@spec fetch_field_graph!( map(), String.t() | %Resourceful.Type{ cache: term(), fields: term(), id: term(), max_depth: term(), max_filters: term(), max_sorters: term(), meta: term(), name: term(), registry: term() } ) :: %{ required(String.t()) => %Resourceful.Type.GraphedField{ field: term(), map_to: term(), name: term(), parent: term(), query_alias: term() } }
@spec maybe_put_name( %Resourceful.Type{ cache: term(), fields: term(), id: term(), max_depth: term(), max_filters: term(), max_sorters: term(), meta: term(), name: term(), registry: term() }, String.t() | nil ) :: %Resourceful.Type{ cache: term(), fields: term(), id: term(), max_depth: term(), max_filters: term(), max_sorters: term(), meta: term(), name: term(), registry: term() }
A name can be optionally passed to the type/2 macro. If provided, this name
will override the name of the resource created in provided block.
Assigns the resource specified in the block and makes it part of the
registry. If name is provided, it will rename the resource and use that
name as the key.
If block does not result in a Resourceful.Type an exception will be
raised.
@spec validate_type!(any(), %{ required(String.t()) => %Resourceful.Type{ cache: term(), fields: term(), id: term(), max_depth: term(), max_filters: term(), max_sorters: term(), meta: term(), name: term(), registry: term() } }) :: %Resourceful.Type{ cache: term(), fields: term(), id: term(), max_depth: term(), max_filters: term(), max_sorters: term(), meta: term(), name: term(), registry: term() }
Ensures a value is a Resourceful.Type and that no type of the same name
exists in the map. Raises an exception if both conditions are not met.