Skip to content

Commit f215a43

Browse files
committedFeb 17, 2020
format code
1 parent 2fd1223 commit f215a43

13 files changed

+492
-270
lines changed
 

‎.formatter.exs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]

‎lib/clickhouse_ecto.ex

+7-7
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@ defmodule ClickhouseEcto do
1212

1313
import ClickhouseEcto.Type, only: [encode: 2, decode: 2]
1414

15-
def autogenerate(:binary_id), do: Ecto.UUID.generate()
16-
def autogenerate(type), do: super(type)
15+
def autogenerate(:binary_id), do: Ecto.UUID.generate()
16+
def autogenerate(type), do: super(type)
1717

1818
def dumpers({:embed, _} = type, _), do: [&Ecto.Adapters.SQL.dump_embed(type, &1)]
19-
def dumpers(:binary_id, _type), do: []
20-
def dumpers(:uuid, _type), do: []
21-
def dumpers(ecto_type, type), do: [type, &(encode(&1, ecto_type))]
19+
def dumpers(:binary_id, _type), do: []
20+
def dumpers(:uuid, _type), do: []
21+
def dumpers(ecto_type, type), do: [type, &encode(&1, ecto_type)]
2222

2323
def loaders({:embed, _} = type, _), do: [&Ecto.Adapters.SQL.load_embed(type, &1)]
24-
def loaders(ecto_type, type), do: [&(decode(&1, ecto_type)), type]
24+
def loaders(ecto_type, type), do: [&decode(&1, ecto_type), type]
2525

2626
## Migration
27-
def supports_ddl_transaction?, do: Migration.supports_ddl_transaction?
27+
def supports_ddl_transaction?, do: Migration.supports_ddl_transaction?()
2828

2929
## Storage
3030
def storage_up(opts), do: Storage.storage_up(opts)

‎lib/clickhouse_ecto/connection.ex

+52-15
Original file line numberDiff line numberDiff line change
@@ -3,73 +3,102 @@ defmodule ClickhouseEcto.Connection do
33
alias ClickhouseEcto.Query, as: SQL
44

55
@typedoc "The prepared query which is an SQL command"
6-
@type prepared :: String.t
6+
@type prepared :: String.t()
77

88
@typedoc "The cache query which is a DBConnection Query"
99
@type cached :: map
1010

1111
@doc """
1212
Receives options and returns `DBConnection` supervisor child specification.
1313
"""
14-
@spec child_spec(options :: Keyword.t) :: {module, Keyword.t}
14+
@spec child_spec(options :: Keyword.t()) :: {module, Keyword.t()}
1515
def child_spec(opts) do
1616
DBConnection.child_spec(Clickhousex.Protocol, opts)
1717
end
1818

1919
@doc """
2020
Prepares and executes the given query with `DBConnection`.
2121
"""
22-
@spec prepare_execute(connection :: DBConnection.t, name :: String.t, prepared, params :: [term], options :: Keyword.t) ::
23-
{:ok, query :: map, term} | {:error, Exception.t}
22+
@spec prepare_execute(
23+
connection :: DBConnection.t(),
24+
name :: String.t(),
25+
prepared,
26+
params :: [term],
27+
options :: Keyword.t()
28+
) ::
29+
{:ok, query :: map, term} | {:error, Exception.t()}
2430
def prepare_execute(conn, name, prepared_query, params, options) do
2531
query = %Query{name: name, statement: prepared_query}
32+
2633
case DBConnection.prepare_execute(conn, query, params, options) do
2734
{:ok, query, result} ->
2835
{:ok, %{query | statement: prepared_query}, process_rows(result, options)}
36+
2937
{:error, %Clickhousex.Error{}} = error ->
3038
if is_no_data_found_bug?(error, prepared_query) do
3139
{:ok, %Query{name: "", statement: prepared_query}, %{num_rows: 0, rows: []}}
3240
else
3341
error
3442
end
35-
{:error, error} -> raise error
43+
44+
{:error, error} ->
45+
raise error
3646
end
3747
end
3848

3949
@doc """
4050
Executes the given prepared query with `DBConnection`.
4151
"""
42-
@spec execute(connection :: DBConnection.t, prepared_query :: prepared, params :: [term], options :: Keyword.t) ::
43-
{:ok, term} | {:error, Exception.t}
44-
@spec execute(connection :: DBConnection.t, prepared_query :: cached, params :: [term], options :: Keyword.t) ::
45-
{:ok, term} | {:error | :reset, Exception.t}
52+
@spec execute(
53+
connection :: DBConnection.t(),
54+
prepared_query :: prepared,
55+
params :: [term],
56+
options :: Keyword.t()
57+
) ::
58+
{:ok, term} | {:error, Exception.t()}
59+
@spec execute(
60+
connection :: DBConnection.t(),
61+
prepared_query :: cached,
62+
params :: [term],
63+
options :: Keyword.t()
64+
) ::
65+
{:ok, term} | {:error | :reset, Exception.t()}
4666
def execute(conn, %Query{} = query, params, options) do
4767
case DBConnection.prepare_execute(conn, query, params, options) do
4868
{:ok, _query, result} ->
4969
{:ok, process_rows(result, options)}
70+
5071
{:error, %Clickhousex.Error{}} = error ->
5172
if is_no_data_found_bug?(error, query.statement) do
5273
{:ok, %{num_rows: 0, rows: []}}
5374
else
5475
error
5576
end
56-
{:error, error} -> raise error
77+
78+
{:error, error} ->
79+
raise error
5780
end
5881
end
82+
5983
def execute(conn, statement, params, options) do
6084
execute(conn, %Query{name: "", statement: statement}, params, options)
6185
end
6286

6387
defp is_no_data_found_bug?({:error, error}, statement) do
64-
is_dml = statement
88+
is_dml =
89+
statement
6590
|> IO.iodata_to_binary()
66-
|> (fn string -> String.starts_with?(string, "INSERT") || String.starts_with?(string, "DELETE") || String.starts_with?(string, "UPDATE") end).()
91+
|> (fn string ->
92+
String.starts_with?(string, "INSERT") || String.starts_with?(string, "DELETE") ||
93+
String.starts_with?(string, "UPDATE")
94+
end).()
6795

68-
is_dml and error.message =~ "No SQL-driver information available."
96+
is_dml and error.message =~ "No SQL-driver information available."
6997
end
7098

7199
defp process_rows(result, options) do
72100
decoder = options[:decode_mapper] || fn x -> x end
101+
73102
Map.update!(result, :rows, fn row ->
74103
unless is_nil(row), do: Enum.map(row, decoder)
75104
end)
@@ -80,8 +109,13 @@ defmodule ClickhouseEcto.Connection do
80109
@doc """
81110
Returns a stream that prepares and executes the given query with `DBConnection`.
82111
"""
83-
@spec stream(connection :: DBConnection.conn, prepared_query :: prepared, params :: [term], options :: Keyword.t) ::
84-
Enum.t
112+
@spec stream(
113+
connection :: DBConnection.conn(),
114+
prepared_query :: prepared,
115+
params :: [term],
116+
options :: Keyword.t()
117+
) ::
118+
Enum.t()
85119
def stream(_conn, _prepared, _params, _options) do
86120
raise("not implemented")
87121
end
@@ -90,14 +124,17 @@ defmodule ClickhouseEcto.Connection do
90124
def all(query) do
91125
SQL.all(query)
92126
end
127+
93128
def update_all(query, prefix \\ nil), do: SQL.update_all(query, prefix)
94129
@doc false
95130
def delete_all(query), do: SQL.delete_all(query)
96131

97132
def insert(prefix, table, header, rows, on_conflict, returning),
98133
do: SQL.insert(prefix, table, header, rows, on_conflict, returning)
134+
99135
def update(prefix, table, fields, filters, returning),
100136
do: SQL.update(prefix, table, fields, filters, returning)
137+
101138
def delete(prefix, table, filters, returning),
102139
do: SQL.delete(prefix, table, filters, returning)
103140

‎lib/clickhouse_ecto/helpers.ex

+32-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
defmodule ClickhouseEcto.Helpers do
2-
32
alias ClickhouseEcto.QueryString
43

54
def get_source(query, sources, ix, source) do
@@ -14,51 +13,63 @@ defmodule ClickhouseEcto.Helpers do
1413

