Skip to content

Commit 5bd7ec3

Browse files
committed
Add warnings for unknown operators
1 parent 91dc464 commit 5bd7ec3

File tree

4 files changed

+13
-4
lines changed

4 files changed

+13
-4
lines changed

lib/adapters/ansi.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ defmodule SQL.Adapters.ANSI do
9898
def token_to_string({:comma, _, value}, mod) do
9999
"#{mod.token_to_string(value)},"
100100
end
101-
def token_to_string({tag, _, value}, _mod) when tag in ~w[ident numeric]a do
101+
def token_to_string({tag, _, value}, _mod) when tag in ~w[ident numeric special]a do
102102
"#{value}"
103103
end
104104
def token_to_string(value, _mod) when is_atom(value) do
@@ -244,7 +244,7 @@ defmodule SQL.Adapters.ANSI do
244244
def to_iodata({:comma, _, value}, context, indent) do
245245
[context.module.to_iodata(value, context, indent), ?,, ?\s]
246246
end
247-
def to_iodata({tag, _, value} = node, context, _indent) when tag in ~w[ident numeric]a do
247+
def to_iodata({tag, _, value} = node, context, _indent) when tag in ~w[ident numeric special]a do
248248
case node in context.errors do
249249
true -> [:red, value, :reset]
250250
false -> value

lib/lexer.ex

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ defmodule SQL.Lexer do
130130
def lex(<<b, rest::binary>>, %{file: file}=context, line, column, acc) when b in ~c"!#$%&*+-/:<=>?@^|~" do
131131
case special(rest, [[]|[b]], column+1) do
132132
{rest, [_|_]=data, c} ->
133-
lex(rest, context, line, c, [{:special, [type: :literal, line: line, column: column, end_column: c, file: file], data}|acc])
133+
node = {:special, [type: :literal, line: line, column: column, end_column: c, file: file], data}
134+
lex(rest, Map.update!(context, :errors, &:lists.append([[node],&1])), line, c, [node|acc])
134135
{rest, tag, c} ->
135136
lex(rest, context, line, c, [{tag, [type: :operator, line: line, column: column, end_column: c, file: file], []}|acc])
136137
end
@@ -247,6 +248,11 @@ defmodule SQL.Lexer do
247248
reserved = rules.keywords["<reserved word>"] ++ rules.keywords["<SQL/JSON key word>"]
248249
operators = Enum.uniq(Enum.flat_map(rules.operators, &elem(&1, 1)))
249250

251+
suggestions = Enum.map(operators, &to_string(elem(&1, 0)))
252+
def suggest_operator(value) do
253+
Enum.sort(Enum.filter(unquote(suggestions), &(String.jaro_distance("#{value}", &1) > 0)), &(String.jaro_distance(value, &1) >= String.jaro_distance(value, &2)))
254+
end
255+
250256
def ident(<<?', rest::binary>>, prefix, l, c) do
251257
{rest, data, l, c} = quote(rest, [], l, c+1)
252258
{rest, :quote, prefix, data, l, c}

lib/sql.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ defmodule SQL do
226226

227227
@doc false
228228
def format_error(errors), do: Enum.group_by(errors, &elem(&1, 2)) |> Enum.reduce([], fn
229+
{k, [{:special, _, _}]}, acc -> [acc | ["the operator ", :red, k, :reset, " is invalid, did you mean any of #{Enum.join(SQL.Lexer.suggest_operator(:erlang.iolist_to_binary(k)), ", ")}", ?\n]]
230+
{k, [{:special, _, _}|_]=v}, acc -> [acc | ["the operator ", :red, k, :reset, " is mentioned #{length(v)} times but is invalid, did you mean any of #{Enum.join(SQL.Lexer.suggest_operator(:erlang.iolist_to_binary(k)), ", ")}", ?\n]]
231+
{k, [_]}, acc -> [acc | ["the relation ", :red, k, :reset, " does not exist", ?\n]]
229232
{k, v}, acc -> [acc | ["the relation ", :red, k, :reset, " is mentioned #{length(v)} times but does not exist", ?\n]]
230233
end)
231234

test/sql_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ defmodule SQLTest do
105105
end
106106

107107
test "missing relation" do
108-
assert capture_io(:stderr, fn -> SQL.parse("select id from users", set_sql_lock()) end) =~ "is mentioned 1 times but does not exist"
108+
assert capture_io(:stderr, fn -> SQL.parse("select id from users", set_sql_lock()) end) =~ "does not exist"
109109
end
110110
end
111111

0 commit comments

Comments
 (0)