Packages
ash_json_api
1.6.0-rc.2
1.7.1
1.7.0
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0-rc.2
1.6.0-rc.1
1.6.0-rc.0
1.5.1
1.5.0
1.4.45
1.4.44
1.4.43
1.4.42
1.4.41
1.4.40
1.4.39
1.4.38
1.4.37
1.4.36
1.4.35
1.4.34
1.4.33
1.4.32
1.4.31
1.4.30
1.4.29
1.4.28
1.4.27
1.4.26
1.4.25
1.4.24
1.4.23
1.4.22
1.4.21
1.4.20
1.4.19
1.4.18
1.4.17
1.4.16
1.4.15
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
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.3.8
1.3.7
1.3.6
1.3.5
1.3.4
retired
1.3.3
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.0
1.0.0-rc.6
1.0.0-rc.5
1.0.0-rc.4
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.34.2
0.34.1
0.34.0
0.33.1
0.33.0
0.32.1
0.32.0
0.31.3
0.31.2
retired
0.31.1
0.31.0
0.30.1
0.30.0-rc.4
0.30.0-rc.3
0.30.0-rc.2
0.30.0-rc.1
0.30.0-rc.0
0.29.1
0.29.0
0.28.6
0.28.5
0.28.4
0.28.3
0.28.2
0.28.1
0.28.0
0.27.6
0.27.5
0.27.1
0.27.0
0.25.0
0.24.4
0.24.2
0.24.1
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.1
0.10.0
0.9.0
0.8.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.4
0.2.3
0.2.1
0.2.0
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
The JSON:API extension for the Ash Framework.
Current section
Files
Jump to
Current section
Files
lib/ash_json_api/resource/info.ex
# SPDX-FileCopyrightText: 2019 ash_json_api contributors <https://github.com/ash-project/ash_json_api/graphs/contributors>
#
# SPDX-License-Identifier: MIT
defmodule AshJsonApi.Resource.Info do
@moduledoc "Introspection helpers for AshJsonApi.Resource"
alias Spark.Dsl.Extension
def type(resource) do
Extension.get_opt(resource, [:json_api], :type, nil, false)
end
def derive_filter?(resource) do
Extension.get_opt(resource, [:json_api], :derive_filter?, true, false)
end
def derive_sort?(resource) do
Extension.get_opt(resource, [:json_api], :derive_sort, true, false)
end
def always_include_linkage(resource) do
Extension.get_opt(resource, [:json_api], :always_include_linkage, [], false)
end
def includes(resource) do
Extension.get_opt(resource, [:json_api], :includes, [], false)
end
def paginated_includes(resource) do
Extension.get_opt(resource, [:json_api], :paginated_includes, [], false)
end
def action_names_in_schema(resource) do
Extension.get_opt(resource, [:json_api], :action_names_in_schema, [], false)
end
def base_route(resource) do
Extension.get_opt(resource, [:json_api, :routes], :base, "/", false)
end
def primary_key_fields(resource) do
Extension.get_opt(resource, [:json_api, :primary_key], :keys, [], false)
end
def primary_key_delimiter(resource) do
Extension.get_opt(resource, [:json_api, :primary_key], :delimiter, [], false)
end
def routes(resource, domain_or_domains \\ []) do
module =
if is_atom(resource) do
resource
else
Spark.Dsl.Extension.get_persisted(resource, :module)
end
domain_or_domains
|> List.wrap()
|> Enum.flat_map(&AshJsonApi.Domain.Info.routes/1)
|> Enum.filter(&(&1.resource == module))
|> Enum.concat(Extension.get_entities(resource, [:json_api, :routes]))
end
def include_nil_values?(resource) do
Extension.get_opt(resource, [:json_api], :include_nil_values?, nil, true)
end
def default_fields(resource) do
Extension.get_opt(resource, [:json_api], :default_fields, nil, true)
end
defp camelize(name) do
camelized = name |> to_string() |> Macro.camelize()
{first, rest} = String.split_at(camelized, 1)
String.downcase(first) <> rest
end
defp dasherize(name) do
name |> to_string() |> String.replace("_", "-")
end
@doc """
Returns the `field_names` config for the resource: a keyword list, a 1-arity function,
or one of the atoms `:camelize` / `:dasherize` (resolved to the corresponding function).
"""
def field_names(resource) do
case Extension.get_opt(resource, [:json_api], :field_names, [], true) do
:camelize -> &camelize/1
:dasherize -> &dasherize/1
other -> other
end
end
@doc """
Returns the `argument_names` config for the resource: a keyword list, a 2-arity function,
or one of the atoms `:camelize` / `:dasherize` (resolved to the corresponding function).
"""
def argument_names(resource) do
case Extension.get_opt(resource, [:json_api], :argument_names, [], true) do
:camelize -> fn _action, name -> camelize(name) end
:dasherize -> fn _action, name -> dasherize(name) end
other -> other
end
end
@doc """
Returns the `calculation_argument_names` config for the resource: a keyword list, a 2-arity function,
or one of the atoms `:camelize` / `:dasherize` (resolved to the corresponding function).
"""
def calculation_argument_names(resource) do
case Extension.get_opt(resource, [:json_api], :calculation_argument_names, [], true) do
:camelize -> fn _calc, name -> camelize(name) end
:dasherize -> fn _calc, name -> dasherize(name) end
other -> other
end
end
@doc """
Converts an Ash atom field name (attribute, calculation, aggregate) to its JSON:API
string key, applying any `field_names` mapping configured on the resource.
"""
def field_to_json_key(resource, field_name) do
names = field_names(resource)
cond do
is_function(names, 1) -> to_string(names.(field_name))
is_list(names) -> to_string(names[field_name] || field_name)
true -> to_string(field_name)
end
end
@doc """
Converts a JSON:API string key to an Ash atom field name, applying the reverse of any
`field_names` mapping configured on the resource. Returns `nil` if not found.
"""
def json_key_to_field(resource, json_key) do
names = field_names(resource)
all_fields =
Ash.Resource.Info.public_attributes(resource) ++
Ash.Resource.Info.public_calculations(resource) ++
Ash.Resource.Info.public_aggregates(resource)
Enum.find_value(all_fields, fn field ->
if apply_field_name_mapping(names, field.name) == json_key, do: field.name
end)
end
@doc """
Converts an Ash argument atom name to its JSON:API string key, applying any
`argument_names` mapping configured on the resource for the given action.
"""
def argument_to_json_key(resource, action_name, arg_name) do
names = argument_names(resource)
apply_argument_name_mapping(names, action_name, arg_name)
end
@doc """
Converts a JSON:API string key to an Ash argument atom name for the given action,
applying the reverse of any `argument_names` mapping. Returns `nil` if not found.
"""
def json_key_to_argument(resource, action_name, json_key) do
names = argument_names(resource)
action = Ash.Resource.Info.action(resource, action_name)
if action do
Enum.find_value(action.arguments, fn arg ->
if apply_argument_name_mapping(names, action_name, arg.name) == json_key, do: arg.name
end)
end
end
@doc """
Converts an Ash calculation argument atom name to its JSON:API string key, applying any
`calculation_argument_names` mapping configured on the resource for the given calculation.
"""
def calculation_argument_to_json_key(resource, calc_name, arg_name) do
names = calculation_argument_names(resource)
apply_argument_name_mapping(names, calc_name, arg_name)
end
@doc """
Converts a JSON:API string key to an Ash argument atom name for the given calculation,
applying the reverse of any `calculation_argument_names` mapping. Returns `nil` if not found.
"""
def json_key_to_calculation_argument(resource, calc_name, json_key) do
names = calculation_argument_names(resource)
case Ash.Resource.Info.public_calculation(resource, calc_name) do
%{arguments: args} ->
Enum.find_value(args, fn arg ->
if apply_argument_name_mapping(names, calc_name, arg.name) == json_key, do: arg.name
end)
nil ->
nil
end
end
@doc """
Returns a ref transformer function suitable for the `:ref_transformer` option of
`Ash.Filter.parse_input/3` and `Ash.Query.filter_input/3`. The returned function maps
user-facing JSON:API field/argument names back to their internal Ash atom names using
the resource's `field_names` and `argument_names` configuration.
"""
def filter_ref_transformer do
fn resource, ref ->
case ref do
{:calculation_argument, calc_name, arg_name} ->
json_key_to_calculation_argument(resource, calc_name, to_string(arg_name))
field_name ->
json_key_to_field(resource, to_string(field_name))
end
end
end
# Applies the name mapping for a single field, returning the JSON:API string.
@doc false
def apply_field_name_mapping(names, field_name) when is_function(names, 1) do
to_string(names.(field_name))
end
def apply_field_name_mapping(names, field_name) when is_list(names) do
to_string(names[field_name] || field_name)
end
def apply_field_name_mapping(_names, field_name) do
to_string(field_name)
end
# Applies the argument name mapping for a single argument, returning the JSON:API string.
@doc false
def apply_argument_name_mapping(names, action_name, arg_name) when is_function(names, 2) do
to_string(names.(action_name, arg_name))
end
def apply_argument_name_mapping(names, action_name, arg_name) when is_list(names) do
to_string((names[action_name] || [])[arg_name] || arg_name)
end
def apply_argument_name_mapping(_names, _action_name, arg_name) do
to_string(arg_name)
end
end