Created
September 4, 2024 02:16
-
-
Save zachdaniel/4df0b35185b1bc729b8a420703e0694c to your computer and use it in GitHub Desktop.
A really shitty parser that gets a list of string expressions from a Postgres index creation definition
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# CREATE INDEX users_lower_email_idx ON public.users USING btree (lower((email)::text)) | |
# CREATE INDEX unique_email_com3 ON public.users USING btree (email, id) WHERE (email ~~ '%.com'::citext) | |
defp parse_columns_from_index_def(string, using) do | |
string | |
|> String.trim_leading("CREATE ") | |
|> String.trim_leading("UNIQUE ") | |
|> String.trim_leading("INDEX ") | |
|> String.replace(~r/^[a-zA-Z0-9_\.]+\s/, "") | |
|> String.trim_leading("ON ") | |
|> String.replace(~r/^[\S]+/, "") | |
|> String.trim_leading() | |
|> String.trim_leading("USING #{using} ") | |
|> do_parse_columns() | |
|> then(&{:ok, &1}) | |
catch | |
:error -> :error | |
end | |
def parse_columns(char) do | |
do_parse_columns(char) | |
end | |
defp do_parse_columns(char, state \\ [], field \\ "", acc \\ []) | |
defp do_parse_columns("(" <> rest, [], field, acc) do | |
do_parse_columns(rest, [:outer], field, acc) | |
end | |
defp do_parse_columns(")" <> _rest, [:outer], field, acc) do | |
if field == "" do | |
Enum.reverse(acc) | |
else | |
Enum.reverse([field | acc]) | |
end | |
end | |
defp do_parse_columns("(" <> rest, [:outer], field, acc) do | |
do_parse_columns(rest, [:in_paren, :in_field, :outer], field, acc) | |
end | |
defp do_parse_columns(", " <> rest, [:in_field, :outer], field, acc) do | |
do_parse_columns(rest, [:in_field, :outer], "", [field | acc]) | |
end | |
defp do_parse_columns(<<str::binary-size(1)>> <> rest, [:outer], field, acc) do | |
do_parse_columns(rest, [:in_field, :outer], field <> str, acc) | |
end | |
defp do_parse_columns("''" <> rest, [:in_quote | stack], field, acc) do | |
do_parse_columns(rest, [:in_quote | stack], field <> "'", acc) | |
end | |
defp do_parse_columns("'" <> rest, [:in_quote | stack], field, acc) do | |
do_parse_columns(rest, stack, field <> "'", acc) | |
end | |
defp do_parse_columns(<<str::binary-size(1)>> <> rest, [:in_quote | stack], field, acc) do | |
do_parse_columns(rest, [:in_quote | stack], field <> str, acc) | |
end | |
defp do_parse_columns("'" <> rest, stack, field, acc) do | |
do_parse_columns(rest, [:in_quote | stack], field <> "'", acc) | |
end | |
defp do_parse_columns("(" <> rest, stack, field, acc) do | |
do_parse_columns(rest, [:in_paren | stack], field <> "(", acc) | |
end | |
defp do_parse_columns(")" <> rest, [:in_paren | stack], field, acc) do | |
do_parse_columns(rest, stack, field <> ")", acc) | |
end | |
defp do_parse_columns("), " <> rest, [:in_field | stack], field, acc) do | |
do_parse_columns(rest, [:in_field | stack], "", [field | acc]) | |
end | |
defp do_parse_columns(")" <> _rest, [:in_field | _stack], field, acc) do | |
Enum.reverse([field | acc]) | |
end | |
defp do_parse_columns(<<str::binary-size(1)>> <> rest, [:in_paren | stack], field, acc) do | |
do_parse_columns(rest, [:in_paren | stack], field <> str, acc) | |
end | |
defp do_parse_columns(<<str::binary-size(1)>> <> rest, [:outer], field, acc) do | |
do_parse_columns(rest, [:in_field, :outer], field <> str, acc) | |
end | |
defp do_parse_columns(<<str::binary-size(1)>> <> rest, [:in_field | stack], field, acc) do | |
do_parse_columns(rest, [:in_field | stack], field <> str, acc) | |
end | |
defp do_parse_columns(", " <> rest, [:in_field | stack], field, acc) do | |
do_parse_columns(rest, stack, "", [field | acc]) | |
end | |
defp do_parse_columns(")" <> _rest, [:outer], field, acc) do | |
Enum.reverse([field | acc]) | |
end | |
defp do_parse_columns("", [:in_field | _stack], field, acc) do | |
Enum.reverse([field | acc]) | |
end | |
defp do_parse_columns("", [:outer], field, acc) do | |
if field == "" do | |
Enum.reverse(acc) | |
else | |
Enum.reverse([field | acc]) | |
end | |
end | |
defp do_parse_columns(other, stack, field, acc) do | |
raise "Unexpected character: #{inspect(other)} at #{inspect(stack)} with #{inspect(field)} - #{inspect(acc)}" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment