Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add duckdb runner #37

Merged
merged 6 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ jobs:
- uses: erlef/setup-beam@v1
name: "Setup Elixir"
with:
otp-version: "26.1.2"
elixir-version: "1.15.7"
otp-version: "27.1.2"
elixir-version: "1.17.3"
- name: "Get dependencies"
run: mix do local.rebar --force, local.hex --force, deps.get
- name: "Compile dependencies"
Expand Down
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
erlang 26.1.2
elixir 1.15.7-otp-26
erlang 27.1.2
elixir 1.17.3-otp-27
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## v1.1.3

### Enhancements

* Updated dependencies.
* Added Duckdbex query runner.

## v1.1.2

### Enhancements
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ SQL DSLs. This library aims to:
- Work out-of-the-box with PostgreSQL using
[Ecto](https://github.com/elixir-ecto/ecto_sql) or
[Postgrex](https://github.com/elixir-ecto/postgrex).
- Work out-of-the-box woth DuckDB using
[Duckdbex](https://github.com/AlexR2D2/duckdbex).

If you want to know more about AyeSQL:

Expand Down Expand Up @@ -403,6 +405,7 @@ their dependencies as well:

- Add `:ecto_sql` for `AyeSQL.Runner.Ecto` (default runner).
- Add `:postgrex` for `AyeSQL.Runner.Postgrex`.
- Add `duckdbex` for `AyeSQL.Runner.Duckdbex`.
- Add `:ecto_sql` and `:postgrex` for running queries using `Ecto` in a
`PostgreSQL` database.

Expand Down
10 changes: 5 additions & 5 deletions lib/ayesql/ast.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ defmodule AyeSQL.AST do
end

defp do_expand(module, key) when is_atom(key) do
if is_query?(module, key) do
if query?(module, key) do
expand_function_fn(module, key)
else
expand_param_fn(module, key)
Expand Down Expand Up @@ -174,7 +174,7 @@ defmodule AyeSQL.AST do
defp expand_local_function(module, local, context, params)

defp expand_local_function(module, value, %Context{} = context, params) do
if is_query?(module, value) do
if query?(module, value) do
expand_remote_function({module, value}, context, params)
else
Context.put_variable(context, value)
Expand Down Expand Up @@ -204,10 +204,10 @@ defmodule AyeSQL.AST do
end

# Whether an atom is a query o not.
@spec is_query?(module(), Core.parameter_name()) :: boolean()
defp is_query?(nil, _key), do: false
@spec query?(module(), Core.parameter_name()) :: boolean()
defp query?(nil, _key), do: false

defp is_query?(module, key) do
defp query?(module, key) do
:functions
|> module.module_info()
|> Enum.member?({key, 2})
Expand Down
79 changes: 79 additions & 0 deletions lib/ayesql/runner/duckdb.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
if Code.ensure_loaded?(Duckdbex) do
defmodule AyeSQL.DuckdbexBehaviour do
@moduledoc false

defmacro __using__(_) do
quote do
@behaviour AyeSQL.DuckdbexBehaviour

@impl AyeSQL.DuckdbexBehaviour
def query(conn, stmt, args) do
with {:ok, res} <- Duckdbex.query(conn, stmt, args) do
columns = Duckdbex.columns(res)
rows = Duckdbex.fetch_all(res)
result = %{rows: rows, columns: columns}

{:ok, result}
end
end

defoverridable query: 3
end
end

@callback query(
Duckdbex.connection(),
iodata(),
list()
) ::
{:ok, %{:rows => [list()], :columns => list()}}
| {:error, Duckdbex.reason()}
end

defmodule AyeSQL.Duckdbex do
@moduledoc false
use AyeSQL.DuckdbexBehaviour
end

defmodule AyeSQL.Runner.Duckdbex do
@moduledoc """
This module defines `Duckdbex` default adapter.

Can be used as follows:

```elixir
defmodule MyQueries do
use AyeSQL,
runner: AyeSQL.Runner.Duckdbex

defqueries("query/my_queries.sql")
end
```

And given a `connection` to the database, then it can be used with the
query options:

```elixir
iex> MyQueries.get_user([id: id], conn: connection)
{:ok, ...}
```
"""
use AyeSQL.Runner

alias AyeSQL.Query
alias AyeSQL.Runner

@impl true
def run(%Query{statement: stmt, arguments: args}, options) do
module = Application.get_env(:ayesql, :duckdbex_module, AyeSQL.Duckdbex)

conn =
options[:conn] ||
raise ArgumentError, message: "Connection `:conn` cannot be `nil`"

with {:ok, result} <- module.query(conn, stmt, args) do
{:ok, Runner.handle_result(result, options)}
end
end
end
end
4 changes: 3 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule AyeSQL.MixProject do
use Mix.Project

@version "1.1.2"
@version "1.1.3"
@name "AyeSQL"
@description "Library for using raw SQL"
@app :ayesql
Expand All @@ -16,6 +16,7 @@ defmodule AyeSQL.MixProject do
elixirc_paths: elixirc_paths(Mix.env()),
build_embedded: Mix.env() == :prod,
start_permanent: Mix.env() == :prod,
compilers: [:leex, :yecc | Mix.compilers()],
dialyzer: dialyzer(),
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [
Expand Down Expand Up @@ -47,6 +48,7 @@ defmodule AyeSQL.MixProject do
{:ecto, "~> 3.11", optional: true},
{:ecto_sql, "~> 3.11", optional: true},
{:postgrex, ">= 0.0.0", optional: true},
{:duckdbex, "~> 0.3", optional: true},
{:mox, "~> 1.1", only: :test, runtime: false},
{:ex_doc, "~> 0.30", only: :dev, runtime: false},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
Expand Down
Loading
Loading