Skip to content

Commit 0392d88

Browse files
authored
Support explain format option for myxql (#454)
1 parent 2821dd8 commit 0392d88

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed

integration_test/myxql/explain_test.exs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,13 @@ defmodule Ecto.Integration.ExplainTest do
3434
TestRepo.explain(:all, from(p in "posts", select: p.invalid, where: p.invalid == "title"))
3535
end)
3636
end
37+
38+
test "map format" do
39+
[explain] = TestRepo.explain(:all, Post, format: :map)
40+
keys = explain["query_block"] |> Map.keys
41+
assert Enum.member?(keys, "cost_info")
42+
assert Enum.member?(keys, "select_id")
43+
assert Enum.member?(keys, "table")
44+
end
3745
end
3846
end

lib/ecto/adapters/myxql/connection.ex

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,18 @@ if Code.ensure_loaded?(MyXQL) do
222222
end
223223

224224
@impl true
225-
# DB explain opts are deprecated, so they aren't used to build the explain query.
225+
# DB explain opts, except format, are deprecated.
226226
# See Notes at https://dev.mysql.com/doc/refman/5.7/en/explain.html
227227
def explain_query(conn, query, params, opts) do
228-
case query(conn, build_explain_query(query), params, opts) do
228+
{explain_opts, opts} = Keyword.split(opts, ~w[format]a)
229+
map_format? = {:format, :map} in explain_opts
230+
231+
case query(conn, build_explain_query(query, explain_opts), params, opts) do
232+
{:ok, %MyXQL.Result{rows: rows}} when map_format? ->
233+
json_library = MyXQL.json_library()
234+
decoded_result = Enum.map(rows, &json_library.decode!(&1))
235+
{:ok, decoded_result}
236+
229237
{:ok, %MyXQL.Result{} = result} ->
230238
{:ok, SQL.format_table(result)}
231239

@@ -234,11 +242,16 @@ if Code.ensure_loaded?(MyXQL) do
234242
end
235243
end
236244

237-
def build_explain_query(query) do
245+
def build_explain_query(query, []) do
238246
["EXPLAIN ", query]
239247
|> IO.iodata_to_binary()
240248
end
241249

250+
def build_explain_query(query, [format: value]) do
251+
["EXPLAIN #{String.upcase("#{format_to_sql(value)}")} ", query]
252+
|> IO.iodata_to_binary()
253+
end
254+
242255
## Query generation
243256

244257
binary_ops =
@@ -1080,6 +1093,9 @@ if Code.ensure_loaded?(MyXQL) do
10801093
[?`, name, ?`]
10811094
end
10821095

1096+
defp format_to_sql(:map), do: "FORMAT=JSON"
1097+
defp format_to_sql(:text), do: "FORMAT=TRADITIONAL"
1098+
10831099
defp intersperse_map(list, separator, mapper, acc \\ [])
10841100
defp intersperse_map([], _separator, _mapper, acc),
10851101
do: acc

lib/ecto/adapters/sql.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,9 @@ defmodule Ecto.Adapters.SQL do
320320
Also note that:
321321
322322
* Currently `:map`, `:yaml`, and `:text` format options are supported
323-
for PostgreSQL. `:map` is the deserialized JSON encoding. The last two
324-
options return the result as a string;
323+
for PostgreSQL. Only `map` and `text` are supported for MyXQL.
324+
* `:map` is the deserialized JSON encoding.
325+
* `:yaml` and `text` return the result as a string;
325326
326327
* Any other value passed to `opts` will be forwarded to the underlying
327328
adapter query function, including Repo shared options such as `:timeout`;

test/ecto/adapters/myxql_test.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,8 @@ defmodule Ecto.Adapters.MyXQLTest do
719719
end
720720

721721
test "build_explain_query" do
722-
assert SQL.build_explain_query("SELECT 1") == "EXPLAIN SELECT 1"
722+
assert SQL.build_explain_query("SELECT 1", []) == "EXPLAIN SELECT 1"
723+
assert SQL.build_explain_query("SELECT 1", format: :map) == "EXPLAIN FORMAT=JSON SELECT 1"
723724
end
724725

725726
## *_all

0 commit comments

Comments
 (0)