Skip to content

Commit 73e1f5a

Browse files
committed
add scalar RowBinary integration tests
1 parent 5ea80a9 commit 73e1f5a

7 files changed

Lines changed: 1039 additions & 3 deletions

lib/ch/http.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,9 @@ defmodule Ch.HTTP do
177177
defp encode_array_param(nil), do: "null"
178178

179179
# DateTime64 array literals parse unquoted numbers as scaled ticks, while
180-
# scalar query params parse the same text as seconds. Quote DateTime values so
180+
# scalar query params parse the same text as seconds. Quote date/time values so
181181
# ClickHouse uses timestamp parsing inside arrays, tuples, and maps too.
182-
defp encode_array_param(%s{} = param) when s in [Date, NaiveDateTime, DateTime] do
182+
defp encode_array_param(%s{} = param) when s in [Date, Time, NaiveDateTime, DateTime] do
183183
[?', encode_param(param), ?']
184184
end
185185

test/ch/query_string_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ defmodule Ch.QueryStringTest do
402402

403403
defp expected_array_param(nil), do: "null"
404404

405-
defp expected_array_param(%value{} = param) when value in [Date, NaiveDateTime, DateTime],
405+
defp expected_array_param(%value{} = param) when value in [Date, Time, NaiveDateTime, DateTime],
406406
do: "'" <> expected_param(param) <> "'"
407407

408408
defp expected_array_param(value), do: expected_param(value)

test/ch/row_binary_bool_test.exs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
defmodule Ch.RowBinaryBoolTest do
2+
use ExUnit.Case, async: true
3+
use ExUnitProperties
4+
5+
alias Ch.RowBinary
6+
7+
setup do
8+
{:ok, pool: start_supervised!(Ch)}
9+
end
10+
11+
property "Bool params round-trip through ClickHouse", %{pool: pool} do
12+
check all value <- boolean() do
13+
assert Ch.query!(pool, "SELECT {value:Bool}", %{"value" => value}).rows == [[value]]
14+
end
15+
end
16+
17+
property "Bool arrays round-trip as query params through ClickHouse", %{pool: pool} do
18+
check all values <- list_of(boolean(), max_length: 16) do
19+
assert Ch.query!(pool, "SELECT {value:Array(Bool)}", %{"value" => values}).rows == [
20+
[values]
21+
]
22+
end
23+
end
24+
25+
test "query params cover nullable, empty arrays, and invalid Bool values", %{pool: pool} do
26+
assert Ch.query!(
27+
pool,
28+
"SELECT {t:Bool}, {f:Bool}, {n:Nullable(Bool)}, {empty:Array(Bool)}",
29+
%{"t" => true, "f" => false, "n" => nil, "empty" => []}
30+
).rows == [[true, false, nil, []]]
31+
32+
assert {:error, %Ch.Error{message: message}} =
33+
Ch.query(pool, "SELECT {value:Bool}", %{"value" => "not-a-bool"})
34+
35+
assert message =~ "Bool"
36+
end
37+
38+
property "RowBinary Bool inserts round-trip through ClickHouse", %{pool: pool} do
39+
Help.query!("""
40+
CREATE TABLE row_binary_bool_property (
41+
id UInt8,
42+
value Bool
43+
) ENGINE Memory
44+
""")
45+
46+
on_exit(fn -> Help.query!("DROP TABLE row_binary_bool_property") end)
47+
48+
check all rows <- rowbinary_bool_rows() do
49+
Ch.query!(pool, "TRUNCATE TABLE row_binary_bool_property")
50+
51+
rowbinary = RowBinary.encode_rows(rows, ["UInt8", "Bool"])
52+
Ch.query!(pool, ["INSERT INTO row_binary_bool_property FORMAT RowBinary\n" | rowbinary])
53+
54+
assert Ch.query!(pool, "SELECT * FROM row_binary_bool_property ORDER BY id").rows ==
55+
Enum.sort_by(rows, &List.first/1)
56+
end
57+
end
58+
59+
test "RowBinary inserts cover nullable, arrays, tuples, maps, and defaults", %{pool: pool} do
60+
Help.query!("""
61+
CREATE TABLE row_binary_bool_representative (
62+
id UInt8,
63+
value Bool,
64+
nullable Nullable(Bool),
65+
bools Array(Bool),
66+
pair Tuple(Bool, Bool),
67+
mapped Map(String, Bool)
68+
) ENGINE Memory
69+
""")
70+
71+
on_exit(fn -> Help.query!("DROP TABLE row_binary_bool_representative") end)
72+
73+
rows = [
74+
[1, true, nil, [], {true, false}, %{}],
75+
[2, false, true, [true, false, true], {false, true}, %{"a" => true, "b" => false}],
76+
[3, nil, false, [false], {true, true}, %{"zero" => false}]
77+
]
78+
79+
types = [
80+
"UInt8",
81+
"Bool",
82+
"Nullable(Bool)",
83+
"Array(Bool)",
84+
"Tuple(Bool, Bool)",
85+
"Map(String, Bool)"
86+
]
87+
88+
rowbinary = RowBinary.encode_rows(rows, types)
89+
Ch.query!(pool, ["INSERT INTO row_binary_bool_representative FORMAT RowBinary\n" | rowbinary])
90+
91+
assert Ch.query!(pool, "SELECT * FROM row_binary_bool_representative ORDER BY id").rows == [
92+
[1, true, nil, [], {true, false}, %{}],
93+
[2, false, true, [true, false, true], {false, true}, %{"a" => true, "b" => false}],
94+
[3, false, false, [false], {true, true}, %{"zero" => false}]
95+
]
96+
end
97+
98+
test "RowBinary rejects invalid Bool values" do
99+
assert_raise FunctionClauseError, fn ->
100+
RowBinary.encode_rows([["true"]], ["Bool"])
101+
end
102+
end
103+
104+
defp rowbinary_bool_rows do
105+
gen all ids <- uniq_list_of(integer(0..255), max_length: 32),
106+
values <- list_of(boolean(), length: length(ids)) do
107+
Enum.zip_with(ids, values, fn id, value -> [id, value] end)
108+
end
109+
end
110+
end

0 commit comments

Comments
 (0)