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

allow_to_return_raw_or_keyword_list #32

Merged
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
32 changes: 32 additions & 0 deletions lib/ayesql.ex
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,38 @@ defmodule AyeSQL do
]
}
```
AyeSQL also allows you to choose the type of returned data structures.
Instead of the default map you can also pass an `into` option to your query
possible values are:
- an empty map: `Map.new()` or `%{}`
- an empty list: Keyword.new()` or `[]`
- a struct
- `:raw` - will return unmodified Postgrex result

```elixir
iex> Queries.get_avg_clicks(params, into: [])
{:ok,
[
[day: ..., count: ...],
[day: ..., count: ...],
[day: ..., count: ...],
...
]
}
```

```elixir
iex> defmodule AvgClicks do defstruct [:day, :count] end
iex> Queries.get_avg_clicks(params, into: AvgClicks)
{:ok,
[
%AvgClicks{day: ..., count: ...},
%AvgClicks{day: ..., count: ...},
%AvgClicks{day: ..., count: ...},
...
]
}
```
"""
alias AyeSQL.Compiler
alias AyeSQL.Query
Expand Down
23 changes: 17 additions & 6 deletions lib/ayesql/runner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,33 @@ defmodule AyeSQL.Runner do

# Handles the result.
@doc false
@spec handle_result(map()) :: [map() | struct()]
@spec handle_result(map(), keyword()) :: [map() | struct()]
@spec handle_result(map()) :: [map() | struct() | keyword()]
@spec handle_result(map(), keyword()) :: [map() | struct() | keyword()]
def handle_result(result, options \\ [])

def handle_result(data, options) when is_list(options) do
handle_result(data, Map.new(options))
end

def handle_result(raw_data, %{into: :raw}) do
raw_data
end

def handle_result(%{columns: nil}, _options) do
[]
end

def handle_result(%{columns: columns, rows: rows}, options) do
struct = options[:into]
columns = Enum.map(columns, &String.to_atom/1)
atom_columns = Stream.map(columns, &String.to_atom/1)

rows
|> Stream.map(&Stream.zip(columns, &1))
|> Stream.map(&Stream.zip(atom_columns, &1))
|> Enum.map(fn row ->
if struct, do: struct(struct, row), else: Map.new(row)
case options[:into] do
struct when is_struct(struct) -> struct(struct, row)
[] -> Enum.into(row, [])
_ -> Enum.into(row, %{})
end
end)
end
end
54 changes: 52 additions & 2 deletions test/ayesql/runner_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ defmodule AyeSQL.RunnerTest do

alias AyeSQL.Runner

defmodule User do
defstruct [:username, :email]
end

describe "handle_result/1" do
test "when columns are nil, returns empty list" do
data = %{columns: nil}

assert [] = Runner.handle_result(data)
end

test "when rows are not empty, returns a list of rows with columns" do
test "when rows are not empty, returns a list of map rows by default" do
data = %{
columns: ["username", "email"],
rows: [
Expand All @@ -24,7 +28,53 @@ defmodule AyeSQL.RunnerTest do
%{username: "alice", email: "[email protected]"}
]

assert ^expected = Runner.handle_result(data)
assert ^expected = Runner.handle_result(data, into: %{})
end

test "when rows are not empty, returns a list of keyword rows" do
data = %{
columns: ["username", "email"],
rows: [
["bob", "[email protected]"],
["alice", "[email protected]"]
]
}

expected = [
[username: "bob", email: "[email protected]"],
[username: "alice", email: "[email protected]"]
]

assert expected == Runner.handle_result(data, into: [])
end

test "when rows are not empty, returns a list of structs rows" do
data = %{
columns: ["username", "email"],
rows: [
["bob", "[email protected]"],
["alice", "[email protected]"]
]
}

expected = [
%User{username: "bob", email: "[email protected]"},
%User{username: "alice", email: "[email protected]"}
]

assert expected == Runner.handle_result(data, into: %User{})
end

test "when rows are not empty, returns a raw result with columns and rows" do
data = %{
columns: ["username", "email"],
rows: [
["bob", "[email protected]"],
["alice", "[email protected]"]
]
}

assert data == Runner.handle_result(data, into: :raw)
end
end
end
Loading