Skip to content

Commit 4626d80

Browse files
committed
add named params
1 parent b8035f2 commit 4626d80

3 files changed

Lines changed: 51 additions & 2 deletions

File tree

c_src/sqlite3_nif.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,28 @@ exqlite_bind_parameter_count(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
561561
return enif_make_int(env, bind_parameter_count);
562562
}
563563

564+
///
565+
/// Get the bind parameter index
566+
///
567+
ERL_NIF_TERM
568+
exqlite_bind_parameter_index(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
569+
{
570+
statement_t* statement;
571+
if (!enif_get_resource(env, argv[0], statement_type, (void**)&statement)) {
572+
return raise_badarg(env, argv[0]);
573+
}
574+
575+
ErlNifBinary name;
576+
if (!enif_inspect_binary(env, argv[1], &name)) {
577+
return raise_badarg(env, argv[1]);
578+
}
579+
580+
statement_acquire_lock(statement);
581+
int index = sqlite3_bind_parameter_index(statement->statement, (const char*)name.data);
582+
statement_release_lock(statement);
583+
return enif_make_int(env, index);
584+
}
585+
564586
///
565587
/// Binds a text parameter
566588
///
@@ -1423,6 +1445,7 @@ static ErlNifFunc nif_funcs[] = {
14231445
{"prepare", 2, exqlite_prepare, ERL_NIF_DIRTY_JOB_IO_BOUND},
14241446
{"reset", 1, exqlite_reset, ERL_NIF_DIRTY_JOB_CPU_BOUND},
14251447
{"bind_parameter_count", 1, exqlite_bind_parameter_count},
1448+
{"bind_parameter_index", 2, exqlite_bind_parameter_index},
14261449
{"bind_text", 3, exqlite_bind_text},
14271450
{"bind_blob", 3, exqlite_bind_blob},
14281451
{"bind_integer", 3, exqlite_bind_integer},

lib/exqlite/sqlite3.ex

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,20 @@ defmodule Exqlite.Sqlite3 do
173173
iex> Sqlite3.bind(stmt, [:erlang.list_to_pid(~c"<0.0.0>")])
174174
** (ArgumentError) unsupported type: #PID<0.0.0>
175175
176+
iex> {:ok, conn} = Sqlite3.open(":memory:", [:readonly])
177+
iex> {:ok, stmt} = Sqlite3.prepare(conn, "SELECT :a, :b")
178+
iex> Sqlite3.bind(stmt, %{":a" => 42, ":b" => "Alice"})
179+
iex> Sqlite3.step(conn, stmt)
180+
{:row, [42, "Alice"]}
181+
176182
"""
177-
@spec bind(statement, [bind_value] | nil) :: :ok
183+
@spec bind(
184+
statement,
185+
[bind_value] | %{optional(String.t()) => bind_value} | nil
186+
) :: :ok
178187
def bind(stmt, nil), do: bind(stmt, [])
179188

180-
def bind(stmt, args) do
189+
def bind(stmt, args) when is_list(args) do
181190
params_count = bind_parameter_count(stmt)
182191
args_count = length(args)
183192

@@ -188,6 +197,20 @@ defmodule Exqlite.Sqlite3 do
188197
end
189198
end
190199

200+
def bind(stmt, args) when is_map(args) do
201+
args =
202+
Enum.map(args, fn {name, value} ->
203+
case Sqlite3NIF.bind_parameter_index(stmt, name) do
204+
-1 -> raise ArgumentError, "unknown parameter: #{inspect(name)}"
205+
idx -> {value, idx}
206+
end
207+
end)
208+
|> Enum.sort_by(fn {_param, idx} -> idx end, :asc)
209+
|> Enum.map(fn {param, _idx} -> param end)
210+
211+
bind(stmt, args)
212+
end
213+
191214
# credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity
192215
defp bind_all([param | params], stmt, idx) do
193216
case convert(param) do

lib/exqlite/sqlite3_nif.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ defmodule Exqlite.Sqlite3NIF do
7272
@spec bind_parameter_count(statement) :: integer
7373
def bind_parameter_count(_stmt), do: :erlang.nif_error(:not_loaded)
7474

75+
@spec bind_parameter_index(statement, String.t()) :: integer
76+
def bind_parameter_index(_stmt, _name), do: :erlang.nif_error(:not_loaded)
77+
7578
@spec bind_text(statement, non_neg_integer, String.t()) :: integer()
7679
def bind_text(_stmt, _index, _text), do: :erlang.nif_error(:not_loaded)
7780

0 commit comments

Comments
 (0)