Desenvolvimento

13 fev, 2017

Defql: consultas SQL como funções Elixir

Publicidade

O mundo do Elixir é funcional. Não existem objetos ou instâncias. Neste caso, eu me pergunto: eu preciso de ORM?

Minha resposta a esta pergunta é não.

Eu preciso de dados. Dados puros que venham direto do banco de dados. Outra questão que me vem à mente: preciso de um DSL para consultar o banco de dados?

Novamente, não!

Temos uma grande linguagem criada para consultar bancos de dados. O SQL, lembra?

E se eu pudesse criar uma função em Elixir que tenha o corpo de um SQL? E se eu pudesse usar esta função exatamente como qualquer outra função Elixir? Seria ótimo, não seria?

Podemos fazer isso utilizando o poderoso sistema de macro do Elixir. No entanto, esta também é uma boa maneira de aprender como as macros do Elixir funcionam.

Para fazer isso, eu comecei a escrever o Defql . O Defql é um pacote Elixir que fornece uma maneira simples de definir funções com a linguagem SQL. Como ele funciona?

Consultando bancos de dados

Este pacote fornece a macro defquery. Com ela, você pode definir a função que contenha uma consulta SQL. Por exemplo:

defmodule UserQuery do
  use Defql
 
  defquery get_by_blocked(blocked) do
    "SELECT * FROM users WHERE blocked = $blocked"
  end
end

É muito limpa, fácil de ler, e a melhor parte: suporta parâmetros. Brilhante!

Chamar essa função também é muito simples.
Dependendo do parâmetro fornecido, vamos bloquear ou desbloquear os usuários.

 

UserQuery.get_user(false) # => {:ok, []} 
UserQuery.get_user(true) # => {:ok, []}

Agora podemos facilmente consultar nosso banco de dados e obter um resultado.

E quanto ao INSERT, o UPDATE, e o DELETE? Boa pergunta! Você pode criar as consultas com defquery, mas há outra maneira.

CRUD

Este pacote também contém outras macros. Veja este exemplo:

defmodule UserQuery do
  use Defql

  defselect get(conds), table: :users
  definsert add(params), table: :users
  defupdate update(params, conds), table: :users
  defdelete delete(conds), table: :users
end

O que elas vão fazer? Essas macros irão criar funções CRUD comuns. Então você não precisa escrever cada consulta com o SQL. Consultas simples são criadas para você assim. Como posso chamá-los? Aqui está um exemplo:

UserQuery.get(id: "3") # => {:ok, [%{...}]}
UserQuery.add(name: "Smbdy") # => {:ok, [%{...}]}
UserQuery.update([name: "Other"],[id: "2"]) # => {:ok, [%{...}]}
UserQuery.delete(id: "2") # => {:ok, [%{...}]}

Configuração

A configuração também é fácil. Você pode usar de duas maneiras.

Com uma conexão Ecto existente:

 

config :defql, connection: [
  adapter: Defql.Adapter.Ecto.Postgres,
  repo: Taped.Repo
]

Com uma conexão independente:

config :defql, connection: [
  hostname: "localhost",
  username: "username",
  password: "password",
  database: "my_db",
  pool: DBConnection.Poolboy,
  pool_size: 1
]

 

O que falta?

Claro, ainda é muito cedo, mas o suporte ao postgres funciona bem. Faltam poucas coisas:

  • Suporte ao MySQL
  • Suporte IN com array %{id: [1,2,3]}
  • Adaptador de limpeza do ECTO
  • Erros de suporte aos bancos de dados

Resumo

Usando Defql temos uma forma muito clara, simples e poderosa para interagir com um banco de dados.

Links

Espero que tenha sido útil para você. Obrigado pela leitura!

 

***

Artigo publicado originalmente em https://blog.fazibear.me/sql-queries-as-elixir-functions-5f8b1d67169e#.jt2j0ac7d