Packages
exosql
0.2.9
0.2.88
0.2.87
0.2.86
0.2.85
0.2.84
0.2.83
0.2.82
0.2.81
0.2.80
0.2.79
0.2.78
0.2.77
0.2.76
0.2.75
0.2.74
0.2.73
0.2.72
0.2.71
0.2.70
0.2.69
0.2.68
0.2.67
0.2.65
0.2.64
0.2.63
0.2.62
0.2.60
0.2.59
0.2.58
0.2.57
0.2.56
0.2.55
0.2.54
0.2.53
0.2.51
0.2.50
0.2.49
0.2.48
0.2.47
0.2.46
0.2.45
0.2.44
0.2.43
0.2.42
0.2.41
0.2.40
0.2.39
0.2.38
0.2.37
0.2.36
0.2.35
0.2.33
0.2.32
0.2.31
0.2.30
0.2.29
0.2.28
0.2.26
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
Universal SQL engine for Elixir. This library implements the SQL logic to perform queries on user provided databases using a simple interface based on Foreign Data Wrappers from PostgreSQL.
Current section
Files
Jump to
Current section
Files
lib/exosql.ex
require Logger
defmodule ExoSQL do
@moduledoc """
Creates a Generic universal parser that can access many tabular databases,
and perform SQL queries.
The databases can be heterogenic, so you can perform searches mixing
data from postgres, mysql, csv or Google Analytics.
For example:
```
iex> {:ok, result} = ExoSQL.query(
...> "SELECT urls.url, status_code FROM urls INNER JOIN request ON request.url = urls.url",
...> %{
...> "A" => {ExoSQL.Csv, path: "test/data/csv/"},
...> "B" => {ExoSQL.HTTP, []}
...> })
...> ExoSQL.format_result(result)
'''
A.urls.url | B.request.status_code
-------------------------------------
https://serverboards.io/e404 | 404
http://www.facebook.com | 302
https://serverboards.io | 200
http://www.serverboards.io | 301
''' |> to_string
```
It also contains functions for all the steps of the process:
`parse` |> `plan` |> `execute`. They can be useful for debugging pourposes.
Finally there are helper functions as `explain` that prints out an explanation
of the plan, and `format_result` for pretty printing results.
"""
defmodule Query do
defstruct [
select: [],
from: [],
where: nil,
groupby: nil,
join: nil,
orderby: [],
]
end
defmodule Result do
defstruct [
columns: [],
rows: []
]
end
def parse(sql, context), do: ExoSQL.Parser.parse(sql, context)
def plan(parsed, context), do: ExoSQL.Planner.plan(parsed, context)
def execute(plan, context), do: ExoSQL.Executor.execute(plan, context)
def query(sql, context) do
# Logger.debug(inspect sql)
with {:ok, parsed} <- ExoSQL.Parser.parse(sql, context),
{:ok, plan} <- ExoSQL.Planner.plan(parsed) do
ExoSQL.Executor.execute(plan, context)
end
# Logger.debug("parsed #{inspect parsed, pretty: true}")
# Logger.debug("planned #{inspect plan, pretty: true}")
end
def explain(sql, context) do
Logger.info("Explain #{inspect sql}")
{:ok, parsed} = ExoSQL.Parser.parse(sql, context)
{:ok, plan} = ExoSQL.Planner.plan(parsed)
Logger.info(inspect plan, pretty: true)
end
def format_result(res), do: ExoSQL.Utils.format_result(res)
def schema("self", _context) do
{:ok, ["tables"]}
end
# Hack to allow internal non database varaibles at context
def schema("__" <> _rest, _context), do: {:ok, []}
def schema(db, context) do
{db, opts} = context[db]
apply(db, :schema, [opts])
end
def schema("self", "tables", _context) do
{:ok, %{
columns: ["db", "table", "column"]
}}
end
def schema(db, table, context) do
{db, opts} = context[db]
apply(db, :schema, [opts, table])
end
def repl(context) do
input = IO.gets("exosql> ") |> String.trim
case input do
"" -> :eof
_other ->
case query(input, context) do
{:ok, result} ->
IO.puts(format_result(result))
{:error, err} ->
Logger.error(inspect err)
end
repl(context)
end
end
end