# -----------------------------------Goal--------------------------------------
# Compare the implementation of parsing Ecto.Query objects into SQL queries by
# the different database adapters

# -------------------------------Description-----------------------------------
# Repo.to_sql/2 is an important step of a database query.
# This benchmark tracks performance of parsing Ecto.Query structures into
# "raw" SQL query strings.
# Different Ecto.Query objects has multiple combinations and some different attributes
# depending on the query type. In this tests we benchmark against different
# query types and complexity.

# ----------------------------Factors(don't change)---------------------------
# Different adapters supported by Ecto, each one has its own implementation that
# is tested against different query inputs

# ----------------------------Parameters(change)-------------------------------
# Different query objects (select, delete, update) to be translated into pure SQL
# strings.

Code.require_file("../../support/setup.exs", __DIR__)

import Ecto.Query

alias Ecto.Bench.{User, Game}

inputs = %{
  "Ordinary Select All" => {:all, from(User)},
  "Ordinary Delete All" => {:delete_all, from(User)},
  "Ordinary Update All" => {:update_all, from(User, update: [set: [name: "Thor"]])},
  "Ordinary Where" => {:all, from(User, where: [name: "Thanos", email: "blah@blah"])},
  "Fetch First Registry" => {:all, first(User)},
  "Fetch Last Registry" => {:all, last(User)},
  "Ordinary Order By" => {:all, order_by(User, desc: :name)},
  "Complex Query 2 Joins" =>
    {:all,
     from(User, where: [name: "Thanos"])
     |> join(:left, [u], ux in User, on: u.id == ux.id)
     |> join(:right, [j], uj in User, on: j.id == 1 and j.email == "email@email")
     |> select([u, ux], {u.name, ux.email})},
  "Complex Query 4 Joins" =>
    {:all,
     from(User)
     |> join(:left, [u], g in Game, on: g.name == u.name)
     |> join(:right, [g], u in User, on: g.id == 1 and u.email == "email@email")
     |> join(:inner, [u], g in fragment("SELECT * from games where game.id = ?", u.id))
     |> join(:left, [g], u in fragment("SELECT * from users = ?", g.id))
     |> select([u, g], {u.name, g.price})}
}

jobs = %{
  "SQLite3 Query Builder" => fn {type, query} ->
    Ecto.Bench.SQLite3Repo.to_sql(type, query)
  end,
  "Pg Query Builder" => fn {type, query} -> Ecto.Bench.PgRepo.to_sql(type, query) end,
  "MyXQL Query Builder" => fn {type, query} ->
    Ecto.Bench.MyXQLRepo.to_sql(type, query)
  end
}

path = System.get_env("BENCHMARKS_OUTPUT_PATH") || "bench/results"

Benchee.run(
  jobs,
  inputs: inputs,
  formatters: [
    Benchee.Formatters.Console,
    {Benchee.Formatters.Markdown, file: Path.join(path, "to_sql.md")}
  ]
)
