defmodule BridgeEx.Graphql.LanguageConventions do
@moduledoc """
This defines an adapter that supports GraphQL query documents in their
conventional (in JS) camelCase notation, while allowing the schema to be
defined using conventional (in Elixir) snake_case notation, and
transforming the names as needed for lookups, results, and error messages.
For example, this document:
```
{
myUser: createUser(userId: 2) {
firstName
lastName
}
}
```
Would map to an internal schema that used the following names:
* `create_user` instead of `createUser`
* `user_id` instead of `userId`
* `first_name` instead of `firstName`
* `last_name` instead of `lastName`
Likewise, the result of executing this (camelCase) query document against our
(snake_case) schema would have its names transformed back into camelcase on the
way out:
```
%{
data: %{
"myUser" => %{
"firstName" => "Joe",
"lastName" => "Black"
}
}
}
```
Note variables are a client-facing concern (they may be provided as
parameters), so variable names should match the convention of the query
document (eg, camelCase).
"""
use Absinthe.Adapter
@doc """
Converts a camelCase to snake_case
iex> to_internal_name("test", :read)
"test"
iex> to_internal_name("testTTT", :read)
"test_t_t_t"
iex> to_internal_name("testTest", :read)
"test_test"
iex> to_internal_name("testTest1", :read)
"test_test_1"
iex> to_internal_name("testTest11", :read)
"test_test_11"
iex> to_internal_name("testTest11Pippo", :read)
"test_test_11_pippo"
iex> to_internal_name("camelCase23Snake4344", :read)
"camel_case_23_snake_4344"
"""
def to_internal_name(nil, _role) do
nil
end
def to_internal_name("__" <> camelized_name, role) do
"__" <> to_internal_name(camelized_name, role)
end
def to_internal_name(camelized_name, :operation) do
camelized_name
end
def to_internal_name(camelized_name, _role) do
~r/([A-Z]|\d+)/
|> Regex.replace(camelized_name, "_\\1")
|> String.downcase()
end
defdelegate to_external_name(underscored_name, role), to: Absinthe.Adapter.LanguageConventions
end