Skip to content

Commit b187e95

Browse files
committed
refactor handling of span and offset
1 parent b72bff1 commit b187e95

File tree

9 files changed

+602
-640
lines changed

9 files changed

+602
-640
lines changed

bench.exs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ defmodule SQL.Repo do
44
use Ecto.Repo, otp_app: :sql, adapter: Ecto.Adapters.Postgres
55
use SQL, adapter: SQL.Adapters.Postgres, repo: __MODULE__
66

7-
def test() do
8-
~SQL[select 1]
9-
|> SQL.map(fn row -> row end)
10-
|> Enum.to_list
7+
def sql() do
8+
Enum.to_list ~SQL[select 1]
9+
end
10+
11+
def ecto() do
12+
{sql, params} = to_sql(:all, select(from("users"), 1))
13+
{:ok, %{columns: columns, rows: rows}} = query(sql, params)
14+
Enum.map(rows, &Map.new(Enum.zip(columns, &1)))
1115
end
1216
end
1317
Application.put_env(:sql, :ecto_repos, [SQL.Repo])
14-
Application.put_env(:sql, SQL.Repo, username: "postgres", password: "postgres", hostname: "localhost", database: "sql_test#{System.get_env("MIX_TEST_PARTITION")}", pool: Ecto.Adapters.SQL.Sandbox, pool_size: 10)
18+
Application.put_env(:sql, SQL.Repo, log: false, username: "postgres", password: "postgres", hostname: "localhost", database: "sql_test#{System.get_env("MIX_TEST_PARTITION")}", pool: Ecto.Adapters.SQL.Sandbox, pool_size: 10)
1519
SQL.Repo.__adapter__().storage_up(SQL.Repo.config())
1620
SQL.Repo.start_link()
1721
query = "temp" |> recursive_ctes(true) |> with_cte("temp", as: ^union_all(select("temp", [t], %{n: 0, fact: 1}), ^where(select("temp", [t], [t.n+1, t.n+1*t.fact]), [t], t.n < 9))) |> select([t], [t.n])
@@ -34,13 +38,14 @@ Benchee.run(
3438
{:ok, pcontext, tokens} = SQL.Parser.parse(tokens, context)
3539
pcontext.module.to_iodata(tokens, pcontext)
3640
end,
37-
"parse" => fn _ -> SQL.parse("with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)") end,
38-
"runtime dynamic" => fn _ -> ~SQL[from users] |> ~SQL[select *] |> ~SQL[where id = {{1+2*3}}] end,
39-
"runtime ecto dynamic" => fn _ -> SQL.Repo.to_sql(:all, from("users") |> select([t], t.id) |> where([t], t.id == ^(1+2*3))) end,
41+
"parse/1" => fn _ -> SQL.parse("with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)") end,
42+
"sql" => fn _ -> SQL.Repo.sql() end,
43+
"ecto" => fn _ -> SQL.Repo.ecto() end,
4044
"runtime to_string" => fn _ -> to_string(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) end,
4145
"runtime to_sql" => fn _ -> SQL.to_sql(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) end,
4246
"runtime inspect" => fn _ -> inspect(~SQL[with recursive temp (n, fact) as (select 0, 1 union all select n+1, (n+1)*fact from temp where n < 9)]) end,
43-
"runtime ecto" => fn _ -> SQL.Repo.to_sql(:all, "temp" |> recursive_ctes(true) |> with_cte("temp", as: ^union_all(select("temp", [t], %{n: 0, fact: 1}), ^where(select("temp", [t], [t.n+1, t.n+1*t.fact]), [t], t.n < 9))) |> select([t], [t.n])) end
47+
"runtime ecto" => fn _ -> SQL.Repo.to_sql(:all, "temp" |> recursive_ctes(true) |> with_cte("temp", as: ^union_all(select("temp", [t], %{n: 0, fact: 1}), ^where(select("temp", [t], [t.n+1, t.n+1*t.fact]), [t], t.n < 9))) |> select([t], [t.n])) end,
48+
"comptime ecto" => fn _ -> SQL.Repo.to_sql(:all, query) end
4449
},
4550
inputs: %{"1..100_000" => Enum.to_list(1..100_000)},
4651
memory_time: 2,

lib/format.ex

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,59 @@ defmodule SQL.Format do
55
@moduledoc false
66
@moduledoc since: "0.4.0"
77

8-
@compile {:inline, indention: 3, newline: 2}
8+
@error IO.ANSI.red()
9+
@reset IO.ANSI.reset()
10+
@keyword IO.ANSI.magenta()
11+
@literal IO.ANSI.yellow()
12+
@enclosed IO.ANSI.green()
13+
14+
@compile {:inline, indention: 3, newline: 2, pad: 1}
915

