# SWAFQueries
`SWAFQueries` is a thin layer on top of Ecto and MyXQL driver that
compiles raw SQL files into Elixir functions.
## Installation
The package can be installed by adding `swaf_queries` to your list of
dependencies in `mix.exs`:
```
defp deps do
[
# {:swaf_views, path: "../swaf_queries"},
{:swaf_queries, "~> 0.2"}
]
end
```
See [Hexdocs](https://hexdocs.pm/swaf_queries/0.2.0/api-reference.html)
for a full documentation.
## Features
* Define as many queries as needed per `.sql` file. All the queries in
a file will be compiled into Elixir functions and will belong to a
module named after the name of the `.sql` file. For the moment
sub-directories are not taken into account but this is on the TODO
list.
* Queries get compiled from within the REPL without need to leave IEx
and explicitly recompile with `mix compile` or `iex -S mix` with the
exception for new files (see the documentation).
* Elixir documentation is generated out of the SQL comments for the
module and for the generated functions. Use `mix docs` in the project.
* Parameters of generated functions are the parameters of the query as
specified in SQL.
* `SWAFQueries` works with MySQL and MariaDB through the `MyXQL` driver
and uses all the goodies provided by Ecto. Integration with Postgrex
is on the TODO list.
* `SWAFQueries` **does not** parse, interpret nor optimize the SQL
code.
`SWAFQueries` is based on Ecto which are fantastic pieces of code that
implement many goodies. The main ones:
* Prepared statement caching for better performance and security
* Automated transaction management
## Todo
Interested to give a hand? Welcome, be my guest and contact me.
* P0: add the `stream:` hint for `defq:`
* P0: manage directory hierarchies so that if the file `user.sql` is
located in `sql/auth/user.sql`, queries will belong to the module
`Auth.User`.
* P0: implement additional hints
* *bang* variants of hints (really necessary ?). `raw!:`, `map!:`,
`stream!:`, `result!:` would return the results directly on success
or raise an error otherwise rather than returning result tuples.
* `all:` would generate all four `raw:`, `map:`, `stream:`, `result:`
* P0: Write a blog and improve documentation
* P0: See how to avoid creation of `Repo.ex`. Probably need to include
it in `Queries.ex`
* P1: Add support for Postgrex and possibly to some other
drivers. Needs to be thought throughout as for the moment the code is
really tied with `MyXQL` driver (positional parameters, returned
results, ...)
* P1: Add an URL to access the DB rather than all the parameters.
* P2: Parameterize query functions with maps and/or keyword lists
(really useful?). For example: `my_query(%{name: "marco", lastname:
"polo"})` or `my_query([name: "marco", surname: "polo"])`
* P1: Add a `compile(sql, {m, f, a}, hints \\ [])` function which will
compile `sql`, an SQL string, and create a function `f` with arity
`a` in the module `m` for use cases not covered by `SWAFQueries`.
* P2 : See [SQLYac](https://github.com/Kalli/sqlyac) and see if it
might be possible to create mix tasks on the same model that
could be used from the command line. For example:
```sql
mix sql sql/user.sql get_user_by_id 42
```
* P1: Global comments to comment out (and ignore) whole parts of code
(for now all comments are used as documentation. For example:
```sql
-- /* This is the start of a global comment
-- defq: some_query
SOME SQL STATEMENTS
-- */
```
All what is between `-- /*` and `-- */` is ignored.
Possibly add a single line comments introduced with `-- //`.
* P2: In function documentation, generate the code of the query
as it is formatted in the SQL file
* P2: `-- no_moduledoc:`: do not generate any module doc, even if
there are global SQL comments
* P2: `-- no_doc`: do not generate function documentation, even if
there are query level SQL comments
## Motivation
My personal reason is that I don't like Ecto DSL. Please, understand
me. Ecto is a great piece of code and `SWAFQueries` relies on it, but
it's just too much for my needs. I'm not (any more) a professional
developer and I'm working on one, maybe two side projects per year
that require a database. Every time I try Ecto, I feel like I need to
re-learn a new language, which means new syntax, debugging, etc. while
the only thing I actually need to do is to send a `SELECT` or an
`INSERT` to a database. Yet, I'm definitely not some kind of
*pro-pure-SQL* extremist and I love having help from my development
stack like connection management, security, optimization.
There are some other good and more general reasons to use SQL directly:
* While the developers may be proficient in Elixir, it might not be
the case with the DBA: it might not be simple to optimize a query
written in Ecto DSL
* When working on large projects, same requests may be required by
different parts of the system not all written in Elixir.
* SQL has excellent tooling and dedicated IDE that require to use SQL
* One argument I've often read about Ecto is that it abstracts
database access and, thus, it allows easy swap from one SQL dialect
to another one. I'm not really sure such use cases happen often in
real life.
All that put together, I started to look around how the others were
doing, to write some macros that inject helpers and it finished with
`SWAFQueries`.
## Sources of inspiration and alternatives
* [Elixir Without Ecto](https://www.openmymind.net/Elixir-Without-Ecto/)
* [Yesql Github page](https://github.com/lpil/yesql)
* [AyeSQL Github page](https://github.com/alexdesousa/ayesql)
* [SQLYac](https://github.com/Kalli/sqlyac)
* Few days ago I came across a post on [Elixir
forum](https://elixirforum.com/t/sqlkit-execute-raw-sql-in-strings-or-sql-files-get-maps-and-structs-back/73794)
which presented yet another alternative developed recently,
[SqlKit](https://github.com/tylerbarker/sql_kit) that is worth
looking at.