I have a work_phone_2 field in my database and in my Absinthe types:
object :contact do
field :id, :id
...
field :work_phone_2, :string
end
If I run a query against this:
query Contact {
contact(id: 1) {
id
workPhone2
}
}
I get an error saying:
Cannot query field "workPhone2" on type "Contact". Did you mean "workPhone2"?
If I change it to snake case (work_phone_2) in my query it works fine (workPhone_2 in the query works too). It appears it only fails when a number immediately follows an underscore. For example, if I set up field :work_phone_a2 then querying against workPhoneA2 works fine.
The default adapter relies on Elixir's Macro.underscore function to translate document field names into schema field names.
iex(1)> "workPhone2" |> Macro.underscore
"work_phone2"
I would advise naming your fields in a way compatible with that function, or using a custom adapter.
Yeah, the issue here is really the error message.
Right, the problem is that this is really a schema error not a document error. This is essentially a duplicate of https://github.com/absinthe-graphql/absinthe/issues/298
Ahh, ok, that makes sense. The error is definitely confusing. And since Absinthe.Utils.camelize "work_phone_2", lower: true gave me workPhone2 I assumed it would reverse the same.
I'm stuck with the database column name unfortunately, but I can use a better name for my Absinthe type and just use a custom resolver with the correct column. Thanks!
Right yeah unfortunately neither underscore/1 nor camelize/1 are bijective, in that different values passed to camelize can give you the same value.
We've discussed having some kind of schema warning, but the challenge there is that right now adapters aren't placed on schemas, they're merely used at document run call sites.
I'm not sure I'd object however to having a schema specify the list of adapters it supports.
Closing as I don't think this gives us anything in addition to the previously linked issue.
I had this problem too, so I overrode a a couple of the Absinthe.Adapter.LanguageConventions functions to stick a _ in before numbers that come after letters.
So in my app, a query for subRank1 to_internal_name()s back to sub_rank_1 matching up with the ecto schema etc.
defmodule MyApp.UnderscoreNumbersAdapter do
@moduledoc """
Implements behaviour or Absinthe.Adapter
Inserts an underscore before numbers to match the strings generated by to_external_name()
"""
use Absinthe.Adapter
@ends_with_a_number ~r/([a-z])([0-9]+)/
def to_internal_name(camelized_name, _role) do
camelized_name
|> Macro.underscore()
|> underscore_number()
end
def underscore_number(snake_name) do
if Regex.match?(@ends_with_a_number, snake_name) do
Regex.replace(@ends_with_a_number, snake_name, "\\1\_\\2")
else
snake_name
end
end
end
This can be implemented by specifying the adapter when configuring Absinthe.
see docs
config :absinthe,
adapter: MyApp.UnderscoreNumbersAdapter
If you're using Absinthe Plug you can configure it here (in router.ex)
forward "/", Absinthe.Plug,
schema: MyApp.UnderscoreNumbersAdapter,
adapter: MyApp.UnderscoreNumbersAdapter
馃槚 This took a little while for me to work out so thought I'd mention it in case it helps anyone.
Most helpful comment
I had this problem too, so I overrode a a couple of the
Absinthe.Adapter.LanguageConventionsfunctions to stick a_in before numbers that come after letters.So in my app, a query for
subRank1to_internal_name()s back tosub_rank_1matching up with the ecto schema etc.This can be implemented by specifying the adapter when configuring Absinthe.
see docs
If you're using Absinthe Plug you can configure it here (in router.ex)
馃槚 This took a little while for me to work out so thought I'd mention it in case it helps anyone.