1016
@doc false
1117
@doc since: "0.4.0"
12-
def to_iodata(tokens, context, indent \\ 0), do: newline(to_iodata(tokens, context.binding, context.case, context.errors, indent, []), indent)
18+
def to_iodata(tokens, context, indent \\ 0), do: pad(to_iodata(tokens, context.binding, context.case, context.errors, indent, []))
1319

14-
defp indention(acc, [{:preset, {_,0}},_,{:offset, {_,0,_,_}}|_], _), do: acc
15-
defp indention(acc, [_,{:offset, {_,0}}|_], 0), do: acc
16-
defp indention(["\e[33m"|_]=acc, [_,{:offset, {_,0}}|_], _), do: acc
20+
defp indention(acc, [{_, {_,_,_,_,_,0}}|_], _), do: acc
21+
defp indention(acc, [{_, {_,_,_,_,_,0,_,_}}|_], _), do: acc
22+
defp indention(acc, 0, 0), do: acc
1723
defp indention(acc, _, 0), do: [?\s|acc]
1824
defp indention(acc, _, 1), do: [?\s,?\s|acc]
19-
defp indention(acc, _, 2), do: [?\s,?\s,?\s,?\s|acc]
20-
defp indention(acc, _, indent), do: [:lists.duplicate(?\s, indent*2)|acc]
25+
defp indention(acc, m, indent), do: indention([?\s,?\s|acc], m, indent-1)
26+
27+
defp newline(acc, indent), do: [?\n|indention(acc, 0, indent)]
2128

22-
defp newline([?\n, ?\s|acc], 0), do: [?\n|acc]
23-
defp newline([?\s|acc], 0), do: [?\n|acc]
24-
defp newline([?\n|_]=acc, _indent), do: acc
25-
defp newline(acc, _indent), do: [?\n|acc]
29+
defp pad([?\n|_]=acc), do: acc
30+
defp pad(acc), do: [?\n|acc]
2631

