Skip to content

Commit f82412a

Browse files
committed
Add with_cte_expression
ClickHouse supports two different sorts of CTEs: 1. Normal, subquery based CTEs supported by most DBMS 2. Expression-based CTEs This PR adds support for (2) by adding a new adapter-specific method. Note the SQL syntax is flipped for (2).
1 parent 9b17f8f commit f82412a

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

Diff for: lib/ecto/adapters/clickhouse/api.ex

+31
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,35 @@ defmodule Ecto.Adapters.ClickHouse.API do
4848
# %{query | sources: {nil, schema}}
4949
query
5050
end
51+
52+
@doc """
53+
Builds a common table expression with an (constant) expression instead of a subquery.
54+
55+
`with_query` must be a fragment to be evaluated as an expression.
56+
57+
## Options
58+
59+
- as: must be a compile-time literal string that is used in the main query to select
60+
the static value.
61+
62+
https://clickhouse.com/docs/en/sql-reference/statements/select/with#syntax
63+
"""
64+
defmacro with_cte_expression(query, with_query, opts) do
65+
name = opts[:as]
66+
67+
if !name do
68+
Ecto.Query.Builder.error!("`as` option must be specified")
69+
end
70+
71+
# :HACK: We override the operation to :update_all to pass context to the connection.
72+
# :update_all is not used within ClickHouse adapter otherwise.
73+
Ecto.Query.Builder.CTE.build(
74+
query,
75+
name,
76+
with_query,
77+
opts[:materialized],
78+
:update_all,
79+
__CALLER__
80+
)
81+
end
5182
end

Diff for: lib/ecto/adapters/clickhouse/connection.ex

+6-2
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,12 @@ defmodule Ecto.Adapters.ClickHouse.Connection do
369369
recursive_opt = if recursive, do: "RECURSIVE ", else: ""
370370

371371
ctes =
372-
intersperse_map(queries, ?,, fn {name, _opts, cte} ->
373-
[quote_name(name), " AS ", cte_query(cte, sources, params, query)]
372+
intersperse_map(queries, ?,, fn {name, opts, cte} ->
373+
if opts[:operation] == :update_all do
374+
[cte_query(cte, sources, params, query), " AS ", quote_name(name)]
375+
else
376+
[quote_name(name), " AS ", cte_query(cte, sources, params, query)]
377+
end
374378
end)
375379

376380
["WITH ", recursive_opt, ctes, " "]

Diff for: test/ecto/adapters/clickhouse/connection_test.exs

+11
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ defmodule Ecto.Adapters.ClickHouse.ConnectionTest do
77

88
import Ecto.Query
99
import Ecto.Migration, only: [table: 1, table: 2, index: 3, constraint: 3]
10+
require Ecto.Adapters.ClickHouse.API
11+
import Ecto.Adapters.ClickHouse.API, only: [with_cte_expression: 3]
1012

1113
defmodule Comment do
1214
use Ecto.Schema
@@ -233,6 +235,15 @@ defmodule Ecto.Adapters.ClickHouse.ConnectionTest do
233235
"""
234236
end
235237

238+
test "common table expression with expression instead of subquery" do
239+
query =
240+
Schema
241+
|> with_cte_expression(fragment("123"), as: "value")
242+
|> select([], fragment("value"))
243+
244+
assert all(query) == "WITH 123 AS \"value\" SELECT value FROM \"schema\" AS s0"
245+
end
246+
236247
test "reference common table in union" do
237248
comments_scope_query =
238249
"comments"

0 commit comments

Comments
 (0)