Skip to content

Commit

Permalink
Implement literal/1 support in fragments
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed May 31, 2022
1 parent 5204948 commit 3b2187a
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 15 deletions.
13 changes: 9 additions & 4 deletions lib/ecto/adapters/myxql/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,10 @@ if Code.ensure_loaded?(MyXQL) do
|> parens_for_select
end

defp expr({:literal, _, [literal]}, _sources, _query) do
quote_name(literal)
end

defp expr({:datetime_add, _, [datetime, count, interval]}, sources, query) do
["date_add(", expr(datetime, sources, query), ", ",
interval(count, interval, sources, query) | ")"]
Expand Down Expand Up @@ -1039,12 +1043,13 @@ if Code.ensure_loaded?(MyXQL) do
end
end

defp quote_name(name) when is_atom(name),
do: quote_name(Atom.to_string(name))
defp quote_name(name) when is_atom(name) do
quote_name(Atom.to_string(name))
end

defp quote_name(name) do
defp quote_name(name) when is_binary(name) do
if String.contains?(name, "`") do
error!(nil, "bad field name #{inspect name}")
error!(nil, "bad literal/field/table name #{inspect name} (` is not permitted)")
end

[?`, name, ?`]
Expand Down
10 changes: 8 additions & 2 deletions lib/ecto/adapters/postgres/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,10 @@ if Code.ensure_loaded?(Postgrex) do
|> parens_for_select
end

defp expr({:literal, _, [literal]}, _sources, _query) do
quote_name(literal)
end

defp expr({:datetime_add, _, [datetime, count, interval]}, sources, query) do
[expr(datetime, sources, query), type_unless_typed(datetime, "timestamp"), " + ",
interval(count, interval, sources, query)]
Expand Down Expand Up @@ -1282,10 +1286,12 @@ if Code.ensure_loaded?(Postgrex) do
defp quote_name(name) when is_atom(name) do
quote_name(Atom.to_string(name))
end
defp quote_name(name) do

defp quote_name(name) when is_binary(name) do
if String.contains?(name, "\"") do
error!(nil, "bad field name #{inspect name}")
error!(nil, "bad literal/field/table name #{inspect name} (\" is not permitted)")
end

[?", 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 @@ -760,6 +760,10 @@ if Code.ensure_loaded?(Tds) do
|> parens_for_select
end

defp expr({:literal, _, [literal]}, _sources, _query) do
quote_name(literal)
end

defp expr({:datetime_add, _, [datetime, count, interval]}, sources, query) do
[
"DATEADD(",
Expand Down Expand Up @@ -1511,9 +1515,9 @@ if Code.ensure_loaded?(Tds) do
quote_name(Atom.to_string(name))
end

defp quote_name(name) do
defp quote_name(name) when is_binary(name) do
if String.contains?(name, ["[", "]"]) do
error!(nil, "bad field name #{inspect(name)} '[' and ']' are not permitted")
error!(nil, "bad literal/field/table name #{inspect(name)} ('[' and ']' are not permitted)")
end

"[#{name}]"
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ defmodule EctoSQL.MixProject do
if path = System.get_env("ECTO_PATH") do
{:ecto, path: path}
else
{:ecto, "~> 3.8.1"}
{:ecto, "~> 3.8.1", github: "elixir-ecto/ecto"}
end
end

Expand Down
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"decimal": {:hex, :decimal, "1.9.0", "83e8daf59631d632b171faabafb4a9f4242c514b0a06ba3df493951c08f64d07", [:mix], [], "hexpm", "b1f2343568eed6928f3e751cf2dffde95bfaa19dd95d09e8a9ea92ccfd6f7d85"},
"deep_merge": {:hex, :deep_merge, "0.2.0", "c1050fa2edf4848b9f556fba1b75afc66608a4219659e3311d9c9427b5b680b3", [:mix], [], "hexpm", "e3bf435a54ed27b0ba3a01eb117ae017988804e136edcbe8a6a14c310daa966e"},
"earmark_parser": {:hex, :earmark_parser, "1.4.25", "2024618731c55ebfcc5439d756852ec4e85978a39d0d58593763924d9a15916f", [:mix], [], "hexpm", "56749c5e1c59447f7b7a23ddb235e4b3defe276afc220a6227237f3efe83f51e"},
"ecto": {:hex, :ecto, "3.8.1", "35e0bd8c8eb772e14a5191a538cd079706ecb45164ea08a7523b4fc69ab70f56", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f1b68f8d5fe3ab89e24f57c03db5b5d0aed3602077972098b3a6006a1be4b69b"},
"ecto": {:git, "https://github.com/elixir-ecto/ecto.git", "6e7bc3f4d757b7c09ced10135e0c5c4ce1f4ea2f", []},
"ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [:mix], [{:earmark_parser, "~> 1.4.19", [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", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"},
"jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"},
"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 @@ -497,6 +497,9 @@ defmodule Ecto.Adapters.MyXQLTest do
query = Schema |> select([r], r.x) |> where([], fragment("? = \"query\\?\"", ^10)) |> plan()
assert all(query) == ~s{SELECT s0.`x` FROM `schema` AS s0 WHERE (? = \"query?\")}

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}

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 @@ -542,6 +542,9 @@ defmodule Ecto.Adapters.PostgresTest do
query = Schema |> select([r], fragment("downcase(?)", r.x)) |> plan()
assert all(query) == ~s{SELECT downcase(s0."x") FROM "schema" AS s0}

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}

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
9 changes: 4 additions & 5 deletions test/ecto/adapters/tds_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -600,13 +600,12 @@ defmodule Ecto.Adapters.TdsTest do
end

test "fragments" do
query =
Schema
|> select([r], fragment("lower(?)", r.x))
|> plan()

query = Schema |> select([r], fragment("lower(?)", r.x)) |> plan()
assert all(query) == ~s{SELECT lower(s0.[x]) FROM [schema] AS s0}

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}

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 3b2187a

Please sign in to comment.