mirror of
https://github.com/ash-project/ash_graphql.git
synced 2024-09-20 21:32:59 +12:00
120 lines
3.8 KiB
Elixir
120 lines
3.8 KiB
Elixir
|
defmodule AshGraphql.Resource.Transformers.ValidateCompatibleNames do
|
||
|
@moduledoc "Ensures that all field names are valid or remapped to something valid exist"
|
||
|
use Spark.Dsl.Transformer
|
||
|
|
||
|
alias Spark.Dsl.Transformer
|
||
|
|
||
|
def after_compile?, do: true
|
||
|
|
||
|
def transform(dsl) do
|
||
|
field_names = AshGraphql.Resource.Info.field_names(dsl)
|
||
|
argument_names = AshGraphql.Resource.Info.argument_names(dsl)
|
||
|
resource = Transformer.get_persisted(dsl, :module)
|
||
|
|
||
|
dsl
|
||
|
|> Ash.Resource.Info.public_attributes()
|
||
|
|> Enum.concat(Ash.Resource.Info.public_aggregates(dsl))
|
||
|
|> Enum.concat(Ash.Resource.Info.public_calculations(dsl))
|
||
|
|> Enum.concat(Ash.Resource.Info.public_relationships(dsl))
|
||
|
|> Enum.each(fn field ->
|
||
|
name = field_names[field.name] || field.name
|
||
|
|
||
|
if invalid_name?(name) do
|
||
|
raise_invalid_name_error(resource, field, name)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
dsl
|
||
|
|> Transformer.get_entities([:graphql, :queries])
|
||
|
|> Enum.concat(Transformer.get_entities(dsl, [:graphql, :mutations]))
|
||
|
|> Enum.map(& &1.action)
|
||
|
|> Enum.uniq()
|
||
|
|> Enum.each(fn action ->
|
||
|
action = Ash.Resource.Info.action(dsl, action)
|
||
|
|
||
|
Enum.each(action.arguments, fn argument ->
|
||
|
name = argument_names[action.name][argument.name] || argument.name
|
||
|
|
||
|
if invalid_name?(name) do
|
||
|
raise_invalid_argument_name_error(resource, action, argument.name, name)
|
||
|
end
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
{:ok, dsl}
|
||
|
end
|
||
|
|
||
|
defp invalid_name?(name) do
|
||
|
Regex.match?(~r/_+\d/, to_string(name))
|
||
|
end
|
||
|
|
||
|
defp raise_invalid_name_error(resource, field, name) do
|
||
|
path =
|
||
|
case field do
|
||
|
%Ash.Resource.Relationships.BelongsTo{} -> [:relationships, :belongs_to, field.name]
|
||
|
%Ash.Resource.Relationships.HasMany{} -> [:relationships, :has_many, field.name]
|
||
|
%Ash.Resource.Relationships.HasOne{} -> [:relationships, :has_one, field.name]
|
||
|
%Ash.Resource.Relationships.ManyToMany{} -> [:relationships, :many_to_many, field.name]
|
||
|
%Ash.Resource.Calculation{} -> [:calculations, field.name]
|
||
|
%Ash.Resource.Aggregate{} -> [:aggregates, field.name]
|
||
|
%Ash.Resource.Attribute{} -> [:attributes, field.name]
|
||
|
end
|
||
|
|
||
|
raise Spark.Error.DslError,
|
||
|
module: resource,
|
||
|
path: path,
|
||
|
message: """
|
||
|
Name #{name} is invalid.
|
||
|
|
||
|
Due to issues in the underlying tooling with camel/snake case conversion of names that
|
||
|
include underscores immediately preceding integers, a different name must be provided to
|
||
|
use in the graphql. To do so, add a mapping in your configured field_names, i.e
|
||
|
|
||
|
graphql do
|
||
|
...
|
||
|
|
||
|
field_names #{name}: :#{make_name_better(name)}
|
||
|
|
||
|
...
|
||
|
end
|
||
|
|
||
|
|
||
|
For more information on the underlying issue, see: https://github.com/absinthe-graphql/absinthe/issues/601
|
||
|
"""
|
||
|
end
|
||
|
|
||
|
defp raise_invalid_argument_name_error(resource, action, argument_name, name) do
|
||
|
path = [:actions, action.type, action.name, :argument, argument_name]
|
||
|
|
||
|
raise Spark.Error.DslError,
|
||
|
module: resource,
|
||
|
path: path,
|
||
|
message: """
|
||
|
Name #{name} is invalid.
|
||
|
|
||
|
Due to issues in the underlying tooling with camel/snake case conversion of names that
|
||
|
include underscores immediately preceding integers, a different name must be provided to
|
||
|
use in the graphql. To do so, add a mapping in your configured argument_names, i.e
|
||
|
|
||
|
graphql do
|
||
|
...
|
||
|
|
||
|
argument_names #{action.name}: [#{argument_name}: :#{make_name_better(name)}]
|
||
|
|
||
|
...
|
||
|
end
|
||
|
|
||
|
|
||
|
For more information on the underlying issue, see: https://github.com/absinthe-graphql/absinthe/issues/601
|
||
|
"""
|
||
|
end
|
||
|
|
||
|
defp make_name_better(name) do
|
||
|
name
|
||
|
|> to_string()
|
||
|
|> String.replace(~r/_+\d/, fn v ->
|
||
|
String.trim_leading(v, "_")
|
||
|
end)
|
||
|
end
|
||
|
end
|