fuelen
Cond in Ecto query DSL
Hi all!
Just want to share a small code snippet which allows writing CASE expressions using macro which is similar to cond.
Here is an example of usage:
import Ecto.Extension.Query.API
import Ecto.Query
from users in "users",
select: %{
email: users.email,
role_label:
cond_ do
users.role == "director" -> "DIRECTOR!"
users.inserted_at < ago(6, "month") -> "OLD!"
true -> type(users.role, :string)
end
}
generated SQL:
SELECT u0."email", CASE WHEN u0."role" = 'director' THEN 'DIRECTOR!' WHEN u0."inserted_at" < $1::timestamp + (-6::decimal::numeric * interval '1 month') THEN 'OLD!' WHEN TRUE THEN u0."role"::varchar END FROM "users" AS u0
and implementation:
defmodule Ecto.Extension.Query.API do
defmacro cond_(do: block) do
bindings =
block
|> Enum.reduce([], fn
{:->, _, [[clause], branch]}, acc ->
[branch, clause | acc]
end)
|> Enum.reverse()
bindings_number = length(bindings)
sql =
IO.iodata_to_binary([
"CASE",
List.duplicate(" WHEN ? THEN ?", div(bindings_number, 2)),
" END"
])
quote do
fragment(unquote(sql), unquote_splicing(bindings))
end
end
end
I hope someone will find this useful 
Most Liked
fuelen
Well, this is my first attempt to implement @hauleth idea. Some kind of composability is still possible
defmodule CustomEctoFrom do
defmacro __using__(map) do
quote do
require Ecto.Query
defmacro from(expr, kw) do
kw = CustomEctoFrom.traverse(kw, unquote(map))
quote do
Ecto.Query.from(unquote(expr), unquote(kw))
end
end
end
end
def traverse({function, args}, map) when is_atom(function) do
{function, traverse(args, map)}
end
def traverse({function, meta, args}, map) do
function =
case Map.fetch(map, function) do
{:ok, aliased_to} -> aliased_to
:error -> function
end
{traverse(function, map), meta, traverse(args, map)}
end
def traverse(kw, map) when is_list(kw) do
for elem <- kw, do: traverse(elem, map)
end
def traverse(term, _map), do: term
end
defmodule OtherModuleWithExtensions do
defmacro concat(a, b) do
quote do
fragment("? || ?", unquote(a), unquote(b))
end
end
end
defmodule Test do
import Ecto.Extension.Query.API
import OtherModuleWithExtensions
use CustomEctoFrom, %{cond: :cond_, <>: :concat}
def test do
from users in "users",
select: %{
full_name: users.first_name <> " " <> users.last_name,
email: users.email,
role_label:
cond do
users.role == "director" -> "DIRECTOR!"
users.inserted_at < ago(6, "month") -> "OLD!"
true -> type(users.role, :string)
end,
id: users.id
}
end
end
1
Popular in Guides/Tuts
Hey guys I’ve made a guide on how to connect Quill to Phoenix.
For the sake of formatting it might be easier to view it on my Notion Doc...
New
Greetings: I just wrote a step-by-step guide on building a Phoenix 1.3 JWT Auth API with Guardian JWTs and Comeonin password hashing.
I ...
New
TLS 1.3 has been out for a little over a year now, but it has been unavailable in Phoenix due to erlang’s handling of ssl. With the most ...
New
Hey friends, wanted to share a tiny shell script I’ve been using to start Livebook with easy access to either a running production server...
New
I wrote a small article on how to use current_user with coherence on Phoenix. There are already a couple of blogposts about it but I thin...
New
In the process of developing a Phx-based multiplayer experience, I found myself with so many browser tabs open with Elixir gaming resourc...
New
Hi everyone,
I recently implemented a real-time search feature in a Phoenix application using LiveView and Tailwind, and I wanted to sha...
New
Hi guys,
I’ve been on a personal journey to learn Elixir for the past two years. During this journey I’ve been using the spaced repetiti...
New
Hi everyone,
Just wanted to say that the new Self-referencing many to many guide is now up on the official Hex docs (at least I just not...
New
We just published a guide to automatic clustering in Elixir 1.9, with Mix releases and libcluster.
The cluster automatically discovers n...
New
Other popular topics
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
Hello all!
I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
Hi folks,
Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
New
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Hey all,
I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
I am trying to run a deploy with docker and I successfully runned with this command:
docker build -t romenigld/blog-prod .
but when I t...
New







