# OnePlusNDetector
This library helps detect 1+n SQL queries in your application. This is a common problem when working with ORMs like Ecto.
## What is the 1+n problem?
When you have a parent-child relationship like a `has_many`, `has_one` or `belongs_to` you might load your parent records with one query and then **for each record**, trigger another SQL statment to load the related children.
Let's say you have the following Ecto schemas
```elixir
defmodule User do
use Ecto.Schema
schema "users" do
has_one :details, Details
end
end
defmodule Details do
use Ecto.Schema
schema "users_details" do
belongs_to :user, User
end
end
```
You could load all the users with its respective details the following way (**wrong way**)
```elixir
User
|> Repo.all
|> Enum.map(& %{&1 | details: Repo.get(&1.details_id)})
```
You can query all users and then for each record that it's returned you can query it's user details. This implementation falls into the 1+N problem because the first query returns N records and for each record you trigger an additional SQL query, having in total 1+N SQL queries issued to your DB.
The number of queries can be reduced to two by just using a [preload](https://hexdocs.pm/ecto/Ecto.Query.html#preload/3) statement.
```elixir
User
|> preload(:details)
|> Repo.all
```
This library helps you detect these cases by triggering a warning in your query log.
## Usage
Add an extra logger to Ecto repo.
```elixir
config :my_app, MyApp.Repo, loggers: [
{OnePlusNDetector, :analyze, []},
{Ecto.LogEntry, :log, []}
]
```
And then configure this library's GenServer in your application
```elixir
def start(_type, _args) do
import Supervisor.Spec, warn: false
children = [
supervisor(MyApp.Endpoint, []),
supervisor(MyApp.Repo, []),
worker(OnePlusNDetector.Detector, []),
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
```
## Documentation
Documentation can be found at [https://hexdocs.pm/one_plus_n_detector](https://hexdocs.pm/one_plus_n_detector).
## Installation
**This library should be used only on development**
```elixir
def deps do
[
{:one_plus_n_detector, "~> 0.1.0", only: :dev}
]
end
```
Remember to **not add** `:one_plus_n_detector` to your applications list!
## License
one_plus_n_detector is licensed under the MIT license.
See [LICENSE](./LICENSE) for the full license text.