diff --git a/lib/ecto/adapters/postgres/connection.ex b/lib/ecto/adapters/postgres/connection.ex index b6398531..01834e3d 100644 --- a/lib/ecto/adapters/postgres/connection.ex +++ b/lib/ecto/adapters/postgres/connection.ex @@ -2020,12 +2020,10 @@ if Code.ensure_loaded?(Postgrex) do end defp escape_json(value) when is_binary(value) do - escaped = - value - |> escape_string() - |> :binary.replace("\"", "\\\"", [:global]) - - [?", escaped, ?"] + value + |> json_library().encode_to_iodata!() + |> IO.iodata_to_binary() + |> escape_string() end defp escape_json(value) when is_integer(value) do @@ -2035,6 +2033,10 @@ if Code.ensure_loaded?(Postgrex) do defp escape_json(true), do: ["true"] defp escape_json(false), do: ["false"] + defp json_library do + Application.get_env(:postgrex, :json_library, Jason) + end + # To allow columns in json paths, we use the array[...] syntax # which requires special handling for strings and column references. # We still keep the escape_json/1 variant for strings because it is diff --git a/test/ecto/adapters/postgres_test.exs b/test/ecto/adapters/postgres_test.exs index e877e7be..c6cbaa41 100644 --- a/test/ecto/adapters/postgres_test.exs +++ b/test/ecto/adapters/postgres_test.exs @@ -1008,6 +1008,22 @@ defmodule Ecto.Adapters.PostgresTest do query = Schema |> where([s], s.meta["id"] == "123") |> select(true) |> plan() assert all(query) == ~s|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"id": "123"}'))| + query = Schema |> where([s], s.meta["k"] == "a\\b") |> select(true) |> plan() + assert all(query) == ~S|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"k": "a\\b"}'))| + + query = Schema |> where([s], s.meta["k"] == "l1\nl2") |> select(true) |> plan() + + assert all(query) == + ~S|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"k": "l1\nl2"}'))| + + query = Schema |> where([s], s.meta["k"] == "a\\q") |> select(true) |> plan() + assert all(query) == ~S|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"k": "a\\q"}'))| + + query = Schema |> where([s], s.meta["a\\b"] == "value") |> select(true) |> plan() + + assert all(query) == + ~S|SELECT TRUE FROM "schema" AS s0 WHERE ((s0."meta"@>'{"a\\b": "value"}'))| + query = Schema |> where([s], s.meta["tags"][0]["name"] == "123") |> select(true) |> plan() assert all(query) ==