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
Correct if me I’m wrong, as best I can tell there aren’t any reasons to use mix run --no-halt in production vs releases. The marginal val...
New
A question I had when first learning contexts and Ecto was how to expand the default context API to support more flexible queries. Usuall...
New
I’m excited about the new LiveComponents feature in LiveView, but I haven’t seen much written on it, so I decided to write a couple of ar...
New
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 ...
New
If you want to use the MongoDB in your next Killer-App-Project, but you did not dare ask because otherwise many would advise you to use P...
New
Me and my boys started a new website specifically designed for other ASP.NET programmers that struggle, as we do, with their transformati...
New
POST IN CONSTRUCTION
Process for compile erlang otp 20 with odbc-unix for Oracle connections on Solaris 11.3 for 64 bits:
Introductio...
New
I just wrote a simple guide on how you can setup a productive elixir development environment in vim.
Its really easy, just a few steps. ...
New
Wrote this guide on how to integrate DropzoneJS with Phoenix Liveview. Hope it helps someone out!
Woah read that title again, what a ...
New
I Created a blog post about setting up svelte with phoenix.
I found it a bit tricky and the only blog post I found was written using som...
New
Other popular topics
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
Hello, how can I check the Phoenix version ?
Thanks !
New
Hello guys,
I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
I have VueJS GUIs with the project generated using Webpack.
I have Elixir modules that will need to be used by the VueJS GUIs.
I forese...
New
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition)
It’s been a while since we first asked this, I...
New
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
Hello!
Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
Lets say I have map like this fetching from my database
%{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









