Reputation: 24107
I have a query in Ecto the includes the sum of a column containing integers. I'm using MySQL as the database.
e.g.
result = Repo.one(
from v in Vote,
where: [post_id: 1],
select: sum(v.direction)
)
IO.inspect(result)
# Yields: #Decimal<5>
The result is returned from Ecto as a #Decimal<x>
. When I encode this to json it's cast to a string. Ideally I'd like it as an integer, especially as the result will always be an integer from the database.
What's the best way to cast this?
Here's my schema:
schema "votes" do
field :direction, :integer
belongs_to :user, Linklet.User
belongs_to :link, Linklet.Link
timestamps()
end
I have managed to achieve the intended result by using MySQL's CONVERT
function within a fragment, but it doesn't seem like the most robust approach:
result = Repo.one(
from v in Vote,
where: [post_id: 1],
select: fragment("CONVERT(?, SIGNED)", sum(v.direction))
)
Is there a better way?
Upvotes: 2
Views: 2194
Reputation: 1601
You can cast to an integer at the database level using Ecto.Query.type/2:
result = Repo.one(
from v in Vote,
where: [post_id: 1],
select: type(sum(v.direction), :integer)
)
Upvotes: 5
Reputation: 222348
SUM
in MySQL returns a DECIMAL
value for integer inputs.
The SUM() and AVG() functions return a DECIMAL value for exact-value arguments (integer or DECIMAL), and a DOUBLE value for approximate-value arguments (FLOAT or DOUBLE).
So you have two options: either convert the value to SIGNED
like you're already doing, or convert the Decimal value to an integer using Decimal.to_integer/1
in Elixir.
Upvotes: 3