Packages
ecto_raw_sql_helpers
0.1.2
EctoRawSQLHelpers aims to improve raw SQL support in Ecto by providing helper functions, such as: - Named parameters support - Response parsing (getting query results as lists of maps, number of rows affected on statements, etc) - Stream support for dealing with big result sets
Current section
Files
Jump to
Current section
Files
lib/internals/named_parameters_translator.ex
defmodule EctoRawSQLHelpers.NamedParameterTranslator do
@split_regex ~r/(?<!:)(?<parameter>:\w+)/
def translate_named_parameters(adapter, sql, params, options) do
@split_regex
|> Regex.split(sql, trim: true, include_captures: true, on: [:parameter])
|> Enum.map(&is_parameter/1)
|> Enum.reduce({_sql = "", _parameter_list = []}, &translate_query_and_params_to_provider_placeholder(&1, &2, params, adapter, options))
end
defp is_parameter(string) do
%{is_parameter: Regex.match?(@split_regex, string), sql: string}
end
defp translate_query_and_params_to_provider_placeholder(%{is_parameter: false, sql: sql_chunk}, {sql, param_list}, _parameters_map, _adapter, _options) do
{sql <> sql_chunk, param_list}
end
defp translate_query_and_params_to_provider_placeholder(
%{is_parameter: true, sql: named_parameter},
{sql, param_list},
parameters_map,
adapter,
options
) do
parameter = find_parameter_or_raise!(named_parameter, parameters_map, options)
{
sql <> adapter_placeholder(adapter, param_list, parameter),
param_list ++ parameter_to_list(parameter)
}
end
defp adapter_placeholder(Ecto.Adapters.Postgres, param_list, {:in, values}) do
previous_parameters = Enum.count(param_list) + 1
in_clause_parameters = Enum.count(values)
previous_parameters..in_clause_parameters
|> Enum.map(fn index -> "$" <> to_string(index) end)
|> Enum.join(",")
end
defp adapter_placeholder(Ecto.Adapters.Postgres, param_list, _parameter) do
"$" <> to_string(Enum.count(param_list) + 1)
end
defp adapter_placeholder(Ecto.Adapters.MyXQL, _param_list, {:in, values}) do
in_clause_parameters = Enum.count(values)
1..in_clause_parameters
|> Enum.map(fn _ -> "?" end)
|> Enum.join(",")
end
defp adapter_placeholder(Ecto.Adapters.MyXQL, _param_list, _parameter) do
"?"
end
defmodule SQLParameterNotSetException do
defexception [:parameter_name]
def message(exception) do
"Parameter #{exception.parameter_name} not found on bind values"
end
end
defp find_parameter_or_raise!(":" <> named_parameter, parameters_map, _options) do
get_parameter(parameters_map, named_parameter)
|> case do
:error -> raise SQLParameterNotSetException, parameter_name: named_parameter
value -> value
end
end
defp get_parameter(parameters_map, named_parameter) do
Map.get(parameters_map, named_parameter)
|| Map.get(parameters_map, String.to_atom(named_parameter))
|| :error
end
defp parameter_to_list({:in, values}) do
values
end
defp parameter_to_list(values) do
[values]
end
end