zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

distinct.ex (2676B)


      1 import Kernel, except: [apply: 2]
      2 
      3 defmodule Ecto.Query.Builder.Distinct do
      4   @moduledoc false
      5 
      6   alias Ecto.Query.Builder
      7 
      8   @doc """
      9   Escapes a list of quoted expressions.
     10 
     11       iex> escape(quote do true end, {[], %{}}, [], __ENV__)
     12       {true, {[], %{}}}
     13 
     14       iex> escape(quote do [x.x, 13] end, {[], %{}}, [x: 0], __ENV__)
     15       {[asc: {:{}, [], [{:{}, [], [:., [], [{:{}, [], [:&, [], [0]]}, :x]]}, [], []]},
     16         asc: 13],
     17        {[], %{}}}
     18 
     19   """
     20   @spec escape(Macro.t, {list, term}, Keyword.t, Macro.Env.t) :: {Macro.t, {list, term}}
     21   def escape(expr, params_acc, _vars, _env) when is_boolean(expr) do
     22     {expr, params_acc}
     23   end
     24 
     25   def escape(expr, params_acc, vars, env) do
     26     Builder.OrderBy.escape(:distinct, expr, params_acc, vars, env)
     27   end
     28 
     29   @doc """
     30   Called at runtime to verify distinct.
     31   """
     32   def distinct!(query, distinct, file, line) when is_boolean(distinct) do
     33     apply(query, %Ecto.Query.QueryExpr{expr: distinct, params: [], line: line, file: file})
     34   end
     35   def distinct!(query, distinct, file, line) do
     36     {expr, params} = Builder.OrderBy.order_by_or_distinct!(:distinct, query, distinct, [])
     37     expr = %Ecto.Query.QueryExpr{expr: expr, params: Enum.reverse(params), line: line, file: file}
     38     apply(query, expr)
     39   end
     40 
     41   @doc """
     42   Builds a quoted expression.
     43 
     44   The quoted expression should evaluate to a query at runtime.
     45   If possible, it does all calculations at compile time to avoid
     46   runtime work.
     47   """
     48   @spec build(Macro.t, [Macro.t], Macro.t, Macro.Env.t) :: Macro.t
     49   def build(query, _binding, {:^, _, [var]}, env) do
     50     quote do
     51       Ecto.Query.Builder.Distinct.distinct!(unquote(query), unquote(var), unquote(env.file), unquote(env.line))
     52     end
     53   end
     54 
     55   def build(query, binding, expr, env) do
     56     {query, binding} = Builder.escape_binding(query, binding, env)
     57     {expr, {params, _acc}} = escape(expr, {[], %{}}, binding, env)
     58     params = Builder.escape_params(params)
     59 
     60     distinct = quote do: %Ecto.Query.QueryExpr{
     61                            expr: unquote(expr),
     62                            params: unquote(params),
     63                            file: unquote(env.file),
     64                            line: unquote(env.line)}
     65     Builder.apply_query(query, __MODULE__, [distinct], env)
     66   end
     67 
     68   @doc """
     69   The callback applied by `build/4` to build the query.
     70   """
     71   @spec apply(Ecto.Queryable.t, term) :: Ecto.Query.t
     72   def apply(%Ecto.Query{distinct: nil} = query, expr) do
     73     %{query | distinct: expr}
     74   end
     75   def apply(%Ecto.Query{}, _expr) do
     76     Builder.error! "only one distinct expression is allowed in query"
     77   end
     78   def apply(query, expr) do
     79     apply(Ecto.Queryable.to_query(query), expr)
     80   end
     81 end