Skip to content

Commit

Permalink
Support fragment splicing (#535)
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-rychlewski committed Jul 14, 2023
1 parent 2b1f9dc commit 9069a4c
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 8 deletions.
6 changes: 5 additions & 1 deletion lib/ecto/adapters/myxql/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ if Code.ensure_loaded?(MyXQL) do

defp cte_expr({name, opts, cte}, sources, query) do
operation_opt = Map.get(opts, :operation)

[quote_name(name), " AS ", cte_query(cte, sources, query, operation_opt)]
end

Expand Down Expand Up @@ -603,6 +603,10 @@ if Code.ensure_loaded?(MyXQL) do
quote_name(literal)
end

defp expr({:splice, _, [{:^, _, [_, length]}]}, _sources, _query) do
Enum.intersperse(List.duplicate(??, length), ?,)
end

defp expr({:selected_as, _, [name]}, _sources, _query) do
[quote_name(name)]
end
Expand Down
12 changes: 8 additions & 4 deletions lib/ecto/adapters/postgres/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ if Code.ensure_loaded?(Postgrex) do
true -> "MATERIALIZED"
false -> "NOT MATERIALIZED"
end

operation_opt = Map.get(opts, :operation)

[quote_name(name), " AS ", materialized_opt, cte_query(cte, sources, query, operation_opt)]
Expand All @@ -435,16 +435,16 @@ if Code.ensure_loaded?(Postgrex) do
query = put_in(query.aliases[@parent_as], {parent_query, sources})
["(", update_all(query), ")"]
end

defp cte_query(%Ecto.Query{} = query, sources, parent_query, :delete_all) do
query = put_in(query.aliases[@parent_as], {parent_query, sources})
["(", delete_all(query), ")"]
end

defp cte_query(%Ecto.Query{} = query, _sources, _parent_query, :insert_all) do
error!(query, "Postgres adapter does not support CTE operation :insert_all")
end

defp cte_query(%Ecto.Query{} = query, sources, parent_query, :all) do
query = put_in(query.aliases[@parent_as], {parent_query, sources})
["(", all(query, subquery_as_prefix(sources)), ")"]
Expand Down Expand Up @@ -746,6 +746,10 @@ if Code.ensure_loaded?(Postgrex) do
quote_name(literal)
end

defp expr({:splice, _, [{:^, _, [idx, length]}]}, _sources, _query) do
Enum.map_join(1..length, ",", &"$#{idx + &1}")
end

defp expr({:selected_as, _, [name]}, _sources, _query) do
[quote_name(name)]
end
Expand Down
8 changes: 6 additions & 2 deletions lib/ecto/adapters/tds/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ if Code.ensure_loaded?(Tds) do

defp cte_expr({name, opts, cte}, sources, query) do
operation_opt = Map.get(opts, :operation)

[quote_name(name), cte_header(cte, query), " AS ", cte_query(cte, sources, query, operation_opt)]
end

Expand Down Expand Up @@ -477,7 +477,7 @@ if Code.ensure_loaded?(Tds) do
query = put_in(query.aliases[@parent_as], {parent_query, sources})
[?(, all(query, subquery_as_prefix(sources)), ?)]
end

defp cte_query(%Ecto.Query{} = query, _sources, _parent_query, operation) do
error!(query, "Tds adapter does not support data-modifying CTEs (operation: #{operation})")
end
Expand Down Expand Up @@ -780,6 +780,10 @@ if Code.ensure_loaded?(Tds) do
quote_name(literal)
end

defp expr({:splice, _, [{:^, _, [idx, length]}]}, _sources, _query) do
list_param_to_args(idx, length)
end

defp expr({:selected_as, _, [name]}, _sources, _query) do
[quote_name(name)]
end
Expand Down
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"deep_merge": {:hex, :deep_merge, "0.2.0", "c1050fa2edf4848b9f556fba1b75afc66608a4219659e3311d9c9427b5b680b3", [:mix], [], "hexpm", "e3bf435a54ed27b0ba3a01eb117ae017988804e136edcbe8a6a14c310daa966e"},
"earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"},
"ecto": {:git, "https://github.com/elixir-ecto/ecto.git", "cf379688df5c786b4f6e5b5cbf283489972b26b3", []},
"ecto": {:git, "https://github.com/elixir-ecto/ecto.git", "eb03f45b999e2bf67ffae92811233eb6e56dba55", []},
"ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"},
"jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
Expand Down
3 changes: 3 additions & 0 deletions test/ecto/adapters/myxql_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,9 @@ defmodule Ecto.Adapters.MyXQLTest do
query = Schema |> select([r], fragment("? COLLATE ?", r.x, literal(^"es_ES"))) |> plan()
assert all(query) == ~s{SELECT s0.`x` COLLATE `es_ES` FROM `schema` AS s0}

query = Schema |> select([r], r.x) |> where([r], fragment("? in (?,?,?)", r.x, ^1, splice(^[2, 3, 4]), ^5)) |> plan()
assert all(query) == ~s{SELECT s0.`x` FROM `schema` AS s0 WHERE (s0.`x` in (?,?,?,?,?))}

value = 13
query = Schema |> select([r], fragment("lcase(?, ?)", r.x, ^value)) |> plan()
assert all(query) == ~s{SELECT lcase(s0.`x`, ?) FROM `schema` AS s0}
Expand Down
3 changes: 3 additions & 0 deletions test/ecto/adapters/postgres_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,9 @@ defmodule Ecto.Adapters.PostgresTest do
query = Schema |> select([r], fragment("? COLLATE ?", r.x, literal(^"es_ES"))) |> plan()
assert all(query) == ~s{SELECT s0."x" COLLATE "es_ES" FROM "schema" AS s0}

query = Schema |> select([r], r.x) |> where([r], fragment("? in (?,?,?)", r.x, ^1, splice(^[2, 3, 4]), ^5)) |> plan()
assert all(query) == ~s{SELECT s0."x" FROM "schema" AS s0 WHERE (s0."x" in ($1,$2,$3,$4,$5))}

value = 13
query = Schema |> select([r], fragment("downcase(?, ?)", r.x, ^value)) |> plan()
assert all(query) == ~s{SELECT downcase(s0."x", $1) FROM "schema" AS s0}
Expand Down
3 changes: 3 additions & 0 deletions test/ecto/adapters/tds_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,9 @@ defmodule Ecto.Adapters.TdsTest do
query = Schema |> select([r], fragment("? COLLATE ?", r.x, literal(^"es_ES"))) |> plan()
assert all(query) == ~s{SELECT s0.[x] COLLATE [es_ES] FROM [schema] AS s0}

query = Schema |> select([r], r.x) |> where([r], fragment("? in (?,?,?)", r.x, ^1, splice(^[2, 3, 4]), ^5)) |> plan()
assert all(query) == ~s{SELECT s0.[x] FROM [schema] AS s0 WHERE (s0.[x] in (@1,@2,@3,@4,@5))}

value = 13
query = Schema |> select([r], fragment("lower(?)", ^value)) |> plan()
assert all(query) == ~s{SELECT lower(@1) FROM [schema] AS s0}
Expand Down

0 comments on commit 9069a4c

Please sign in to comment.