lock.ex (1573B)
1 import Kernel, except: [apply: 2] 2 3 defmodule Ecto.Query.Builder.Lock do 4 @moduledoc false 5 6 alias Ecto.Query.Builder 7 8 @doc """ 9 Escapes the lock code. 10 11 iex> escape(quote(do: "FOO"), [], __ENV__) 12 "FOO" 13 14 """ 15 @spec escape(Macro.t(), Keyword.t, Macro.Env.t) :: Macro.t() 16 def escape(lock, _vars, _env) when is_binary(lock), do: lock 17 18 def escape({:fragment, _, [_ | _]} = expr, vars, env) do 19 {expr, {params, _acc}} = Builder.escape(expr, :any, {[], %{}}, vars, env) 20 21 if params != [] do 22 Builder.error!("value interpolation is not allowed in :lock") 23 end 24 25 expr 26 end 27 28 def escape(other, _, _) do 29 Builder.error!( 30 "`#{Macro.to_string(other)}` is not a valid lock. " <> 31 "For security reasons, a lock must always be a literal string or a fragment" 32 ) 33 end 34 35 @doc """ 36 Builds a quoted expression. 37 38 The quoted expression should evaluate to a query at runtime. 39 If possible, it does all calculations at compile time to avoid 40 runtime work. 41 """ 42 @spec build(Macro.t(), Macro.t(), Macro.t(), Macro.Env.t()) :: Macro.t() 43 def build(query, binding, expr, env) do 44 {query, binding} = Builder.escape_binding(query, binding, env) 45 Builder.apply_query(query, __MODULE__, [escape(expr, binding, env)], env) 46 end 47 48 @doc """ 49 The callback applied by `build/4` to build the query. 50 """ 51 @spec apply(Ecto.Queryable.t(), term) :: Ecto.Query.t() 52 def apply(%Ecto.Query{} = query, value) do 53 %{query | lock: value} 54 end 55 56 def apply(query, value) do 57 apply(Ecto.Queryable.to_query(query), value) 58 end 59 end