Packages

Multiple crypto support.

Current section

Files

Jump to
common_parser lib simple_sql.ex
Raw

lib/simple_sql.ex

defmodule CommonParser.SimpleSql do
@moduledoc """
SQL parser
a sql: select * from account_state where balance > 100
# tag := ascii_string([?a..?z], min: 1)
# tag_list := tag | tag , tag
# selector := * | tag_list
# condition := expr
# sql := select selector from tag where condition
"""
import NimbleParsec
import CommonParser.Helper
tag = parse_tag()
defcombinatorp :tag_list,
choice([
tag
|> concat(ignore_space())
|> concat(ignore_sep(","))
|> concat(ignore_space())
|> concat(parsec(:tag_list)),
tag
])
defcombinatorp :selector,
ignore_keyword("select")
|> concat(ignore_space())
|> concat(
choice([
string("*"),
parsec(:tag_list)
])
)
|> concat(ignore_space())
|> reduce({Enum, :uniq, []})
|> unwrap_and_tag(:select)
from =
ignore_keyword("from")
|> concat(ignore_space())
|> concat(tag)
|> concat(ignore_space())
|> reduce({:parser_result_to_atom, []})
|> tag(:from)
condition = ascii_string([], min: 1) |> tag(:where)
# for where condition, we don't allow subquery
where_cond =
ignore_keyword("where")
|> concat(ignore_space())
|> concat(condition)
|> optional()
sql = parsec(:selector) |> concat(from) |> concat(where_cond)
@doc """
parse `select` statement. For testing purpose. Please use `parse/2` instead.
iex> CommonParser.SimpleSql.parse_select("select *")
{:ok, [select: ["*"]], "", %{}, {1, 0}, 8}
iex> CommonParser.SimpleSql.parse_select("select a, b, c, a")
{:ok, [select: ["a", "b", "c"]], "", %{}, {1, 0}, 17}
"""
defparsec :parse_select, parsec(:selector)
@doc """
parse `from` statement. For testing purpose. Please use `parse/2` instead.
iex> CommonParser.SimpleSql.parse_from("from abc")
{:ok, [from: [:abc]], "", %{}, {1, 0}, 8}
iex(4)> CommonParser.SimpleSql.parse_from("from abc, def")
{:ok, [from: [:abc]], ", def", %{}, {1, 0}, 8}
"""
defparsec :parse_from, from
@doc """
parse a full sql. Note that where condition is not parsed. You can use `CommonParser.Expr.parse/2` to validate the where condition.
iex> CommonParser.SimpleSql.parse("select * from abc where c < 10")
{:ok, [select: ["*"], from: [:abc], where: ["c < 10"]], "", %{}, {1, 0}, 30}
iex(7)> CommonParser.SimpleSql.parse(~S(select balance, nonce, num_txs from abc where c < 10 and b not in ["c", "d"]))
{:ok, [select: ["balance", "nonce", "num_txs"], from: [:abc], where: [~S(c < 10 and b not in ["c", "d"])]], "", %{}, {1, 0}, 76}
"""
defparsec :parse, sql
end