AyeSQL v0.5.0 AyeSQL View Source

Aye /ʌɪ/ exclamation (archaic dialect): said to express assent; yes.

AyeSQL is a small Elixir library for using raw SQL.

Overview

Inspired on Clojure library Yesql, AyeSQL tries to find a middle ground between those two approaches by:

  • Keeping the SQL in SQL files.
  • Generating Elixir functions for every query.
  • Having mandatory and optional named parameters.
  • Allowing query composability with ease.

Using the previous query, we would create a SQL file with the following contents:

-- name: get_day_interval
-- This query do not have docs, so it's private.
SELECT datetime::date AS date
  FROM generate_series(
        current_date - :days::interval, -- Named parameter :days
        current_date - interval '1 day',
        interval '1 day'
      );

-- name: get_avg_clicks
-- docs: Gets average click count.
    WITH computed_dates AS ( :get_day_interval ) -- Composing with another query
  SELECT dates.date AS day, count(clicks.id) AS count
    FROM computed_date AS dates
        LEFT JOIN clicks AS clicks ON date(clicks.inserted_at) = dates.date
  WHERE clicks.link_id = :link_id -- Named parameter :link_id
GROUP BY dates.date
ORDER BY dates.date;

In Elixir we would load all the queries in this file by creating the following module:

defmodule Queries do
  use AyeSQL, repo: MyRepo

  defqueries("queries.sql") # File name with relative path to SQL file.
end

or using the macro defqueries/3:

import AyeSQL, only: [defqueries: 3]

defqueries(Queries, "queries.sql", repo: MyRepo)

Both approaches will create a module called Queries with all the queries defined in "queries.sql".

And then we could execute the query as follows:

iex> params = [
...>   link_id: 42,
...>   days: %Postgrex.Interval{secs: 864_000} # 10 days
...> ]
iex> Queries.get_avg_clicks(params, run?: true)
{:ok,
  [
    %{day: ..., count: ...},
    ...
  ]
}

Link to this section Summary

Functions

Uses AyeSQL for loading queries.

Macro to load queries from a file.

Macro to load queries from a file and create a module for them.

Link to this section Functions

Link to this macro

__using__(options)

View Source (macro)

Uses AyeSQL for loading queries.

The available options are:

  • runner: module handling the query.

Any other option will be passed to the runner.

Link to this macro

defqueries(relative)

View Source (macro)

Macro to load queries from a file.

Let's say we have the file my_queries.sql with the following contents:

-- name: get_user
-- docs: Gets user by username
SELECT *
  FROM users
 WHERE username = :username;

We can load our queries to Elixir using the macro defqueries/1 as follows:

defmodule Queries do
  use AyeSQL, repo: MyRepo

  defqueries("my_queries.sql")
end

We can now do the following to get the SQL and the ordered arguments:

iex(1)> Queries.get_user!(%{username: "some_user"})
{"SELECT * FROM user WHERE username = $1", ["some_user"]}

If we would like to execute the previous query directly, the we could do the following:

iex(1)> Queries.get_user!(%{username: "some_user"}, run?: true)
%Postgrex.Result{...}

We can also run the query by composing it with the Queries.run/1 function generated in the module e.g:

iex(1)> %{username: "some_user"} |> Queries.get_user!() |> Queries.run!()
%Postgrex.Result{...}
Link to this macro

defqueries(module, relative, options)

View Source (macro)

Macro to load queries from a file and create a module for them.

Same as defqueries/1, but creates a module e.g:

use AyeSQL, repo: MyRepo

defqueries(Queries, "my_queries.sql")

This will generate the module Queries and it'll contain all the SQL statements included in "sql/my_queries.sql".