Skip to content

Commit a46c740

Browse files
committed
use decimals for encoding and decoding decimals in cassandra
1 parent c9b2d24 commit a46c740

File tree

4 files changed

+57
-11
lines changed

4 files changed

+57
-11
lines changed

Diff for: lib/xandra/protocol.ex

+15-6
Original file line numberDiff line numberDiff line change
@@ -302,14 +302,20 @@ defmodule Xandra.Protocol do
302302
if boolean, do: [1], else: [0]
303303
end
304304

305-
defp encode_value(:date, date) when date in 0..0xFFFFFFFF do
306-
<<date::32>>
305+
defp encode_value(:decimal, float) when is_float(float) do
306+
encode_value(:decimal, Decimal.new(float))
307+
end
308+
defp encode_value(:decimal, %Decimal{sign: sign, coef: coef, exp: exp}) do
309+
[encode_value(:int, exp), encode_value(:varint, sign * coef)]
307310
end
308-
309311
defp encode_value(:decimal, {value, scale}) do
310312
[encode_value(:int, scale), encode_value(:varint, value)]
311313
end
312314

315+
defp encode_value(:date, date) when date in 0..0xFFFFFFFF do
316+
<<date::32>>
317+
end
318+
313319
defp encode_value(:double, double) when is_float(double) do
314320
<<double::64-float>>
315321
end
@@ -598,12 +604,15 @@ defmodule Xandra.Protocol do
598604

599605
defp decode_value(<<value::8>>, :boolean), do: Kernel.!=(value, 0)
600606

601-
defp decode_value(<<value::32>>, :date), do: value
602-
603607
defp decode_value(<<scale::32-signed, rest::bits>>, :decimal) do
604-
{decode_value(rest, :varint), scale}
608+
coef = decode_value(rest, :varint)
609+
sign = if coef < 0, do: -1, else: 1
610+
coef = coef * sign
611+
%Decimal{sign: sign, coef: coef, exp: scale}
605612
end
606613

614+
defp decode_value(<<value::32>>, :date), do: value
615+
607616
defp decode_value(<<value::64-float>>, :double), do: value
608617

609618
defp decode_value(<<value::32-float>>, :float), do: value

Diff for: mix.exs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ defmodule Xandra.Mixfile do
3838

3939
defp deps() do
4040
[{:db_connection, "~> 1.0"},
41+
{:decimal, "~> 1.0"},
4142
{:snappy, github: "skunkwerks/snappy-erlang-nif", only: [:dev, :test]},
4243
{:ex_doc, "~> 0.14", only: :dev}]
4344
end

Diff for: mix.lock

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
%{"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], []},
2-
"db_connection": {:hex, :db_connection, "1.1.1", "f9d246e8f65b9490945cf7360875eee18fcec9a0115207603215eb1fd94c39ef", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, optional: true]}]},
3-
"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], []},
4-
"ex_doc": {:hex, :ex_doc, "0.14.5", "c0433c8117e948404d93ca69411dd575ec6be39b47802e81ca8d91017a0cf83c", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
1+
%{"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
2+
"db_connection": {:hex, :db_connection, "1.1.1", "f9d246e8f65b9490945cf7360875eee18fcec9a0115207603215eb1fd94c39ef", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
3+
"decimal": {:hex, :decimal, "1.4.0", "fac965ce71a46aab53d3a6ce45662806bdd708a4a95a65cde8a12eb0124a1333", [:mix], [], "hexpm"},
4+
"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], [], "hexpm"},
5+
"ex_doc": {:hex, :ex_doc, "0.14.5", "c0433c8117e948404d93ca69411dd575ec6be39b47802e81ca8d91017a0cf83c", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
56
"snappy": {:git, "https://github.com/skunkwerks/snappy-erlang-nif.git", "0951a1bf8e58141b3c439bebe1f2992688298631", []}}

Diff for: test/integration/datatypes_test.exs

+36-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ defmodule DataTypesTest do
129129
assert Map.fetch!(row, "blob") == <<0, 0xFF>>
130130
assert Map.fetch!(row, "boolean") == true
131131
assert Map.fetch!(row, "date") == 1358013521
132-
assert Map.fetch!(row, "decimal") == {1323, -2}
132+
assert Decimal.equal? Map.fetch!(row, "decimal"), %Decimal{sign: 1, coef: 1323, exp: -2}
133133
assert Map.fetch!(row, "double") == 3.1415
134134
assert Map.fetch!(row, "float") == -1.25
135135
assert Map.fetch!(row, "inet") == {192, 168, 0, 1}
@@ -217,6 +217,41 @@ defmodule DataTypesTest do
217217
assert Map.fetch!(row, "set_of_tinyint") == nil
218218
end
219219

220+
test "passing Decimal types and floats to :decimal columns", %{conn: conn} do
221+
statement = """
222+
CREATE TABLE decimals
223+
(id int PRIMARY KEY,
224+
decimal_from_float decimal,
225+
decimal_from_decimal decimal,
226+
decimal_from_fraction decimal)
227+
"""
228+
Xandra.execute!(conn, statement, [])
229+
230+
statement = """
231+
INSERT INTO decimals
232+
(id,
233+
decimal_from_float,
234+
decimal_from_decimal,
235+
decimal_from_fraction)
236+
VALUES
237+
(#{"?" |> List.duplicate(4) |> Enum.join(", ")})
238+
"""
239+
values = [
240+
{"int", 1},
241+
{"decimal", 0.123456789},
242+
{"decimal", Decimal.new(12.4)},
243+
{"decimal", Decimal.div(Decimal.new(100), Decimal.new(3))}
244+
]
245+
Xandra.execute!(conn, statement, values)
246+
247+
page = Xandra.execute!(conn, "SELECT * FROM decimals WHERE id = 1", [])
248+
assert [row] = Enum.to_list(page)
249+
assert Map.fetch!(row, "id") == 1
250+
assert Decimal.equal? Map.fetch!(row, "decimal_from_float"), %Decimal{sign: 1, coef: 123456789, exp: -9}
251+
assert Decimal.equal? Map.fetch!(row, "decimal_from_decimal"), %Decimal{sign: 1, coef: 124, exp: -1}
252+
assert Decimal.equal? Map.fetch!(row, "decimal_from_fraction"), %Decimal{sign: 1, coef: 3333333333333333333333333333, exp: -26}
253+
end
254+
220255
test "user-defined types", %{conn: conn} do
221256
statement = """
222257
CREATE TYPE full_name

0 commit comments

Comments
 (0)