Skip to content

Commit

Permalink
Ecto driver support
Browse files Browse the repository at this point in the history
  • Loading branch information
lpil committed Aug 3, 2018
1 parent d8e2f7a commit e692828
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 55 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

Yesql is an Elixir library for _using_ SQL.


## Rationale

You're writing Elixir You need to write some SQL.
Expand Down
19 changes: 19 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use Mix.Config

case Mix.env() do
:test ->
config :yesql, ecto_repos: [YesqlTest.Repo]

config :yesql, YesqlTest.Repo, adapter: Ecto.Adapters.Postgres

config :yesql, YesqlTest.Repo,
username: "postgres",
password: "postgres",
database: "yesql_test",
hostname: "localhost"

config :logger, level: :info

_ ->
:ok
end
23 changes: 21 additions & 2 deletions lib/yesql.ex
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
defmodule Yesql do
@moduledoc """
Documentation for Yesql.
defmodule Query do
use Yesql, driver: Postgrex, conn: MyApp.ConnectionPool
Yesql.defquery("some/where/select_users_by_country.sql")
end
Query.users_by_country(country_code: "gbr")
# => {:ok, [%{name: "Louis", country_code: "gbr"}]}
## Supported drivers
- `Postgrex`
- `Ecto`, for which `conn` is an Ecto repo.
"""

alias __MODULE__.{NoDriver, UnknownDriver, MissingParam}

@supported_drivers [Postgrex]
@supported_drivers [Postgrex, Ecto]

defmacro __using__(opts) do
quote bind_quoted: binding() do
Expand Down Expand Up @@ -90,6 +103,12 @@ defmodule Yesql do
end
end

if Code.ensure_compiled?(Ecto) do
defp exec_for_driver(repo, Ecto, sql, param_list) do
Ecto.Adapters.SQL.query(repo, sql, param_list)
end
end

defp exec_for_driver(_, driver, _, _) do
raise UnknownDriver.exception(driver)
end
Expand Down
2 changes: 2 additions & 0 deletions lib/yesql/exceptions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule Yesql.MissingParam do
msg = """
Required parameter `:#{param}` not given
"""

%__MODULE__{message: msg}
end
end
Expand All @@ -18,6 +19,7 @@ defmodule Yesql.UnknownDriver do
msg = """
Unknown database driver #{driver}
"""

%__MODULE__{message: msg}
end
end
Expand Down
22 changes: 19 additions & 3 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ defmodule Yesql.Mixfile do
def project do
[
app: :yesql,
version: "0.2.0",
version: "0.3.0",
elixir: "~> 1.5",
start_permanent: Mix.env() == :prod,
elixirc_paths: elixirc_paths(Mix.env()),
deps: deps(),
name: "Yesql",
description: "Using plain old SQL to query databases",
Expand All @@ -20,17 +21,32 @@ defmodule Yesql.Mixfile do
end

def application do
[extra_applications: []]
case Mix.env() do
:test ->
[
mod: {YesqlTest.Application, []},
extra_applications: [:logger, :runtime_tools]
]

_ ->
[extra_applications: []]
end
end

defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]

