Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- defmodule MarketData.Query do
- @moduledoc """
- Builds and executes a `MarketData.Repo` query from a `Map` of params..
- """
- alias MarketData.Repo
- import Ecto.Query
- @namespace "Elixir.MarketData.Schemas"
- @doc """
- """
- def run(schema, params), do: schema |> schema(params) |> build() |> execute()
- defp schema(schema, params) do
- try do
- {:ok, query(schema), params}
- rescue
- _ -> {:error, "Invalid schema", nil}
- end
- end
- defp query(schema), do: from(:"#{@namespace}.#{schema}", order_by: [asc: :ticker])
- defp build({:error, reason, _params}), do: {:error, reason, nil}
- defp build({:ok, query, params}) when params == %{}, do: {:ok, query, params}
- defp build({:ok, query, %{"limit" => limit} = params}),
- do: build({:ok, query_limit(query, limit), Map.delete(params, "limit")})
- defp build({:ok, query, %{"order_by.asc" => order_by} = params}),
- do: build({:ok, query_order_by(query, order_by, :asc), Map.delete(params, "order_by.asc")})
- defp build({:ok, query, %{"order_by.desc" => order_by} = params}),
- do: build({:ok, query_order_by(query, order_by, :desc), Map.delete(params, "order_by.desc")})
- defp build({:ok, query, %{"select" => selects} = params}),
- do: build({:ok, query_select(query, selects), Map.delete(params, "select")})
- defp build({:ok, query, wheres}), do: {:ok, build_where(query, Map.to_list(wheres)), %{}}
- defp query_limit(query, limit), do: limit(query, ^limit)
- defp query_order_by(query, order_by, :asc) do
- order_by = String.to_atom(order_by)
- query |> exclude(:order_by) |> from(order_by: [asc: ^order_by])
- end
- defp query_order_by(query, order_by, :desc) do
- order_by = String.to_atom(order_by)
- query |> exclude(:order_by) |> from(order_by: [desc: ^order_by])
- end
- defp query_select(query, selects) do
- selects = selects |> String.split(",") |> Enum.map(&String.to_atom/1)
- from(query, select: ^selects)
- end
- defp build_where(query, wheres) when wheres == [], do: query
- defp build_where(query, [{keys, value} | wheres]) do
- {key, operator} = parse_key_operator(keys)
- query |> where_clause(key, value, operator) |> build_where(wheres)
- end
- defp where_clause(query, k, v, "not"), do: from(q in query, where: field(q, ^k) != ^v)
- defp where_clause(query, k, v, "lt"), do: from(q in query, where: field(q, ^k) < ^v)
- defp where_clause(query, k, v, "lte"), do: from(q in query, where: field(q, ^k) <= ^v)
- defp where_clause(query, k, v, "gt"), do: from(q in query, where: field(q, ^k) > ^v)
- defp where_clause(query, k, v, "gte"), do: from(q in query, where: field(q, ^k) >= ^v)
- defp where_clause(query, k, v, _), do: from(q in query, where: field(q, ^k) == ^v)
- defp parse_key_operator(keys) do
- [key | operator] = String.split(keys, ".")
- {String.to_atom(key), Enum.at(operator, 0)}
- end
- defp execute({:error, reason, _params}), do: {:error, reason}
- defp execute({:ok, query, _params}) do
- try do
- {:ok, Repo.all(query)}
- rescue
- _ -> {:error, "Invalid query"}
- end
- end
- end
Add Comment
Please, Sign In to add comment