Skip to content

Commit 46b7a8f

Browse files
author
Philip Sampaio
authored
Add query/4 that can receive a Req.Request (#6)
* Add `query/4` that can receive a `Req.Request` * Remove query/3 and add query/4 defaults
1 parent 3d397d7 commit 46b7a8f

File tree

2 files changed

+68
-38
lines changed

2 files changed

+68
-38
lines changed

lib/req_ch.ex

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -72,71 +72,84 @@ defmodule ReqCH do
7272
defguardp is_query_params(value) when is_list(value) or is_map(value)
7373

7474
@doc """
75-
Performs a query against ClickHouse API.
75+
Performs a query against the ClickHouse API.
7676
77-
See docs from `new/1` for details about the options.
77+
This version receives a `Req.Request.t()`, so it won't
78+
create a new one from scratch.
79+
80+
By default, it will use the `http://localhost:8123` as `:base_url`.
81+
You can change that either providing in your Req request, or in passing
82+
down in the options.
83+
See `new/1` for the options. Like that function, `query/4` accepts any
84+
option that `Req.new/1` accepts.
7885
7986
## Examples
8087
8188
Queries can be performed using both `Req.get/2` or `Req.post/2`, but GET
8289
is "read-only" and commands like `CREATE` or `INSERT` cannot be used with it.
8390
For that reason, by default we perform a `POST` request.
84-
To change that, use `query/2` with a pre-configured `req`.
8591
8692
A plain query:
8793
88-
iex> {:ok, response} = ReqCH.query("SELECT number FROM system.numbers LIMIT 3")
94+
iex> req = ReqCH.new(database: "system")
95+
iex> {:ok, response} = ReqCH.query(req, "SELECT number FROM numbers LIMIT 3")
8996
iex> response.body
9097
"0\\n1\\n2\\n"
9198
92-
Changing the format to `:explorer` will return a dataframe:
99+
With a specific format:
93100
94-
iex> {:ok, response} = ReqCH.query("SELECT number FROM system.numbers LIMIT 3", [], format: :explorer)
101+
iex> req = ReqCH.new(database: "system")
102+
iex> {:ok, response} = ReqCH.query(req, "SELECT number FROM numbers LIMIT 3", [], [format: :explorer])
95103
iex> response.body
96104
#Explorer.DataFrame<
97105
Polars[3 x 1]
98106
number u64 [0, 1, 2]
99107
>
100108
101-
Using parameters is also possible:
109+
Passing SQL params:
102110
103-
iex> opts = [format: :explorer, database: "system"]
104-
iex> {:ok, response} = ReqCH.query("SELECT number FROM numbers WHERE number > {num:UInt8} LIMIT 3", [num: 5], opts)
105-
#Explorer.DataFrame<
106-
Polars[3 x 1]
107-
number u64 [6, 7, 8]
108-
>
111+
iex> req = ReqCH.new(database: "system")
112+
iex> {:ok, response} = ReqCH.query(req, "SELECT number FROM numbers WHERE number > {num:UInt8} LIMIT 3", [num: 5], [])
113+
iex> response.body
114+
"6\\n7\\n8\\n"
109115
110116
This function can accept `Req` options, as well as mixing them with `ReqCH` options:
111117
112118
iex> opts = [base_url: "http://example.org:8123", database: "system", auth: {:basic, "user:pass"}]
113-
iex> {:ok, response} = ReqCH.query("SELECT number FROM numbers LIMIT 3", [], opts)
119+
iex> {:ok, response} = ReqCH.query(ReqCH.new(), "SELECT number FROM numbers LIMIT 3", [], opts)
114120
iex> response.body
115121
"0\\n1\\n2\\n"
116122
117123
"""
118-
@spec query(sql_query :: binary(), params :: Map.t() | Keyword.t(), opts :: Keyword.t()) ::
119-
{:ok, Req.Response.t()} | {:error, binary()}
120-
def query(sql_query, params \\ [], opts \\ [])
121-
122-
def query(sql_query, params, opts)
123-
when is_binary(sql_query) and is_query_params(params) and is_list(opts) do
124-
opts
125-
|> new()
126-
|> put_params(prepare_params(params))
124+
@spec query(
125+
Req.t(),
126+
sql_query :: binary(),
127+
sql_query_params :: Map.t() | Keyword.t(),
128+
opts :: Keyword.t()
129+
) :: {:ok, Req.Response.t()} | {:error, binary()}
130+
def query(req, sql_query, sql_query_params \\ [], opts \\ [])
131+
132+
def query(%Req.Request{} = req, sql_query, sql_query_params, opts)
133+
when is_binary(sql_query) and is_query_params(sql_query_params) and is_list(opts) do
134+
req
135+
|> attach(opts)
136+
|> put_params(prepare_params(sql_query_params))
127137
|> Req.post(body: sql_query)
128138
end
129139

130140
@doc """
131-
Same as `query/3`, but raises in case of error.
141+
Same as `query/4`, but raises in case of error.
132142
"""
133-
@spec query!(sql_query :: binary(), params :: Map.t() | Keyword.t(), opts :: Keyword.t()) ::
134-
Req.Response.t()
135-
def query!(sql_query, params \\ [], opts \\ [])
136-
137-
def query!(sql_query, params, opts)
138-
when is_binary(sql_query) and is_query_params(params) and is_list(opts) do
139-
case query(sql_query, params, opts) do
143+
@spec query!(
144+
Req.t(),
145+
sql_query :: binary(),
146+
sql_query_params :: Map.t() | Keyword.t(),
147+
opts :: Keyword.t()
148+
) :: Req.Response.t()
149+
def query!(req, sql_query, sql_query_params \\ [], opts \\ [])
150+
151+
def query!(%Req.Request{} = req, sql_query, sql_query_params, opts) do
152+
case query(req, sql_query, sql_query_params, opts) do
140153
{:ok, response} -> response
141154
{:error, exception} -> raise exception
142155
end

test/req_ch_test.exs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,12 @@ defmodule ReqCHTest do
5858
end
5959
end
6060

61-
describe "query/3" do
61+
describe "query/4" do
6262
test "a plain query with defaults" do
63+
req = ReqCH.new(database: "system")
64+
6365
assert {:ok, %Req.Response{} = response} =
64-
ReqCH.query("SELECT number FROM system.numbers LIMIT 3")
66+
ReqCH.query(req, "SELECT number FROM numbers LIMIT 3", [], [])
6567

6668
assert response.status == 200
6769

@@ -72,22 +74,32 @@ defmodule ReqCHTest do
7274
"""
7375
end
7476

75-
test "a plain query with database" do
77+
test "a query with params and database in opts" do
78+
req = ReqCH.new()
79+
7680
assert {:ok, %Req.Response{} = response} =
77-
ReqCH.query("SELECT number FROM numbers LIMIT 3", [], database: "system")
81+
ReqCH.query(
82+
req,
83+
"SELECT number FROM numbers WHERE number > {num:UInt8} LIMIT 3",
84+
[num: 25],
85+
database: "system"
86+
)
7887

7988
assert response.status == 200
8089

8190
assert response.body == """
82-
0
83-
1
84-
2
91+
26
92+
27
93+
28
8594
"""
8695
end
8796

8897
test "with format option as :explorer" do
98+
req = ReqCH.new()
99+
89100
assert {:ok, %Req.Response{} = response} =
90101
ReqCH.query(
102+
req,
91103
"SELECT number, number - 2 as less_two from system.numbers LIMIT 10",
92104
[],
93105
format: :explorer
@@ -105,6 +117,7 @@ defmodule ReqCHTest do
105117
test "with format option as :explorer but different format in the query" do
106118
assert {:ok, %Req.Response{} = response} =
107119
ReqCH.query(
120+
ReqCH.new(),
108121
"SELECT number, number - 2 as less_two from system.numbers LIMIT 10 FORMAT JSON",
109122
format: :explorer
110123
)
@@ -141,6 +154,7 @@ defmodule ReqCHTest do
141154
test "with format :json" do
142155
assert {:ok, %Req.Response{} = response} =
143156
ReqCH.query(
157+
ReqCH.new(),
144158
"SELECT number, number - 2 as less_two from system.numbers LIMIT 3",
145159
[],
146160
format: :json
@@ -170,6 +184,7 @@ defmodule ReqCHTest do
170184

171185
assert_raise ArgumentError, error_message, fn ->
172186
ReqCH.query(
187+
ReqCH.new(),
173188
"SELECT number from system.numbers LIMIT 10",
174189
[],
175190
format: :invalid_format
@@ -180,6 +195,7 @@ defmodule ReqCHTest do
180195
test "a query with params" do
181196
assert {:ok, %Req.Response{} = response} =
182197
ReqCH.query(
198+
ReqCH.new(),
183199
"SELECT number FROM system.numbers WHERE number > {num:UInt8} LIMIT 7",
184200
num: 5
185201
)
@@ -200,6 +216,7 @@ defmodule ReqCHTest do
200216
test "a query with unknown database" do
201217
assert {:ok, %Req.Response{} = response} =
202218
ReqCH.query(
219+
ReqCH.new(),
203220
"SELECT number FROM sistema WHERE number > {num:UInt8} LIMIT 7",
204221
num: 5
205222
)

0 commit comments

Comments
 (0)