1514
def quote_name(name, quoter \\ ?")
1615
def quote_name(nil, _), do: []
16+
1717
def quote_name(names, quoter) when is_list(names) do
1818
names
1919
|> Enum.filter(&(not is_nil(&1)))
20-
|> intersperse_map(?., &(quote_name(&1, nil)))
20+
|> intersperse_map(?., &quote_name(&1, nil))
2121
|> wrap_in(quoter)
2222
end
23+
2324
def quote_name(name, quoter) when is_atom(name) do
2425
quote_name(Atom.to_string(name), quoter)
2526
end
27+
2628
def quote_name(name, quoter) do
2729
if String.contains?(name, "\"") do
28-
error!(nil, "bad name #{inspect name}")
30+
error!(nil, "bad name #{inspect(name)}")
2931
end
32+
3033
wrap_in(name, quoter)
3134
end
3235

3336
def wrap_in(value, nil), do: value
37+
3438
def wrap_in(value, {left_wrapper, right_wrapper}) do
3539
[left_wrapper, value, right_wrapper]
3640
end
41+
3742
def wrap_in(value, wrapper) do
3843
[wrapper, value, wrapper]
3944
end
4045

4146
def quote_table(prefix, name)
42-
def quote_table(nil, name), do: quote_name(name)
47+
def quote_table(nil, name), do: quote_name(name)
4348
def quote_table(prefix, name), do: intersperse_map([prefix, name], ?., &quote_name/1)
4449

4550
def single_quote(value), do: value |> escape_string |> wrap_in(?')
4651

4752
def intersperse_map(list, separator, mapper, acc \\ [])
53+
4854
def intersperse_map([], _separator, _mapper, acc),
4955
do: acc
56+
5057
def intersperse_map([elem], _separator, mapper, acc),
5158
do: [acc | mapper.(elem)]
59+
5260
def intersperse_map([elem | rest], separator, mapper, acc),
5361
do: intersperse_map(rest, separator, mapper, [acc, mapper.(elem), separator])
5462

5563
def intersperse_reduce(list, separator, user_acc, reducer, acc \\ [])
64+
5665
def intersperse_reduce([], _separator, user_acc, _reducer, acc),
5766
do: {acc, user_acc}
67+
5868
def intersperse_reduce([elem], _separator, user_acc, reducer, acc) do
5969
{elem, user_acc} = reducer.(elem, user_acc)
6070
{[acc | elem], user_acc}
6171
end
72+
6273
def intersperse_reduce([elem | rest], separator, user_acc, reducer, acc) do
6374
{elem, user_acc} = reducer.(elem, user_acc)
6475
intersperse_reduce(rest, separator, user_acc, reducer, [acc, elem, separator])
@@ -67,6 +78,7 @@ defmodule ClickhouseEcto.Helpers do
6778
def if_do(condition, value) do
6879
if condition, do: value, else: []
6980
end
81+
7082
def if_do(condition, value, else_value) do
7183
if condition, do: value, else: else_value
7284
end
@@ -75,28 +87,28 @@ defmodule ClickhouseEcto.Helpers do
7587
:binary.replace(value, "'", "''", [:global])
7688
end
7789

78-
def ecto_to_db({:array, t}), do: "Array(#{ecto_to_db(t)})"
79-
def ecto_to_db(:id), do: "UInt32"
80-
def ecto_to_db(:binary_id), do: "FixedString(36)"
81-
def ecto_to_db(:uuid), do: "FixedString(36)"
82-
def ecto_to_db(:string), do: "String"
83-
def ecto_to_db(:binary), do: "FixedString(4000)"
84-
def ecto_to_db(:integer), do: "Int32"
85-
def ecto_to_db(:bigint), do: "Int64"
86-
def ecto_to_db(:float), do: "Float32"
87-
def ecto_to_db(:decimal), do: "Float64"
88-
def ecto_to_db(:boolean), do: "UInt8"
89-
def ecto_to_db(:date), do: "Date"
90-
def ecto_to_db(:utc_datetime), do: "DateTime"
90+
def ecto_to_db({:array, t}), do: "Array(#{ecto_to_db(t)})"
91+
def ecto_to_db(:id), do: "UInt32"
92+
def ecto_to_db(:binary_id), do: "FixedString(36)"
93+
def ecto_to_db(:uuid), do: "FixedString(36)"
94+
def ecto_to_db(:string), do: "String"
95+
def ecto_to_db(:binary), do: "FixedString(4000)"
96+
def ecto_to_db(:integer), do: "Int32"
97+
def ecto_to_db(:bigint), do: "Int64"
98+
def ecto_to_db(:float), do: "Float32"
99+
def ecto_to_db(:decimal), do: "Float64"
100+
def ecto_to_db(:boolean), do: "UInt8"
101+
def ecto_to_db(:date), do: "Date"
102+
def ecto_to_db(:utc_datetime), do: "DateTime"
91103
def ecto_to_db(:naive_datetime), do: "DateTime"
92-
def ecto_to_db(:timestamp), do: "DateTime"
93-
def ecto_to_db(other), do: Atom.to_string(other)
104+
def ecto_to_db(:timestamp), do: "DateTime"
105+
def ecto_to_db(other), do: Atom.to_string(other)
94106

95107
def error!(nil, message) do
96108
raise ArgumentError, message
97109
end
110+
98111
def error!(query, message) do
99112
raise Ecto.QueryError, query: query, message: message
100113
end
101-
102114
end

‎lib/clickhouse_ecto/migration.ex

+104-49
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,43 @@ defmodule ClickhouseEcto.Migration do
99
@doc """
1010
Receives a DDL command and returns a query that executes it.
1111
"""
12-
@spec execute_ddl(command :: Ecto.Adapter.Migration.command) :: String.t
13-
def execute_ddl({command, %Table{} = table, columns}) when command in [:create, :create_if_not_exists] do
12+
@spec execute_ddl(command :: Ecto.Adapter.Migration.command()) :: String.t()
13+
def execute_ddl({command, %Table{} = table, columns})
14+
when command in [:create, :create_if_not_exists] do
1415
engine = table.engine
1516

1617
{_, first_column_name, _, _} = List.first(columns)
17-
filtered_columns = cond do
18-
first_column_name == :id ->
19-
List.delete_at(columns, 0)
20-
true ->
21-
columns
22-
end
2318

24-
query = [if_do(command == :create_if_not_exists, "CREATE TABLE IF NOT EXISTS ", "CREATE TABLE "),
25-
quote_table(table.prefix, table.name), ?\s, ?(,
26-
column_definitions(table, filtered_columns), ?),
27-
options_expr(table.options),
28-
if_do(engine != nil, " ENGINE = #{engine} ", " ENGINE = TinyLog ")]
19+
filtered_columns =
20+
cond do
21+
first_column_name == :id ->
22+
List.delete_at(columns, 0)
23+
24+
true ->
25+
columns
26+
end
27+
28+
query = [
29+
if_do(command == :create_if_not_exists, "CREATE TABLE IF NOT EXISTS ", "CREATE TABLE "),
30+
quote_table(table.prefix, table.name),
31+
?\s,
32+
?(,
33+
column_definitions(table, filtered_columns),
34+
?),
35+
options_expr(table.options),
36+
if_do(engine != nil, " ENGINE = #{engine} ", " ENGINE = TinyLog ")
37+
]
2938

3039
[query]
3140
end
3241

3342
def execute_ddl({command, %Table{} = table}) when command in @drops do
34-
[[if_do(command == :drop_if_exists, "DROP TABLE IF EXISTS ", "DROP TABLE "),
35-
quote_table(table.prefix, table.name)
36-
]]
43+
[
44+
[
45+
if_do(command == :drop_if_exists, "DROP TABLE IF EXISTS ", "DROP TABLE "),
46+
quote_table(table.prefix, table.name)
47+
]
48+
]
3749
end
3850

3951
def execute_ddl({:alter, %Table{} = table, changes}) do
@@ -44,8 +56,14 @@ defmodule ClickhouseEcto.Migration do
4456

4557
# TODO: Add 'ON CLUSTER' option.
4658
def execute_ddl({:rename, %Table{} = current_table, %Table{} = new_table}) do
47-
[["RENAME TABLE ", quote_name([current_table.prefix, current_table.name]),
48-
" TO ", quote_name(new_table.name)]]
59+
[
60+
[
61+
"RENAME TABLE ",
62+
quote_name([current_table.prefix, current_table.name]),
63+
" TO ",
64+
quote_name(new_table.name)
65+
]
66+
]
4967
end
5068

5169
def execute_ddl({:rename, %Table{} = table, current_column, new_column}) do
@@ -66,6 +84,7 @@ defmodule ClickhouseEcto.Migration do
6684
## Helpers
6785

6886
defp quote_alter([], _table), do: []
87+
6988
defp quote_alter(statement, table),
7089
do: ["ALTER TABLE ", quote_table(table.prefix, table.name), statement, "; "]
7190

@@ -74,49 +93,63 @@ defmodule ClickhouseEcto.Migration do
7493
end
7594

7695
defp column_definition(table, {:add, name, %Reference{} = ref, opts}) do
77-
[quote_name(name), ?\s,
78-
column_options(ref.type, opts, table, name)
79-
]
96+
[quote_name(name), ?\s, column_options(ref.type, opts, table, name)]
8097
end
8198

8299
defp column_definition(table, {:add, name, type, opts}) do
83-
[quote_name(name), ?\s, column_type(type, opts),
84-
column_options(type, opts, table, name)]
100+
[quote_name(name), ?\s, column_type(type, opts), column_options(type, opts, table, name)]
85101
end
86102

87103
defp column_changes(table, columns) do
88-
{additions, changes} = Enum.split_with(columns,
89-
fn val -> elem(val, 0) == :add end)
90-
[if_do(additions !== [], column_additions(additions, table)),
91-
if_do(changes !== [], Enum.map(changes, &column_change(table, &1)))]
104+
{additions, changes} =
105+
Enum.split_with(
106+
columns,
107+
fn val -> elem(val, 0) == :add end
108+
)
109+
110+
[
111+
if_do(additions !== [], column_additions(additions, table)),
112+
if_do(changes !== [], Enum.map(changes, &column_change(table, &1)))
113+
]
92114
end
93115

94116
defp column_additions(additions, table) do
95-
Enum.map(additions, fn(addition) ->
117+
Enum.map(additions, fn addition ->
96118
[" ADD COLUMN ", column_change(table, addition)]
97119
end)
98120
|> Enum.join(",")
99121
|> quote_alter(table)
100122
end
101123

102124
defp column_change(table, {:add, name, %Reference{} = ref, opts}) do
103-
[quote_name(name), ?\s,
104-
column_options(ref.type, opts, table, name)]
125+
[quote_name(name), ?\s, column_options(ref.type, opts, table, name)]
105126
end
106127

107128
defp column_change(table, {:add, name, type, opts}) do
108-
[quote_name(name), ?\s, column_type(type, opts),
109-
column_options(type, opts, table, name)]
129+
[quote_name(name), ?\s, column_type(type, opts), column_options(type, opts, table, name)]
110130
end
111131

112132
defp column_change(table, {:modify, name, %Reference{} = ref, opts}) do
113-
[quote_alter([" MODIFY COLUMN ", quote_name(name), ?\s, modify_null(name, opts)], table),
114-
modify_default(name, ref.type, opts, table, name)]
133+
[
134+
quote_alter([" MODIFY COLUMN ", quote_name(name), ?\s, modify_null(name, opts)], table),
135+
modify_default(name, ref.type, opts, table, name)
136+
]
115137
end
116138

117139
defp column_change(table, {:modify, name, type, opts}) do
118-
[quote_alter([" MODIFY COLUMN ", quote_name(name), ?\s, column_type(type, opts),
119-
modify_null(name, opts)], table), modify_default(name, type, opts, table, name)]
140+
[
141+
quote_alter(
142+
[
143+
" MODIFY COLUMN ",
144+
quote_name(name),
145+
?\s,
146+
column_type(type, opts),
147+
modify_null(name, opts)
148+
],
149+
table
150+
),
151+
modify_default(name, type, opts, table, name)
152+
]
120153
end
121154

122155
defp column_change(table, {:remove, name}) do
@@ -134,70 +167,92 @@ defmodule ClickhouseEcto.Migration do
134167
case Keyword.fetch(opts, :default) do
135168
{:ok, val} ->
136169
[
137-
quote_alter([" ADD", default_expr({:ok, val}, type, table, name), " FOR ", quote_name(name)], table)]
138-
:error -> []
170+
quote_alter(
171+
[" ADD", default_expr({:ok, val}, type, table, name), " FOR ", quote_name(name)],
172+
table
173+
)
174+
]
175+
176+
:error ->
177+
[]
139178
end
140179
end
141180

142181
defp column_options(type, opts, table, name) do
143182
default = Keyword.fetch(opts, :default)
144-
null = Keyword.get(opts, :null)
183+
null = Keyword.get(opts, :null)
145184
[default_expr(default, type, table, name), null_expr(null)]
146185
end
147186

148-
#defp null_expr(false), do: " NOT NULL"
187+
# defp null_expr(false), do: " NOT NULL"
149188
defp null_expr(false), do: " "
150189
defp null_expr(true), do: " NULL"
151190
defp null_expr(_), do: []
152191

153192
defp default_expr({:ok, _} = default, type, table, name),
154193
do: [default_expr(default, type)]
194+
155195
defp default_expr(:error, _, _, _),
156196
do: []
197+
157198
defp default_expr({:ok, nil}, _type),
158199
do: error!(nil, "NULL is not supported")
200+
159201
defp default_expr({:ok, []}, _type),
160202
do: error!(nil, "arrays are not supported")
203+
161204
defp default_expr({:ok, literal}, _type) when is_binary(literal),
162205
do: [" DEFAULT '", escape_string(literal), ?']
206+
163207
defp default_expr({:ok, literal}, _type) when is_number(literal),
164208
do: [" DEFAULT ", to_string(literal)]
209+
165210
defp default_expr({:ok, literal}, _type) when is_boolean(literal),
166211
do: [" DEFAULT ", to_string(if literal, do: 1, else: 0)]
212+
167213
defp default_expr({:ok, :today}, :date),
168-
do: [" DEFAULT today()"]
214+
do: [" DEFAULT today()"]
215+
169216
defp default_expr({:ok, {:fragment, expr}}, _type),
170217
do: [" DEFAULT ", expr]
218+
171219
defp default_expr({:ok, expr}, type),
172-
do: raise(ArgumentError, "unknown default `#{inspect expr}` for type `#{inspect type}`. " <>
173-
":default may be a string, number, boolean, empty list or a fragment(...)")
220+
do:
221+
raise(
222+
ArgumentError,
223+
"unknown default `#{inspect(expr)}` for type `#{inspect(type)}`. " <>
224+
":default may be a string, number, boolean, empty list or a fragment(...)"
225+
)
174226

175227
defp index_expr(literal) when is_binary(literal),
176228
do: literal
229+
177230
defp index_expr(literal),
178231
do: quote_name(literal)
179232

180233
defp options_expr(nil),
181234
do: []
235+
182236
defp options_expr(keyword) when is_list(keyword),
183237
do: error!(nil, "ClickHouse adapter does not support keyword lists in :options")
238+
184239
defp options_expr(options),
185240
do: [?\s, options]
186241

187242
defp column_type({:array, type}, opts),
188243
do: [column_type(type, opts), "[]"]
244+
189245
defp column_type(type, opts) do
190-
size = Keyword.get(opts, :size)
246+
size = Keyword.get(opts, :size)
191247
precision = Keyword.get(opts, :precision)
192-
scale = Keyword.get(opts, :scale)
248+
scale = Keyword.get(opts, :scale)
193249
type_name = ecto_to_db(type)
194250

195251
cond do
196-
size -> [type_name, ?(, to_string(size), ?)]
197-
precision -> [type_name, ?(, to_string(precision), ?,, to_string(scale || 0), ?)]
252+
size -> [type_name, ?(, to_string(size), ?)]
253+
precision -> [type_name, ?(, to_string(precision), ?,, to_string(scale || 0), ?)]
198254
type == :string -> [type_name, " "]
199-
true -> type_name
255+
true -> type_name
200256
end
201257
end
202-
203258
end

‎lib/clickhouse_ecto/query.ex

+44-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
defmodule ClickhouseEcto.Query do
2-
32
alias ClickhouseEcto.QueryString
43

54
import ClickhouseEcto.Helpers
@@ -9,23 +8,23 @@ defmodule ClickhouseEcto.Query do
98
@doc """
109
Receives a query and must return a SELECT query.
1110
"""
12-
@spec all(query :: Ecto.Query.t) :: String.t
11+
@spec all(query :: Ecto.Query.t()) :: String.t()
1312
def all(query) do
1413
sources = QueryString.create_names(query)
1514
{select_distinct, order_by_distinct} = QueryString.distinct(query.distinct, sources, query)
1615

17-
from = QueryString.from(query, sources)
18-
select = QueryString.select(query, select_distinct, sources)
19-
join = QueryString.join(query, sources)
20-
where = QueryString.where(query, sources)
16+
from = QueryString.from(query, sources)
17+
select = QueryString.select(query, select_distinct, sources)
18+
join = QueryString.join(query, sources)
19+
where = QueryString.where(query, sources)
2120
group_by = QueryString.group_by(query, sources)
22-
having = QueryString.having(query, sources)
21+
having = QueryString.having(query, sources)
2322
order_by = QueryString.order_by(query, order_by_distinct, sources)
24-
limit = QueryString.limit(query, sources)
25-
#lock = QueryString.lock(query.lock)
23+
limit = QueryString.limit(query, sources)
24+
# lock = QueryString.lock(query.lock)
2625

27-
#res = [select, from, join, where, group_by, having, order_by, lock]
28-
#res = [select, from, join, where, group_by, having, order_by, offset | lock]
26+
# res = [select, from, join, where, group_by, having, order_by, lock]
27+
# res = [select, from, join, where, group_by, having, order_by, offset | lock]
2928
res = [select, from, join, where, group_by, having, order_by, limit]
3029

3130
IO.iodata_to_binary(res)
@@ -35,29 +34,41 @@ defmodule ClickhouseEcto.Query do
3534
Returns an INSERT for the given `rows` in `table` returning
3635
the given `returning`.
3736
"""
38-
@spec insert(prefix ::String.t, table :: String.t,
39-
header :: [atom], rows :: [[atom | nil]],
40-
on_conflict :: Ecto.Adapter.on_conflict, returning :: [atom]) :: String.t
37+
@spec insert(
38+
prefix :: String.t(),
39+
table :: String.t(),
40+
header :: [atom],
41+
rows :: [[atom | nil]],
42+
on_conflict :: Ecto.Adapter.on_conflict(),
43+
returning :: [atom]
44+
) :: String.t()
4145
def insert(prefix, table, header, rows, on_conflict, returning) do
42-
included_fields = header
43-
|> Enum.filter(fn value -> Enum.any?(rows, fn row -> value in row end) end)
46+
included_fields =
47+
header
48+
|> Enum.filter(fn value -> Enum.any?(rows, fn row -> value in row end) end)
4449

4550
included_rows =
4651
Enum.map(rows, fn row ->
4752
row
4853
|> Enum.zip(header)
4954
|> Enum.filter_map(
50-
fn {_row, col} -> col in included_fields end,
51-
fn {row, _col} -> row end)
55+
fn {_row, col} -> col in included_fields end,
56+
fn {row, _col} -> row end
57+
)
5258
end)
5359

5460
fields = intersperse_map(included_fields, ?,, &quote_name/1)
61+
5562
query = [
56-
"INSERT INTO ", quote_table(prefix, table),
57-
" (", fields, ")",
63+
"INSERT INTO ",
64+
quote_table(prefix, table),
65+
" (",
66+
fields,
67+
")",
5868
" VALUES ",
59-
insert_all(included_rows, 1),
69+
insert_all(included_rows, 1)
6070
]
71+
6172
IO.iodata_to_binary(query)
6273
end
6374

@@ -73,6 +84,7 @@ defmodule ClickhouseEcto.Query do
7384
intersperse_reduce(values, ?,, counter, fn
7485
nil, counter ->
7586
{"DEFAULT", counter}
87+
7688
_, counter ->
7789
{[??], counter + 1}
7890
end)
@@ -81,31 +93,38 @@ defmodule ClickhouseEcto.Query do
8193
@doc """
8294
Clickhouse doesn't support update
8395
"""
84-
@spec update(prefix :: String.t, table :: String.t, fields :: [atom], filters :: [atom], returning :: [atom]) :: String.t
96+
@spec update(
97+
prefix :: String.t(),
98+
table :: String.t(),
99+
fields :: [atom],
100+
filters :: [atom],
101+
returning :: [atom]
102+
) :: String.t()
85103
def update(prefix, table, fields, filters, returning) do
86104
raise "UPDATE is not supported"
87105
end
88106

89107
@doc """
90108
Clickhouse doesn't support delete
91109
"""
92-
@spec delete(prefix :: String.t, table :: String.t, filters :: [atom], returning :: [atom]) :: String.t
110+
@spec delete(prefix :: String.t(), table :: String.t(), filters :: [atom], returning :: [atom]) ::
111+
String.t()
93112
def delete(prefix, table, filters, returning) do
94113
raise "DELETE is not supported"
95114
end
96115

97116
@doc """
98117
Receives a query and values to update and must return an UPDATE query.
99118
"""
100-
@spec update_all(query :: Ecto.Query.t) :: String.t
119+
@spec update_all(query :: Ecto.Query.t()) :: String.t()
101120
def update_all(%{from: from} = query, prefix \\ nil) do
102121
raise "UPDATE is not supported"
103122
end
104123

105124
@doc """
106125
Clickhouse doesn't support delete
107126
"""
108-
@spec delete_all(query :: Ecto.Query.t) :: String.t
127+
@spec delete_all(query :: Ecto.Query.t()) :: String.t()
109128
def delete_all(%{from: from} = query) do
110129
raise "DELETE is not supported"
111130
end

‎lib/clickhouse_ecto/query_string.ex

+89-52
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
defmodule ClickhouseEcto.QueryString do
2-
32
alias Ecto.Query
43
alias Ecto.SubQuery
54
alias Ecto.Query.{BooleanExpr, JoinExpr, QueryExpr}
65
alias ClickhouseEcto.Connection
76
alias ClickhouseEcto.Helpers
87

9-
binary_ops =
10-
[
11-
==: " = ",
12-
!=: " != ",
13-
<=: " <= ",
14-
>=: " >= ",
15-
<: " < ",
16-
>: " > ",
17-
and: " AND ",
18-
or: " OR ",
19-
ilike: " ILIKE ",
20-
like: " LIKE ",
21-
in: " IN ",
22-
is_nil: " WHERE "
23-
]
8+
binary_ops = [
9+
==: " = ",
10+
!=: " != ",
11+
<=: " <= ",
12+
>=: " >= ",
13+
<: " < ",
14+
>: " > ",
15+
and: " AND ",
16+
or: " OR ",
17+
ilike: " ILIKE ",
18+
like: " LIKE ",
19+
in: " IN ",
20+
is_nil: " WHERE "
21+
]
2422

2523
@binary_ops Keyword.keys(binary_ops)
2624

@@ -35,10 +33,12 @@ defmodule ClickhouseEcto.QueryString do
3533
end
3634

3735
def select_fields([], _sources, _query), do: "'TRUE'"
36+
3837
def select_fields(fields, sources, query) do
3938
Helpers.intersperse_map(fields, ", ", fn
4039
{key, value} ->
4140
[expr(value, sources, query), " AS " | Helpers.quote_name(key)]
41+
4242
value ->
4343
expr(value, sources, query)
4444
end)
@@ -48,9 +48,12 @@ defmodule ClickhouseEcto.QueryString do
4848
def distinct(%QueryExpr{expr: []}, _, _), do: {[], []}
4949
def distinct(%QueryExpr{expr: true}, _, _), do: {" DISTINCT", []}
5050
def distinct(%QueryExpr{expr: false}, _, _), do: {[], []}
51+
5152
def distinct(%QueryExpr{expr: exprs}, sources, query) do
52-
Helpers.error!(query,
53-
"DISTINCT ON is not supported! Use `distinct: true`, for ex. `from rec in MyModel, distinct: true, select: rec.my_field`")
53+
Helpers.error!(
54+
query,
55+
"DISTINCT ON is not supported! Use `distinct: true`, for ex. `from rec in MyModel, distinct: true, select: rec.my_field`"
56+
)
5457
end
5558

5659
def from(%{from: from} = query, sources) do
@@ -63,17 +66,21 @@ defmodule ClickhouseEcto.QueryString do
6366
end
6467

6568
def join(%Query{joins: []}, _sources), do: []
69+
6670
def join(%Query{joins: joins} = query, sources) do
67-
[?\s | Helpers.intersperse_map(joins, ?\s, fn
68-
%JoinExpr{qual: qual, ix: ix, source: source, on: %QueryExpr{expr: on_expr}} ->
69-
{join, _name} = Helpers.get_source(query, sources, ix, source)
70-
["ANY", join_qual(qual), join, " USING ", on_join_expr(on_expr)]
71-
end)]
71+
[
72+
?\s
73+
| Helpers.intersperse_map(joins, ?\s, fn
74+
%JoinExpr{qual: qual, ix: ix, source: source, on: %QueryExpr{expr: on_expr}} ->
75+
{join, _name} = Helpers.get_source(query, sources, ix, source)
76+
["ANY", join_qual(qual), join, " USING ", on_join_expr(on_expr)]
77+
end)
78+
]
7279
end
7380

74-
def on_join_expr({_, _,[head | tail]}) do
81+
def on_join_expr({_, _, [head | tail]}) do
7582
retorno = [on_join_expr(head) | on_join_expr(tail)]
76-
retorno |> Enum.uniq |> Enum.join(",")
83+
retorno |> Enum.uniq() |> Enum.join(",")
7784
end
7885

7986
def on_join_expr([head | tail]) do
@@ -89,7 +96,7 @@ defmodule ClickhouseEcto.QueryString do
8996
end
9097

9198
def join_qual(:inner), do: " INNER JOIN "
92-
def join_qual(:left), do: " LEFT OUTER JOIN "
99+
def join_qual(:left), do: " LEFT OUTER JOIN "
93100

94101
def where(%Query{wheres: wheres} = query, sources) do
95102
boolean(" WHERE ", wheres, sources, query)
@@ -100,53 +107,73 @@ defmodule ClickhouseEcto.QueryString do
100107
end
101108

102109
def group_by(%Query{group_bys: []}, _sources), do: []
110+
103111
def group_by(%Query{group_bys: group_bys} = query, sources) do
104-
[" GROUP BY " |
105-
Helpers.intersperse_map(group_bys, ", ", fn
106-
%QueryExpr{expr: expr} ->
107-
Helpers.intersperse_map(expr, ", ", &expr(&1, sources, query))
108-
end)]
112+
[
113+
" GROUP BY "
114+
| Helpers.intersperse_map(group_bys, ", ", fn
115+
%QueryExpr{expr: expr} ->
116+
Helpers.intersperse_map(expr, ", ", &expr(&1, sources, query))
117+
end)
118+
]
109119
end
110120

111121
def order_by(%Query{order_bys: []}, _distinct, _sources), do: []
122+
112123
def order_by(%Query{order_bys: order_bys} = query, distinct, sources) do
113124
order_bys = Enum.flat_map(order_bys, & &1.expr)
114-
[" ORDER BY " |
115-
Helpers.intersperse_map(distinct ++ order_bys, ", ", &order_by_expr(&1, sources, query))]
125+
126+
[
127+
" ORDER BY "
128+
| Helpers.intersperse_map(distinct ++ order_bys, ", ", &order_by_expr(&1, sources, query))
129+
]
116130
end
117131

118132
def order_by_expr({dir, expr}, sources, query) do
119133
str = expr(expr, sources, query)
134+
120135
case dir do
121-
:asc -> str
136+
:asc -> str
122137
:desc -> [str | " DESC"]
123138
end
124139
end
125140

126141
def limit(%Query{offset: nil, limit: nil}, _sources), do: []
142+
127143
def limit(%Query{offset: nil, limit: %QueryExpr{expr: expr}} = query, sources) do
128144
[" LIMIT ", expr(expr, sources, query)]
129145
end
130-
def limit(%Query{offset: %QueryExpr{expr: expr_offset}, limit: %QueryExpr{expr: expr_limit}} = query, sources) do
146+
147+
def limit(
148+
%Query{offset: %QueryExpr{expr: expr_offset}, limit: %QueryExpr{expr: expr_limit}} =
149+
query,
150+
sources
151+
) do
131152
[" LIMIT ", expr(expr_offset, sources, query), ", ", expr(expr_limit, sources, query)]
132153
end
133154

134155
def boolean(_name, [], _sources, _query), do: []
156+
135157
def boolean(name, [%{expr: expr, op: op} | query_exprs], sources, query) do
136-
[name |
137-
Enum.reduce(query_exprs, {op, paren_expr(expr, sources, query)}, fn
138-
%BooleanExpr{expr: expr, op: op}, {op, acc} ->
139-
{op, [acc, operator_to_boolean(op), paren_expr(expr, sources, query)]}
140-
%BooleanExpr{expr: expr, op: op}, {_, acc} ->
141-
{op, [?(, acc, ?), operator_to_boolean(op), paren_expr(expr, sources, query)]}
142-
end) |> elem(1)]
158+
[
159+
name
160+
| Enum.reduce(query_exprs, {op, paren_expr(expr, sources, query)}, fn
161+
%BooleanExpr{expr: expr, op: op}, {op, acc} ->
162+
{op, [acc, operator_to_boolean(op), paren_expr(expr, sources, query)]}
163+
164+
%BooleanExpr{expr: expr, op: op}, {_, acc} ->
165+
{op, [?(, acc, ?), operator_to_boolean(op), paren_expr(expr, sources, query)]}
166+
end)
167+
|> elem(1)
168+
]
143169
end
144170

145171
def operator_to_boolean(:and), do: " AND "
146172
def operator_to_boolean(:or), do: " OR "
147173

148-
def paren_expr(false, _sources, _query), do: "(0=1)"
149-
def paren_expr(true, _sources, _query), do: "(1=1)"
174+
def paren_expr(false, _sources, _query), do: "(0=1)"
175+
def paren_expr(true, _sources, _query), do: "(1=1)"
176+
150177
def paren_expr(expr, sources, query) do
151178
[?(, expr(expr, sources, query), ?)]
152179
end
@@ -165,12 +192,17 @@ defmodule ClickhouseEcto.QueryString do
165192

166193
def expr({:&, _, [idx, fields, _counter]}, sources, query) do
167194
{_, name, schema} = elem(sources, idx)
195+
168196
if is_nil(schema) and is_nil(fields) do
169-
Helpers.error!(query, "ClickHouse requires a schema module when using selector " <>
170-
"#{inspect name} but none was given. " <>
171-
"Please specify a schema or specify exactly which fields from " <>
172-
"#{inspect name} you desire")
197+
Helpers.error!(
198+
query,
199+
"ClickHouse requires a schema module when using selector " <>
200+
"#{inspect(name)} but none was given. " <>
201+
"Please specify a schema or specify exactly which fields from " <>
202+
"#{inspect(name)} you desire"
203+
)
173204
end
205+
174206
Helpers.intersperse_map(fields, ", ", &[name, ?. | Helpers.quote_name(&1)])
175207
end
176208

@@ -204,6 +236,7 @@ defmodule ClickhouseEcto.QueryString do
204236
case expr do
205237
{fun, _, _} when fun in @binary_ops ->
206238
["NOT (", expr(expr, sources, query), ?)]
239+
207240
_ ->
208241
["~(", expr(expr, sources, query), ?)]
209242
end
@@ -219,7 +252,7 @@ defmodule ClickhouseEcto.QueryString do
219252

220253
def expr({:fragment, _, parts}, sources, query) do
221254
Enum.map(parts, fn
222-
{:raw, part} -> part
255+
{:raw, part} -> part
223256
{:expr, expr} -> expr(expr, sources, query)
224257
end)
225258
end
@@ -235,6 +268,7 @@ defmodule ClickhouseEcto.QueryString do
235268
{:binary_op, op} ->
236269
[left, right] = args
237270
[op_to_binary(left, sources, query), op | op_to_binary(right, sources, query)]
271+
238272
{:fun, fun} ->
239273
[fun, ?(, modifier, Helpers.intersperse_map(args, ", ", &expr(&1, sources, query)), ?)]
240274
end
@@ -257,8 +291,8 @@ defmodule ClickhouseEcto.QueryString do
257291
["CAST(", expr(other, sources, query), " AS ", Helpers.ecto_to_db(type), ")"]
258292
end
259293

260-
def expr(nil, _sources, _query), do: "NULL"
261-
def expr(true, _sources, _query), do: "1"
294+
def expr(nil, _sources, _query), do: "NULL"
295+
def expr(true, _sources, _query), do: "1"
262296
def expr(false, _sources, _query), do: "0"
263297

264298
def expr(literal, _sources, _query) when is_binary(literal) do
@@ -285,7 +319,7 @@ defmodule ClickhouseEcto.QueryString do
285319
expr(expr, sources, query)
286320
end
287321

288-
def returning(returning), do: raise "RETURNING is not supported!"
322+
def returning(returning), do: raise("RETURNING is not supported!")
289323

290324
def create_names(%{prefix: prefix, sources: sources}) do
291325
create_names(prefix, sources, 0, tuple_size(sources)) |> List.to_tuple()
@@ -297,11 +331,14 @@ defmodule ClickhouseEcto.QueryString do
297331
{table, schema} ->
298332
name = [String.first(table) | Integer.to_string(pos)]
299333
{Helpers.quote_table(prefix, table), name, schema}
334+
300335
{:fragment, _, _} ->
301336
{nil, [?f | Integer.to_string(pos)], nil}
337+
302338
%Ecto.SubQuery{} ->
303339
{nil, [?s | Integer.to_string(pos)], nil}
304340
end
341+
305342
[current | create_names(prefix, sources, pos + 1, limit)]
306343
end
307344

‎lib/clickhouse_ecto/storage.ex

+30-18
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,85 @@
11
defmodule ClickhouseEcto.Storage do
2-
32
@behaviour Ecto.Adapter.Storage
43

54
def storage_up(opts) do
6-
database = Keyword.fetch!(opts, :database) || raise ":database is nil in repository configuration"
7-
opts = Keyword.put(opts, :database, nil)
5+
database =
6+
Keyword.fetch!(opts, :database) || raise ":database is nil in repository configuration"
7+
8+
opts = Keyword.put(opts, :database, nil)
89

910
command = ~s[CREATE DATABASE IF NOT EXISTS "#{database}"]
1011

1112
case run_query(command, opts) do
1213
{:ok, _} ->
1314
:ok
15+
1416
{:error, %{code: :database_already_exists}} ->
1517
{:error, :already_up}
18+
1619
{:error, error} ->
1720
{:error, Exception.message(error)}
1821
end
1922
end
2023

21-
defp concat_if(content, nil, _fun), do: content
24+
defp concat_if(content, nil, _fun), do: content
2225
defp concat_if(content, value, fun), do: content <> " " <> fun.(value)
2326

2427
@doc false
2528
def storage_down(opts) do
26-
database = Keyword.fetch!(opts, :database) || raise ":database is nil in repository configuration"
27-
command = ~s[DROP DATABASE "#{database}"]
28-
opts = Keyword.put(opts, :database, nil)
29+
database =
30+
Keyword.fetch!(opts, :database) || raise ":database is nil in repository configuration"
31+
32+
command = ~s[DROP DATABASE "#{database}"]
33+
opts = Keyword.put(opts, :database, nil)
2934

3035
case run_query(command, opts) do
3136
{:ok, _} ->
3237
:ok
38+
3339
{:error, %{code: :database_does_not_exists}} ->
3440
{:error, :already_down}
41+
3542
{:error, error} ->
3643
{:error, Exception.message(error)}
3744
end
3845
end
3946

4047
defp run_query(sql, opts) do
41-
# {:ok, _} = Application.ensure_all_started(:clickhousex)
48+
# {:ok, _} = Application.ensure_all_started(:clickhousex)
4249

4350
opts =
4451
opts
4552
|> Keyword.drop([:name, :log])
4653
|> Keyword.put(:pool, DBConnection.Connection)
4754
|> Keyword.put(:backoff_type, :stop)
4855

49-
{:ok, pid} = Task.Supervisor.start_link
56+
{:ok, pid} = Task.Supervisor.start_link()
5057

51-
task = Task.Supervisor.async_nolink(pid, fn ->
52-
HTTPoison.start
53-
{:ok, conn} = DBConnection.start_link(Clickhousex.Protocol, opts)
54-
value = ClickhouseEcto.Connection.execute(conn, sql, [], opts)
55-
GenServer.stop(conn)
56-
value
57-
end)
58+
task =
59+
Task.Supervisor.async_nolink(pid, fn ->
60+
HTTPoison.start()
61+
{:ok, conn} = DBConnection.start_link(Clickhousex.Protocol, opts)
62+
value = ClickhouseEcto.Connection.execute(conn, sql, [], opts)
63+
GenServer.stop(conn)
64+
value
65+
end)
5866

5967
timeout = Keyword.get(opts, :timeout, 15_000)
6068

6169
case Task.yield(task, timeout) || Task.shutdown(task) do
6270
{:ok, {:ok, result}} ->
6371
{:ok, result}
72+
6473
{:ok, {:error, error}} ->
6574
{:error, error}
75+
6676
{:exit, {%{__struct__: struct} = error, _}}
67-
when struct in [DBConnection.Error] ->
77+
when struct in [DBConnection.Error] ->
6878
{:error, error}
69-
{:exit, reason} ->
79+
80+
{:exit, reason} ->
7081
{:error, RuntimeError.exception(Exception.format_exit(reason))}
82+
7183
nil ->
7284
{:error, RuntimeError.exception("command timed out")}
7385
end

‎lib/clickhouse_ecto/structure.ex

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,21 @@ defmodule ClickhouseEcto.Structure do
22
@behaviour Ecto.Adapter.Structure
33

44
def structure_dump(_default, _config) do
5-
#table = config[:migration_source] || "schema_migrations"
5+
# table = config[:migration_source] || "schema_migrations"
66

77
raise "not implemented"
88
# with {:ok, versions} <- select_versions(table, config),
99
# {:ok, path} <- pg_dump(default, config),
10-
# do: append_versions(table, versions, path)
10+
# do: append_versions(table, versions, path)
1111
end
1212

1313
def structure_load(_default, _config) do
14-
#path = config[:dump_path] || Path.join(default, "structure.sql")
14+
# path = config[:dump_path] || Path.join(default, "structure.sql")
1515

1616
raise "not implemented"
1717
# case run_with_cmd("psql", config, ["--quiet", "--file", path, config[:database]]) do
1818
# {_output, 0} -> {:ok, path}
1919
# {output, _} -> {:error, output}
2020
# end
2121
end
22-
2322
end

‎lib/clickhouse_ecto/type.ex

+14-12
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ defmodule ClickhouseEcto.Type do
1414

1515
def encode(value, :decimal) do
1616
try do
17-
{float_value, _} = value |> Decimal.new |> Decimal.to_string |> Float.parse
17+
{float_value, _} = value |> Decimal.new() |> Decimal.to_string() |> Float.parse()
1818
{:ok, float_value}
1919
rescue
2020
_e in FunctionClauseError ->
@@ -27,24 +27,25 @@ defmodule ClickhouseEcto.Type do
2727
end
2828

2929
def decode(value, type)
30-
when type in @int_types and is_binary(value) do
30+
when type in @int_types and is_binary(value) do
3131
case Integer.parse(value) do
32-
{int, _} -> {:ok, int}
33-
:error -> {:error, "Not an integer id"}
32+
{int, _} -> {:ok, int}
33+
:error -> {:error, "Not an integer id"}
3434
end
3535
end
3636

3737
def decode(value, type)
38-
when type in [:float] do
38+
when type in [:float] do
3939
tmp = if is_binary(value), do: value, else: to_string(value)
40+
4041
case Float.parse(tmp) do
41-
{float, _} -> {:ok, float}
42-
:error -> {:error, "Not an float value"}
42+
{float, _} -> {:ok, float}
43+
:error -> {:error, "Not an float value"}
4344
end
4445
end
4546

4647
def decode(value, type)
47-
when type in @decimal_types do
48+
when type in @decimal_types do
4849
{:ok, Decimal.new(value)}
4950
end
5051

@@ -53,22 +54,23 @@ defmodule ClickhouseEcto.Type do
5354
end
5455

5556
def decode({date, {h, m, s}}, type)
56-
when type in [:utc_datetime, :naive_datetime] do
57+
when type in [:utc_datetime, :naive_datetime] do
5758
{:ok, {date, {h, m, s, 0}}}
5859
end
5960

6061
def decode(value, type)
61-
when type in [:date] and is_binary(value) do
62+
when type in [:date] and is_binary(value) do
6263
case value do
6364
@empty_clickhouse_date ->
6465
Ecto.Date.cast!(@unix_default_time)
66+
6567
val ->
6668
Ecto.Date.cast!(val)
67-
end |> Ecto.Date.dump
69+
end
70+
|> Ecto.Date.dump()
6871
end
6972

7073
def decode(value, _type) do
7174
{:ok, value}
7275
end
73-
7476
end

‎mix.exs

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ defmodule ClickhouseEcto.Mixfile do
66
app: :clickhouse_ecto,
77
version: "0.2.8",
88
elixir: "~> 1.5",
9-
start_permanent: Mix.env == :prod,
9+
start_permanent: Mix.env() == :prod,
1010
deps: deps(),
1111
description: description(),
1212
package: package(),
@@ -26,7 +26,8 @@ defmodule ClickhouseEcto.Mixfile do
2626
[
2727
{:ecto, "~> 2.1"},
2828
{:clickhousex, "~> 0.4.0"},
29-
{:ex_doc, "~> 0.19", only: :dev}
29+
{:ex_doc, "~> 0.19", only: :dev},
30+
{:db_connection, "~> 2.2.1", override: true}
3031
]
3132
end
3233

‎mix.lock

+21-20
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
%{
2-
"certifi": {:hex, :certifi, "2.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
3-
"clickhousex": {:hex, :clickhousex, "0.2.3", "6f129e8acbe468f0c1a368e6875d797f925c16bcfd0900240d1642eca009a251", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
4-
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [], [], "hexpm"},
5-
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [], [{: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"},
6-
"decimal": {:hex, :decimal, "1.4.0", "fac965ce71a46aab53d3a6ce45662806bdd708a4a95a65cde8a12eb0124a1333", [], [], "hexpm"},
7-
"earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"},
8-
"ecto": {:hex, :ecto, "2.2.0", "87e985766684b87e81452aef39453850dac2dfb29fc5885b0267a2a784327bb8", [], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
9-
"ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
10-
"hackney": {:hex, :hackney, "1.14.0", "66e29e78feba52176c3a4213d42b29bdc4baff93a18cfe480f73b04677139dee", [:rebar3], [{:certifi, "2.4.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
11-
"httpoison": {:hex, :httpoison, "1.3.1", "7ac607311f5f706b44e8b3fab736d0737f2f62a31910ccd9afe7227b43edb7f0", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
12-
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
13-
"makeup": {:hex, :makeup, "0.5.1", "966c5c2296da272d42f1de178c1d135e432662eca795d6dc12e5e8787514edf7", [:mix], [{:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
14-
"makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
15-
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [], [], "hexpm"},
16-
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [], [], "hexpm"},
17-
"nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm"},
18-
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
2+
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"},
3+
"clickhousex": {:hex, :clickhousex, "0.4.0", "4d6e173e4aaffa82ea6f2d86db95686dff2d9f05b9c195d11cc2810178df1ba8", [:mix], [{:db_connection, "~> 2.0.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:httpoison, "~> 1.5", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1.2", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6c926434196d7d4d16f85459b0b0e87e7d00bc5eadb28d8080201c728da1840c"},
4+
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"},
5+
"db_connection": {:hex, :db_connection, "2.2.1", "caee17725495f5129cb7faebde001dc4406796f12a62b8949f4ac69315080566", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "2b02ece62d9f983fcd40954e443b7d9e6589664380e5546b2b9b523cd0fb59e1"},
6+
"decimal": {:hex, :decimal, "1.4.0", "fac965ce71a46aab53d3a6ce45662806bdd708a4a95a65cde8a12eb0124a1333", [:mix], [], "hexpm", "76de71de4e2fa0b371b5359a060a3a3d38e74b2da7a1157a45e146a68f71e023"},
7+
"earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm", "c57508ddad47dfb8038ca6de1e616e66e9b87313220ac5d9817bc4a4dc2257b9"},
8+
"ecto": {:hex, :ecto, "2.2.0", "87e985766684b87e81452aef39453850dac2dfb29fc5885b0267a2a784327bb8", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm", "b4d47f548c1da6dec78926a25716580d9f42b7b94e18c0c55d917133d3135c7e"},
9+
"ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "dc87f778d8260da0189a622f62790f6202af72f2f3dee6e78d91a18dd2fcd137"},
10+
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"},
11+
"httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"},
12+
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
13+
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"},
14+
"makeup": {:hex, :makeup, "0.5.1", "966c5c2296da272d42f1de178c1d135e432662eca795d6dc12e5e8787514edf7", [:mix], [{:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "259748a45dfcf5f49765a7c29c9594791c82de23e22d7a3e6e59533fe8e8935b"},
15+
"makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "393d17c5a648e3b30522b2a4743bd1dc3533e1227c8c2823ebe8c3a8e5be5913"},
16+
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
17+
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
18+
"nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm", "4ababf5c44164f161872704e1cfbecab3935fdebec66c72905abaad0e6e5cef6"},
19+
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
1920
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [], [], "hexpm"},
20-
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [], [], "hexpm"},
21-
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"},
22-
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
21+
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
22+
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"},
23+
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
2324
}

‎test/clickhouse_ecto_test.exs

+89-46
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ defmodule ClickhouseEctoTest do
1010
use Ecto.Schema
1111

1212
schema "schema" do
13-
field :x, :integer
14-
field :y, :integer
15-
field :z, :integer
13+
field(:x, :integer)
14+
field(:y, :integer)
15+
field(:z, :integer)
1616
end
1717
end
1818

@@ -22,11 +22,10 @@ defmodule ClickhouseEctoTest do
2222
query
2323
end
2424

25-
26-
defp all(query), do: query |> SQL.all |> IO.iodata_to_binary()
25+
defp all(query), do: query |> SQL.all() |> IO.iodata_to_binary()
2726

2827
defp insert(prefx, table, header, rows, on_conflict, returning) do
29-
IO.iodata_to_binary SQL.insert(prefx, table, header, rows, on_conflict, returning)
28+
IO.iodata_to_binary(SQL.insert(prefx, table, header, rows, on_conflict, returning))
3029
end
3130

3231
test "from" do
@@ -41,21 +40,25 @@ defmodule ClickhouseEctoTest do
4140
query = "Posts" |> select([:x]) |> normalize
4241
assert all(query) == ~s{SELECT P0."x" FROM "Posts" AS P0}
4342

44-
# FIXME
45-
# query = "0posts" |> select([:x]) |> normalize
46-
# assert all(query) == ~s{SELECT t0."x" FROM "0posts" AS t0}
43+
# FIXME
44+
# query = "0posts" |> select([:x]) |> normalize
45+
# assert all(query) == ~s{SELECT t0."x" FROM "0posts" AS t0}
4746

48-
# assert_raise Ecto.QueryError, ~r/MySQL does not support selecting all fields from "posts" without a schema/, fn ->
49-
# all from(p in "posts", select: p) |> normalize()
50-
# end
47+
# assert_raise Ecto.QueryError, ~r/MySQL does not support selecting all fields from "posts" without a schema/, fn ->
48+
# all from(p in "posts", select: p) |> normalize()
49+
# end
5150
end
5251

5352
test "from with subquery" do
5453
query = subquery("posts" |> select([r], %{x: r.x, y: r.y})) |> select([r], r.x) |> normalize
55-
assert all(query) == ~s{SELECT s0."x" FROM (SELECT p0."x" AS "x", p0."y" AS "y" FROM "posts" AS p0) AS s0}
54+
55+
assert all(query) ==
56+
~s{SELECT s0."x" FROM (SELECT p0."x" AS "x", p0."y" AS "y" FROM "posts" AS p0) AS s0}
5657

5758
query = subquery("posts" |> select([r], %{x: r.x, z: r.y})) |> select([r], r) |> normalize
58-
assert all(query) == ~s{SELECT s0."x", s0."z" FROM (SELECT p0."x" AS "x", p0."y" AS "z" FROM "posts" AS p0) AS s0}
59+
60+
assert all(query) ==
61+
~s{SELECT s0."x", s0."z" FROM (SELECT p0."x" AS "x", p0."y" AS "z" FROM "posts" AS p0) AS s0}
5962
end
6063

6164
test "select" do
@@ -89,16 +92,34 @@ defmodule ClickhouseEctoTest do
8992
end
9093

9194
test "where" do
92-
query = Schema |> where([r], r.x == 42) |> where([r], r.y != 43) |> select([r], r.x) |> normalize
93-
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 WHERE (s0."x" = 42) AND (s0."y" != 43)}
95+
query =
96+
Schema |> where([r], r.x == 42) |> where([r], r.y != 43) |> select([r], r.x) |> normalize
97+
98+
assert all(query) ==
99+
~s{SELECT s0."x" FROM "schema" AS s0 WHERE (s0."x" = 42) AND (s0."y" != 43)}
94100
end
95101

96102
test "or_where" do
97-
query = Schema |> or_where([r], r.x == 42) |> or_where([r], r.y != 43) |> select([r], r.x) |> normalize
98-
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 WHERE (s0."x" = 42) OR (s0."y" != 43)}
99-
100-
query = Schema |> or_where([r], r.x == 42) |> or_where([r], r.y != 43) |> where([r], r.z == 44) |> select([r], r.x) |> normalize
101-
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 WHERE ((s0."x" = 42) OR (s0."y" != 43)) AND (s0."z" = 44)}
103+
query =
104+
Schema
105+
|> or_where([r], r.x == 42)
106+
|> or_where([r], r.y != 43)
107+
|> select([r], r.x)
108+
|> normalize
109+
110+
assert all(query) ==
111+
~s{SELECT s0."x" FROM "schema" AS s0 WHERE (s0."x" = 42) OR (s0."y" != 43)}
112+
113+
query =
114+
Schema
115+
|> or_where([r], r.x == 42)
116+
|> or_where([r], r.y != 43)
117+
|> where([r], r.z == 44)
118+
|> select([r], r.x)
119+
|> normalize
120+
121+
assert all(query) ==
122+
~s{SELECT s0."x" FROM "schema" AS s0 WHERE ((s0."x" = 42) OR (s0."y" != 43)) AND (s0."z" = 44)}
102123
end
103124

104125
test "order by" do
@@ -108,7 +129,7 @@ defmodule ClickhouseEctoTest do
108129
query = Schema |> order_by([r], [r.x, r.y]) |> select([r], r.x) |> normalize
109130
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 ORDER BY s0."x", s0."y"}
110131

111-
query = Schema |> order_by([r], [asc: r.x, desc: r.y]) |> select([r], r.x) |> normalize
132+
query = Schema |> order_by([r], asc: r.x, desc: r.y) |> select([r], r.x) |> normalize
112133
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 ORDER BY s0."x", s0."y" DESC}
113134

114135
query = Schema |> order_by([r], []) |> select([r], r.x) |> normalize
@@ -164,14 +185,17 @@ defmodule ClickhouseEctoTest do
164185
query = Schema |> select([r], fragment("lcase(?)", r.x)) |> normalize
165186
assert all(query) == ~s{SELECT lcase(s0."x") FROM "schema" AS s0}
166187

167-
query = Schema |> select([r], r.x) |> where([], fragment("? = \"query\\?\"", ^10)) |> normalize
188+
query =
189+
Schema |> select([r], r.x) |> where([], fragment("? = \"query\\?\"", ^10)) |> normalize
190+
168191
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 WHERE (? = \"query?\")}
169192

170193
value = 13
171194
query = Schema |> select([r], fragment("lcase(?, ?)", r.x, ^value)) |> normalize
172195
assert all(query) == ~s{SELECT lcase(s0."x", ?) FROM "schema" AS s0}
173196

174197
query = Schema |> select([], fragment(title: 2)) |> normalize
198+
175199
assert_raise Ecto.QueryError, fn ->
176200
all(query)
177201
end
@@ -195,7 +219,9 @@ defmodule ClickhouseEctoTest do
195219
end
196220

197221
test "tagged type" do
198-
query = Schema |> select([], type(^"601d74e4-a8d3-4b6e-8365-eddb4c893327", Ecto.UUID)) |> normalize
222+
query =
223+
Schema |> select([], type(^"601d74e4-a8d3-4b6e-8365-eddb4c893327", Ecto.UUID)) |> normalize
224+
199225
assert all(query) == ~s{SELECT CAST(? AS FixedString(36)) FROM "schema" AS s0}
200226
end
201227

@@ -206,15 +232,15 @@ defmodule ClickhouseEctoTest do
206232

207233
test "nested expressions" do
208234
z = 123
209-
query = from(r in Schema, []) |> select([r], r.x > 0 and (r.y > ^(-z)) or true) |> normalize
235+
query = from(r in Schema, []) |> select([r], (r.x > 0 and r.y > ^(-z)) or true) |> normalize
210236
assert all(query) == ~s{SELECT ((s0."x" > 0) AND (s0."y" > ?)) OR 1 FROM "schema" AS s0}
211237
end
212238

213239
test "in expression" do
214240
query = Schema |> select([e], 1 in []) |> normalize
215241
assert all(query) == ~s{SELECT 0=1 FROM "schema" AS s0}
216242

217-
query = Schema |> select([e], 1 in [1,e.x,3]) |> normalize
243+
query = Schema |> select([e], 1 in [1, e.x, 3]) |> normalize
218244
assert all(query) == ~s{SELECT 1 IN (1,s0."x",3) FROM "schema" AS s0}
219245

220246
query = Schema |> select([e], 1 in ^[]) |> normalize
@@ -230,23 +256,39 @@ defmodule ClickhouseEctoTest do
230256
assert all(query) == ~s{SELECT 1 = ANY(foo) FROM "schema" AS s0}
231257

232258
query = Schema |> select([e], e.x == ^0 or e.x in ^[1, 2, 3] or e.x == ^4) |> normalize
233-
assert all(query) == ~s{SELECT ((s0."x" = ?) OR (s0."x" IN (?,?,?))) OR (s0."x" = ?) FROM "schema" AS s0}
259+
260+
assert all(query) ==
261+
~s{SELECT ((s0."x" = ?) OR (s0."x" IN (?,?,?))) OR (s0."x" = ?) FROM "schema" AS s0}
234262
end
235263

236264
test "having" do
237265
query = Schema |> having([p], p.x == p.x) |> select([p], p.x) |> normalize
238266
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 HAVING (s0."x" = s0."x")}
239267

240-
query = Schema |> having([p], p.x == p.x) |> having([p], p.y == p.y) |> select([p], [p.y, p.x]) |> normalize
241-
assert all(query) == ~s{SELECT s0."y", s0."x" FROM "schema" AS s0 HAVING (s0."x" = s0."x") AND (s0."y" = s0."y")}
268+
query =
269+
Schema
270+
|> having([p], p.x == p.x)
271+
|> having([p], p.y == p.y)
272+
|> select([p], [p.y, p.x])
273+
|> normalize
274+
275+
assert all(query) ==
276+
~s{SELECT s0."y", s0."x" FROM "schema" AS s0 HAVING (s0."x" = s0."x") AND (s0."y" = s0."y")}
242277
end
243278

244279
test "or_having" do
245280
query = Schema |> or_having([p], p.x == p.x) |> select([p], p.x) |> normalize
246281
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 HAVING (s0."x" = s0."x")}
247282

248-
query = Schema |> or_having([p], p.x == p.x) |> or_having([p], p.y == p.y) |> select([p], [p.y, p.x]) |> normalize
249-
assert all(query) == ~s{SELECT s0."y", s0."x" FROM "schema" AS s0 HAVING (s0."x" = s0."x") OR (s0."y" = s0."y")}
283+
query =
284+
Schema
285+
|> or_having([p], p.x == p.x)
286+
|> or_having([p], p.y == p.y)
287+
|> select([p], [p.y, p.x])
288+
|> normalize
289+
290+
assert all(query) ==
291+
~s{SELECT s0."y", s0."x" FROM "schema" AS s0 HAVING (s0."x" = s0."x") OR (s0."y" = s0."y")}
250292
end
251293

252294
test "group by" do
@@ -264,24 +306,25 @@ defmodule ClickhouseEctoTest do
264306
end
265307

266308
test "interpolated values" do
267-
query = Schema
268-
|> select([m], {m.id, ^0})
269-
|> where([], fragment("?", ^true))
270-
|> where([], fragment("?", ^false))
271-
|> having([], fragment("?", ^true))
272-
|> having([], fragment("?", ^false))
273-
|> group_by([], fragment("?", ^1))
274-
|> group_by([], fragment("?", ^2))
275-
|> order_by([], fragment("?", ^3))
276-
|> order_by([], ^:x)
277-
|> limit([], ^4)
278-
|> offset([], ^5)
279-
|> normalize
309+
query =
310+
Schema
311+
|> select([m], {m.id, ^0})
312+
|> where([], fragment("?", ^true))
313+
|> where([], fragment("?", ^false))
314+
|> having([], fragment("?", ^true))
315+
|> having([], fragment("?", ^false))
316+
|> group_by([], fragment("?", ^1))
317+
|> group_by([], fragment("?", ^2))
318+
|> order_by([], fragment("?", ^3))
319+
|> order_by([], ^:x)
320+
|> limit([], ^4)
321+
|> offset([], ^5)
322+
|> normalize
280323

281324
result =
282325
~s{SELECT s0."id", ? FROM "schema" AS s0 } <>
283-
~s{WHERE (?) AND (?) GROUP BY ?, ? HAVING (?) AND (?) } <>
284-
~s{ORDER BY ?, s0."x" LIMIT ?, ?}
326+
~s{WHERE (?) AND (?) GROUP BY ?, ? HAVING (?) AND (?) } <>
327+
~s{ORDER BY ?, s0."x" LIMIT ?, ?}
285328

286329
assert all(query) == String.trim(result)
287330
end

0 commit comments

Comments
 (0)
Please sign in to comment.