I decided to change from :float
to :decimal
types in an Phoenix App. And there is a weird case where I post the below mutation:
@desc "Create a wallet"
field :create_wallet, :wallet do
arg(:currency, non_null(:currency_type))
arg(:user_id, non_null(:id))
arg(:units, :decimal)
resolve(&Resolvers.WalletResolver.create_wallet/3)
end
without putting a value for units
argument. This raises the error pointing to the Decimal
library:
POST /api/graphiql
[debug] Processing with Absinthe.Plug.GraphiQL
Parameters: %{"query" => "mutation {\n createWallet(currency: CAD, userId: 1) {\n id\n currency\n units\n user {\n id\n email\n name\n }\n }\n}", "variables" => nil}
Pipelines: [:api]
[debug] ABSINTHE schema=PaymentServerWeb.Schema variables=%{}
---
mutation {
createWallet(currency: CAD, userId: 1) {
id
currency
units
user {
id
email
name
}
}
}
---
[debug] QUERY OK source="wallets" db=1.6ms queue=1.1ms idle=1784.6ms
INSERT INTO "wallets" ("currency","user_id","units","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" [:CAD, 1, 0.0, ~N[2024-04-10 13:43:10], ~N[2024-04-10 13:43:10]]
↳ PaymentServerWeb.Graphql.Resolvers.WalletResolver.create_wallet/3, at: lib/payment_server_web/resolvers/wallet_resolver.ex:23
[debug] QUERY OK source="users" db=1.4ms idle=1790.7ms
SELECT u0."id", u0."email", u0."name", u0."inserted_at", u0."updated_at", u0."id" FROM "users" AS u0 WHERE (u0."id" = $1) [1]
↳ Dataloader.Source.Dataloader.Ecto.run_batch/2, at: lib/dataloader/ecto.ex:703
[info] Sent 500 in 86ms
[error] #PID<0.494.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.478.0>, stream id 2) terminated
Server: localhost:4000 (http)
Request: POST /api/graphiql
** (exit) an exception was raised:
** (FunctionClauseError) no function clause matching in Decimal.to_string/2
(decimal 2.1.1) lib/decimal.ex:1362: Decimal.to_string(0.0, :scientific)
(absinthe 1.7.6) lib/absinthe/phase/document/result.ex:55: Absinthe.Phase.Document.Result.data/2
(absinthe 1.7.6) lib/absinthe/phase/document/result.ex:104: Absinthe.Phase.Document.Result.field_data/3
(absinthe 1.7.6) lib/absinthe/phase/document/result.ex:22: Absinthe.Phase.Document.Result.process/2
(absinthe 1.7.6) lib/absinthe/phase/document/result.ex:11: Absinthe.Phase.Document.Result.run/2
...
Moreover, the wallet was created successfully with the default units
value set to 0.0
.
If I pass is the value for units
in the GraphQL mutation above, it works without error:
debug] Processing with Absinthe.Plug.GraphiQL
Parameters: %{"query" => "mutation {\n createWallet(currency: GBP, userId: 1, units: 30.21) {\n id\n currency\n units\n user {\n id\n email\n name\n }\n }\n}", "variables" => nil}
Pipelines: [:api]
[debug] ABSINTHE schema=PaymentServerWeb.Schema variables=%{}
---
mutation {
createWallet(currency: GBP, userId: 1, units: 30.21) {
id
currency
units
user {
id
email
name
}
}
}
---
[debug] QUERY OK source="wallets" db=2.7ms idle=1577.6ms
INSERT INTO "wallets" ("currency","user_id","units","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" [:GBP, 1, Decimal.new("30.21"), ~N[2024-04-10 13:51:15], ~N[2024-04-10 13:51:15]]
↳ PaymentServerWeb.Graphql.Resolvers.WalletResolver.create_wallet/3, at: lib/payment_server_web/resolvers/wallet_resolver.ex:23
[debug] QUERY OK source="users" db=1.3ms idle=1583.3ms
SELECT u0."id", u0."email", u0."name", u0."inserted_at", u0."updated_at", u0."id" FROM "users" AS u0 WHERE (u0."id" = $1) [1]
A simple test proves it as well:
...
@create_wallet_mutation """
mutation ($currency: CurrencyType!, $userId: ID!, $units: Decimal) {
createWallet(currency: $currency, userId: $userId, units: $units) {
currency
units
user {
id
email
}
}
}
"""
...
test "it should create a new Wallet with valid attributes", %{conn: _conn} do
user = insert(:user)
wallet_input = %{
"currency" => "GBP",
"userId" => user.id,
"units" => 0 # remove this argument and the test will fail!
}
{:ok, ref} =
Absinthe.run(@create_wallet_mutation, PaymentServerWeb.Schema, variables: wallet_input)
expected = %{
data: %{
"createWallet" => get_in(ref, [:data, "createWallet"])
}
}
assert ref == expected
end
Any ideas?