Skip to content

Commit

Permalink
Improve param encoding (#223)
Browse files Browse the repository at this point in the history
* improve param encoding

* changelog
  • Loading branch information
ruslandoga authored Dec 20, 2024
1 parent bc0b2a8 commit e8a4431
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased

- gracefully handle `connection: closed` response from server https://github.com/plausible/ch/pull/211
- allow non-UTC `DateTime.t()` in query params https://github.com/plausible/ch/pull/223

## 0.2.9 (2024-11-04)

Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ defaults = [
Note on datetime encoding in query parameters:

- `%NaiveDateTime{}` is encoded as text to make it assume the column's or ClickHouse server's timezone
- `%DateTime{time_zone: "Etc/UTC"}` is encoded as unix timestamp and is treated as UTC timestamp by ClickHouse
- encoding non UTC `%DateTime{}` raises `ArgumentError`
- `%DateTime{}` is encoded as unix timestamp and is treated as UTC timestamp by ClickHouse

#### Insert rows

Expand Down
8 changes: 3 additions & 5 deletions lib/ch/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,9 @@ defimpl DBConnection.Query, for: Ch.Query do
defp encode_param(%Date{} = date), do: Date.to_iso8601(date)
defp encode_param(%NaiveDateTime{} = naive), do: NaiveDateTime.to_iso8601(naive)

defp encode_param(%DateTime{time_zone: "Etc/UTC", microsecond: microsecond} = dt) do
defp encode_param(%DateTime{microsecond: microsecond} = dt) do
dt = DateTime.shift_zone!(dt, "Etc/UTC")

case microsecond do
{val, precision} when val > 0 and precision > 0 ->
size = round(:math.pow(10, precision))
Expand All @@ -242,10 +244,6 @@ defimpl DBConnection.Query, for: Ch.Query do
end
end

defp encode_param(%DateTime{} = dt) do
raise ArgumentError, "non-UTC timezones are not supported for encoding: #{dt}"
end

defp encode_param(tuple) when is_tuple(tuple) do
IO.iodata_to_binary([?(, encode_array_params(Tuple.to_list(tuple)), ?)])
end
Expand Down
14 changes: 14 additions & 0 deletions test/ch/connection_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ defmodule Ch.ConnectionTest do
assert {:ok, %{num_rows: 1, rows: [["a\t"]]}} =
Ch.query(conn, "select {a:String}", %{"a" => "a\t"})

assert {:ok, %{num_rows: 1, rows: [[["a\tb"]]]}} =
Ch.query(conn, "select {a:Array(String)}", %{"a" => ["a\tb"]})

assert {:ok, %{num_rows: 1, rows: [row]}} =
Ch.query(conn, "select {a:Decimal(9,4)}", %{"a" => Decimal.new("2000.333")})

Expand Down Expand Up @@ -127,6 +130,17 @@ defmodule Ch.ConnectionTest do
[[msk, "2021-01-01 15:00:00"]]
end

test "non-utc datetime query param encoding", %{conn: conn} do
jp = DateTime.shift_zone!(~U[2021-01-01 12:34:56Z], "Asia/Tokyo")
assert inspect(jp) == "#DateTime<2021-01-01 21:34:56+09:00 JST Asia/Tokyo>"

assert [[utc, jp]] =
Ch.query!(conn, "select {$0:DateTime('UTC')}, {$0:DateTime('Asia/Tokyo')}", [jp]).rows

assert inspect(utc) == "~U[2021-01-01 12:34:56Z]"
assert inspect(jp) == "#DateTime<2021-01-01 21:34:56+09:00 JST Asia/Tokyo>"
end

test "utc datetime64 query param encoding", %{conn: conn} do
utc = ~U[2021-01-01 12:00:00.123456Z]
msk = DateTime.new!(~D[2021-01-01], ~T[15:00:00.123456], "Europe/Moscow")
Expand Down

0 comments on commit e8a4431

Please sign in to comment.