defp deps do
[
# Postgresql driver
{:postgrex, "~> 0.12", optional: true},
# Database abstraction
{:ecto, "~> 2.0", optional: true},

# Automatic testing tool
{:mix_test_watch, ">= 0.0.0", only: :dev},
# Documentation generator
{:ex_doc, "~> 0.18.0", only: :dev}
{:ex_doc, "~> 0.18", only: :dev}
]
end
end
22 changes: 14 additions & 8 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
%{
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [], [], "hexpm"},
"db_connection": {:hex, :db_connection, "1.1.2", "2865c2a4bae0714e2213a0ce60a1b12d76a6efba0c51fbda59c9ab8d1accc7a8", [], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.4.1", "ad9e501edf7322f122f7fc151cce7c2a0c9ada96f2b0155b8a09a795c2029770", [], [], "hexpm"},
"earmark": {:hex, :earmark, "1.2.4", "99b637c62a4d65a20a9fb674b8cffb8baa771c04605a80c911c4418c69b75439", [:mix], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.18.1", "37c69d2ef62f24928c1f4fdc7c724ea04aecfdf500c4329185f8e3649c915baf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
"fs": {:hex, :fs, "0.9.2", "ed17036c26c3f70ac49781ed9220a50c36775c6ca2cf8182d123b6566e49ec59", [], [], "hexpm"},
"mix_test_watch": {:hex, :mix_test_watch, "0.5.0", "2c322d119a4795c3431380fca2bca5afa4dc07324bd3c0b9f6b2efbdd99f5ed3", [], [{:fs, "~> 0.9.1", [hex: :fs, repo: "hexpm", optional: false]}], "hexpm"},
"postgrex": {:hex, :postgrex, "0.13.3", "c277cfb2a9c5034d445a722494c13359e361d344ef6f25d604c2353185682bfc", [], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.10", "e7366dc82f48f8dd78fcbf3ab50985ceeb11cb3dc93435147c6e13f2cda0992e", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.19.0", "e22b6434373b4870ea77b24df069dbac7002c1f483615e9ebfc0c37497e1c75c", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"file_system": {:hex, :file_system, "0.2.6", "fd4dc3af89b9ab1dc8ccbcc214a0e60c41f34be251d9307920748a14bf41f1d3", [:mix], [], "hexpm"},
"fs": {:hex, :fs, "0.9.2", "ed17036c26c3f70ac49781ed9220a50c36775c6ca2cf8182d123b6566e49ec59", [:rebar], [], "hexpm"},
"makeup": {:hex, :makeup, "0.5.1", "966c5c2296da272d42f1de178c1d135e432662eca795d6dc12e5e8787514edf7", [:mix], [{:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"mix_test_watch": {:hex, :mix_test_watch, "0.8.0", "acf97da2abc66532e7dc1aa66a5d6c9fc4442d7992d5d7eb4faeaeb964c2580e", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm"},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.13.5", "3d931aba29363e1443da167a4b12f06dcd171103c424de15e5f3fc2ba3e6d9c5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"},
}
13 changes: 13 additions & 0 deletions test/support/support.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule YesqlTest.Application do
use Application

def start(_type, _args) do
Application.ensure_all_started(:ecto)
Application.ensure_all_started(:postgrex)
Supervisor.start_link([YesqlTest.Repo], strategy: :one_for_one, name: Blondie.Supervisor)
end
end

defmodule YesqlTest.Repo do
use Ecto.Repo, otp_app: :yesql
end
74 changes: 33 additions & 41 deletions test/yesql_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,25 @@ defmodule YesqlTest do
doctest Yesql
import TestHelper

defmodule Query do
use Yesql, driver: Postgrex

Yesql.defquery("test/sql/select_older_cats.sql")
Yesql.defquery("test/sql/insert_cat.sql")
end

defmodule QueryConn do
use Yesql, driver: Postgrex, conn: YesqlTest.Postgrex
Yesql.defquery("test/sql/select_older_cats.sql")
Yesql.defquery("test/sql/insert_cat.sql")
end

defmodule QueryEcto do
use Yesql, driver: Ecto, conn: YesqlTest.Repo
Yesql.defquery("test/sql/select_older_cats.sql")
Yesql.defquery("test/sql/insert_cat.sql")
end

setup_all [:new_postgrex_connection, :create_cats_postgres_table]

describe "parse/1" do
Expand Down Expand Up @@ -112,31 +131,28 @@ defmodule YesqlTest do
describe "defquery/2" do
setup [:truncate_postgres_cats]

defmodule Query do
use Yesql, driver: Postgrex

Yesql.defquery("test/sql/select_older_cats.sql")
Yesql.defquery("test/sql/insert_cat.sql")
end

test "query function is created" do
refute function_exported?(Query, :select_older_cats, 1)
assert function_exported?(Query, :select_older_cats, 2)

# The /1 arity function is called because conn isn't needed.
assert function_exported?(QueryConn, :select_older_cats, 1)
assert function_exported?(QueryConn, :select_older_cats, 2)
end

test "throws if map argument missing" do
assert_raise Yesql.MissingParam, "Required parameter `:age` not given\n", fn ->
Query.select_older_cats(nil, %{})
QueryConn.select_older_cats(%{})
end
end

test "throws if keyword argument missing" do
assert_raise Yesql.MissingParam, "Required parameter `:age` not given\n", fn ->
Query.select_older_cats(nil, [])
QueryConn.select_older_cats(nil, [])
end
end

test "query exec", %{postgrex: conn} do
test "query exec with explicit conn", %{postgrex: conn} do
assert Query.select_older_cats(conn, age: 5) == {:ok, []}
assert Query.insert_cat(conn, age: 50) == {:ok, []}
assert Query.select_older_cats(conn, age: 5) == {:ok, [%{age: 50, name: nil}]}
Expand All @@ -150,38 +166,8 @@ defmodule YesqlTest do
assert Query.select_older_cats(conn, age: 5) ==
{:ok, [%{age: 10, name: nil}, %{age: 50, name: nil}]}
end
end

# TODO
# describe "defquery/2 with driver passed"

describe "defquery/2 with conn" do
setup [:truncate_postgres_cats]

defmodule QueryConn do
use Yesql, driver: Postgrex, conn: YesqlTest.Postgrex
Yesql.defquery("test/sql/select_older_cats.sql")
Yesql.defquery("test/sql/insert_cat.sql")
end

test "query function is created" do
assert function_exported?(QueryConn, :select_older_cats, 1)
assert function_exported?(QueryConn, :select_older_cats, 2)
end

test "throws if map argument missing" do
assert_raise Yesql.MissingParam, "Required parameter `:age` not given\n", fn ->
QueryConn.select_older_cats(%{})
end
end

test "throws if keyword argument missing" do
assert_raise Yesql.MissingParam, "Required parameter `:age` not given\n", fn ->
QueryConn.select_older_cats([])
end
end

test "query exec" do
test "query exec with implicit conn" do
assert QueryConn.select_older_cats(age: 5) == {:ok, []}
assert QueryConn.insert_cat(age: 50) == {:ok, []}
assert QueryConn.select_older_cats(age: 5) == {:ok, [%{age: 50, name: nil}]}
Expand All @@ -195,5 +181,11 @@ defmodule YesqlTest do
assert QueryConn.select_older_cats(age: 5) ==
{:ok, [%{age: 10, name: nil}, %{age: 50, name: nil}]}
end

test "query exec with Ecto driver" do
assert QueryEcto.select_older_cats(age: 5) == {:ok, []}
assert QueryEcto.insert_cat(age: 50) == {:ok, []}
assert QueryEcto.select_older_cats(age: 5) == {:ok, [%{age: 50, name: nil}]}
end
end
end

0 comments on commit e692828

Please sign in to comment.