27-
newline = ~w[select from join where group having window order limit offset fetch]a
32+
newline = ~w[select from join where having window limit offset fetch]a
2833
{reserved, non_reserved, operators} = SQL.BNF.get_rules()
2934
for atom <- Enum.uniq(Enum.map(reserved++non_reserved++operators,&elem(&1, 0))), atom not in newline do
3035
defp to_iodata(unquote(atom), _binding ,:lower, _errors, _indent, acc) do
31-
["\e[35m", unquote("#{atom}"), "\e[0m"|acc]
36+
[@keyword, unquote("#{atom}"), @reset|acc]
3237
end
3338
defp to_iodata(unquote(atom), _binding, :upper, _errors, _indent, acc) do
34-
["\e[35m", unquote(String.upcase("#{atom}")), "\e[0m"|acc]
39+
[@keyword, unquote(String.upcase("#{atom}")), @reset|acc]
3540
end
3641
end
3742
for atom <- newline do
38-
defp to_iodata({unquote(atom), m, values}, binding, :lower=case, errors, indent, acc) do
39-
newline(indention(["\e[35m", unquote("#{atom}"), "\e[0m"|newline(to_iodata(values, binding, case, errors, indent+1, acc), indent+1)], m, indent), indent)
43+
defp to_iodata({unquote(atom), _m, values}, binding, :lower=case, errors, indent, acc) do
44+
newline([@keyword, unquote("#{atom}"), @reset|newline(to_iodata(values, binding, case, errors, indent, acc), indent)], indent)
45+
end
46+
defp to_iodata({unquote(atom), _m, values}, binding, :upper=case, errors, indent, acc) do
47+
newline([@keyword, unquote(String.upcase("#{atom}")), @reset|newline(to_iodata(values, binding, case, errors, indent, acc), indent)], indent)
48+
end
49+
end
50+
for atom <- ~w[group order]a do
51+
defp to_iodata({unquote(atom), _m, values}, binding, :lower=case, errors, indent, acc) do
52+
newline([@keyword, unquote("#{atom}"), @reset|to_iodata(values, binding, case, errors, indent, acc)], indent)
4053
end
41-
defp to_iodata({unquote(atom), m, values}, binding, :upper=case, errors, indent, acc) do
42-
newline(indention(["\e[35m", unquote(String.upcase("#{atom}")), "\e[0m"|newline(to_iodata(values, binding, case, errors, indent+1, acc), indent+1)], m, indent), indent)
54+
defp to_iodata({unquote(atom), _m, values}, binding, :upper=case, errors, indent, acc) do
55+
newline([@keyword, unquote(String.upcase("#{atom}")), @reset|to_iodata(values, binding, case, errors, indent, acc)], indent)
4356
end
4457
end
58+
defp to_iodata({tag, m, values}, binding, case, errors, indent, acc) when tag in ~w[by on]a do
59+
indention(to_iodata(tag, binding, case, errors, 0, newline(to_iodata(values, binding, case, errors, indent, acc), indent)), m, 0)
60+
end
4561
defp to_iodata(:comma, _binding, _case, _errors, 0, acc) do
4662
[?,|acc]
4763
end
@@ -67,53 +83,68 @@ defmodule SQL.Format do
6783
[?\\,?*,value,?*,?\\|acc]
6884
end
6985
defp to_iodata({:quote, m, value}, _binding, _case, _errors, indent, acc) do
70-
indention([?',"\e[32m" , value, "\e[0m",?'|acc], m, indent)
86+
indention([?',@enclosed, value, @reset,?'|acc], m, indent)
7187
end
7288
defp to_iodata({:backtick, m, value}, _binding, _case, _errors, indent, acc) do
73-
indention([?`,"\e[32m" , value, "\e[0m",?`|acc], m, indent)
89+
indention([?`,@enclosed, value, @reset,?`|acc], m, indent)
7490
end
7591
defp to_iodata({tag, m, []}, binding, case, errors, indent, acc) do
7692
indention(to_iodata(tag, binding, case, errors, indent, acc), m, indent)
7793
end
78-
defp to_iodata({:paren, m, [{t, _, _}|_]=values}, binding, case, errors, indent, acc) when t in unquote(newline++~w[union except intersect]a) do
94+
defp to_iodata({:paren, m, [{t, _, _}|_]=values}, binding, case, errors, indent, acc) when t in unquote(newline++~w[group order union except intersect]a) do
7995
indention([?(|to_iodata(values, binding, case, errors, indent+1, [?\n,?)|acc])], m, indent)
8096
end
8197
defp to_iodata({:paren, m, values}, binding, case, errors, indent, acc) do
8298
indention([?(|to_iodata(values, binding, case, errors, 0, [?)|acc])], m, indent)
8399
end
84-
defp to_iodata({:bracket, _m, values}, binding, case, errors, indent, acc) do
85-
[?[|to_iodata(values, binding, case, errors, indent, [?]|acc])]
100+
defp to_iodata({:bracket, m, values}, binding, case, errors, indent, acc) do
101+
indention([?[|to_iodata(values, binding, case, errors, 0, [?]|acc])], m, indent)
102+
end
103+
defp to_iodata({:brace, m, values}, binding, case, errors, indent, acc) do
104+
indention([?{|to_iodata(values, binding, case, errors, 0, [?}|acc])], m, indent)
86105
end
87106
defp to_iodata({_, [], values}, binding, case, errors, indent, acc) do
88107
to_iodata(values, binding, case, errors, indent, acc)
89108
end
90-
defp to_iodata({:ident, [_,_,_,{:tag, tag}|_]=m, [{:paren, _, _}]=values}, binding, case, errors, indent, acc) do
109+
defp to_iodata({:ident, [_,_,{:tag, tag}|_]=m, [{:paren, _, _}]=values}, binding, case, errors, indent, acc) do
91110
indention(to_iodata(tag, binding, case, errors, indent, to_iodata(values, binding, case, errors, indent, acc)), m, indent)
92111
end
93-
defp to_iodata({tag, [{:span, {l, c, _, _}}|_]=m, [{_, [{:span, {ll, cc, _, _}}|_], _}]=values}, binding, case, errors, indent, acc) when l >= ll and c >= cc do
112+
defp to_iodata({tag, [{_, {l,c,_,_,_,_}}|_]=m, [{_, [{_, {l,lc,_,_,_,_}}|_], _}=left, {_, [{_, {l,rc,_,_,_,_}}|_], _}=right]}, binding, case, errors, indent, acc) when (c > lc and c < rc) do
113+
to_iodata(left, binding, case, errors, indent, indention(to_iodata(tag, binding, case, errors, 0, to_iodata(right, binding, case, errors, 0, acc)), m, 0))
114+
end
115+
defp to_iodata({tag, [{_, {l,c,_,_,_,_}}|_]=m, [{_, [{_, {l,lc,_,_,_,_,_,_}}|_], _}=left, {_, [{_, {l,rc,_,_,_,_,_,_}}|_], _}=right]}, binding, case, errors, indent, acc) when (c > lc and c < rc) do
116+
to_iodata(left, binding, case, errors, indent, indention(to_iodata(tag, binding, case, errors, 0, to_iodata(right, binding, case, errors, 0, acc)), m, 0))
117+
end
118+
defp to_iodata({tag, [{_, {l,c,_,_,_,_}}|_]=m, [{_, [{_, {l,lc,_,_,_,_}}|_], _}=left, {_, [{_, {l,rc,_,_,_,_,_,_}}|_], _}=right]}, binding, case, errors, indent, acc) when (c > lc and c < rc) do
119+
to_iodata(left, binding, case, errors, indent, indention(to_iodata(tag, binding, case, errors, 0, to_iodata(right, binding, case, errors, 0, acc)), m, 0))
120+
end
121+
defp to_iodata({tag, [{_, {l,c,_,_,_,_}}|_]=m, [{_, [{_, {l,lc,_,_,_,_,_,_}}|_], _}=left, {_, [{_, {l,rc,_,_,_,_}}|_], _}=right]}, binding, case, errors, indent, acc) when (c > lc and c < rc) do
122+
to_iodata(left, binding, case, errors, indent, indention(to_iodata(tag, binding, case, errors, 0, to_iodata(right, binding, case, errors, 0, acc)), m, 0))
123+
end
124+
defp to_iodata({tag, [{_, {l,c,_,_,_,_}}|_]=m, [{_, [{_, {ll,cc,_,_,_,_}}|_], _}]=values}, binding, case, errors, indent, acc) when (l == ll and c < cc and tag in ~w[desc asc not]a) do
125+
to_iodata(values, binding, case, errors, indent, indention(to_iodata(tag, binding, case, errors, indent, acc), m, 0))
126+
end
127+
defp to_iodata({tag, [{_, {l,c,_,_,_,_}}|_]=m, [{_, [{_, {ll,cc,_,_,_,_,_,_}}|_], _}]=values}, binding, case, errors, indent, acc) when (l == ll and c < cc and tag in ~w[desc asc not]a) do
94128
to_iodata(values, binding, case, errors, indent, indention(to_iodata(tag, binding, case, errors, indent, acc), m, 0))
95129
end
96-
defp to_iodata({tag, m, [left, right]}, binding, case, errors, indent, acc) when tag in ~w[union except intersect]a do
97-
to_iodata(left, binding, case, errors, indent, newline(indention(to_iodata(tag, binding, case, errors, indent, to_iodata(right, binding, case, errors, indent, acc)), m, indent), indent))
130+
defp to_iodata({tag, _m, [left, right]}, binding, case, errors, indent, acc) when tag in ~w[union except intersect]a do
131+
to_iodata(left, binding, case, errors, indent, newline(to_iodata(tag, binding, case, errors, indent, to_iodata(right, binding, case, errors, indent, acc)), indent))
98132
end
99-
defp to_iodata({tag, [_,_,{:type, type}|_]=m, [left, right]}, binding, case, errors, indent, acc) when type == :operator or tag in ~w[between cursor for to]a do
100-
to_iodata(left, binding, case, errors, indent, indention(to_iodata(tag, binding, case, errors, indent, to_iodata(right, binding, case, errors, 0, acc)), m, 0))
133+
defp to_iodata({tag, m, [{_,_,_}|_]=values}, binding, case, errors, indent, acc) do
134+
indention(to_iodata(tag, binding, case, errors, indent, to_iodata(values, binding, case, errors, indent, acc)), m, 0)
101135
end
102136
defp to_iodata({tag, m, value}=node, _binding, _case, errors, indent, acc) when tag in ~w[ident numeric special]a do
103137
case node in errors do
104-
true -> indention(["\e[31m", value, "\e[0m"|acc], m, indent)
105-
false -> indention(["\e[33m", value, "\e[0m"|acc], m, indent)
138+
true -> indention([@error, value, @reset|acc], m, indent)
139+
false -> indention([@literal, value, @reset|acc], m, indent)
106140
end
107141
end
108142
defp to_iodata({:double_quote, m, value}=node, _binding, _case, errors, indent, acc) do
109143
case node in errors do
110-
true -> indention([?","\e[31m",value, "\e[0m", ?"|acc], m, indent)
111-
false -> indention([?", "\e[32m" , value, "\e[0m", ?"|acc], m, indent)
144+
true -> indention([?",@error,value, @reset, ?"|acc], m, indent)
145+
false -> indention([?", @enclosed , value, @reset, ?"|acc], m, indent)
112146
end
113147
end
114-
defp to_iodata({tag, m, values}, binding, case, errors, indent, acc) do
115-
indention(to_iodata(tag, binding, case, errors, indent, to_iodata(values, binding, case, errors, indent, acc)), m, 0)
116-
end
117148
defp to_iodata([token|tokens], binding, case, errors, indent, acc) do
118149
to_iodata(token, binding, case, errors, indent, to_iodata(tokens, binding, case, errors, indent, acc))
119150
end

0 commit comments

Comments
 (0)