Skip to content

Commit 3d69b84

Browse files
authored
fix: Implement and support cell-wise placeholder support (#154)
I went ahead and added in support for cell-wise support for bounded values. This has been on the todo list for a while. fixes: #152
1 parent b39bcba commit 3d69b84

File tree

2 files changed

+25
-20
lines changed

2 files changed

+25
-20
lines changed

lib/ecto/adapters/sqlite3/connection.ex

+18-13
Original file line numberDiff line numberDiff line change
@@ -267,17 +267,21 @@ defmodule Ecto.Adapters.SQLite3.Connection do
267267
]
268268
end
269269

270-
def insert(prefix, table, header, rows, on_conflict, returning, _placeholders) do
271-
fields = quote_names(header)
270+
def insert(prefix, table, header, rows, on_conflict, returning, placeholders) do
271+
counter_offset = length(placeholders) + 1
272+
273+
values =
274+
if header == [] do
275+
[" VALUES " | Enum.map_intersperse(rows, ?,, fn _ -> "(DEFAULT)" end)]
276+
else
277+
[" (", quote_names(header), ") " | insert_all(rows, counter_offset)]
278+
end
272279

273280
[
274281
"INSERT INTO ",
275282
quote_table(prefix, table),
276283
insert_as(on_conflict),
277-
" (",
278-
fields,
279-
") ",
280-
insert_all(rows, on_conflict),
284+
values,
281285
on_conflict(on_conflict, header),
282286
returning(returning)
283287
]
@@ -766,13 +770,13 @@ defmodule Ecto.Adapters.SQLite3.Connection do
766770
]
767771
end
768772

769-
def insert_all(rows, on_conflict), do: insert_all(rows, on_conflict, 1)
773+
def insert_all(rows), do: insert_all(rows, 1)
770774

771-
def insert_all(%Ecto.Query{} = query, _on_conflict, _counter) do
775+
def insert_all(%Ecto.Query{} = query, _counter) do
772776
[all(query)]
773777
end
774778

775-
def insert_all(rows, _on_conflict, counter) do
779+
def insert_all(rows, counter) do
776780
[
777781
"VALUES ",
778782
intersperse_reduce(
@@ -797,11 +801,12 @@ defmodule Ecto.Adapters.SQLite3.Connection do
797801
{%Ecto.Query{} = query, params_counter}, counter ->
798802
{[?(, all(query), ?)], counter + params_counter}
799803

804+
{:placeholder, placeholder_index}, counter ->
805+
{[?? | placeholder_index], counter}
806+
800807
_, counter ->
801-
# TODO: Should we have cell wise value support?
802-
# Essentially ``?1 ?2 ?3`` instead of ``? ? ?``
803-
# {['?' | Integer.to_string(counter)], counter + 1}
804-
{[~c"?"], counter + 1}
808+
# Cell wise value support ex: (?1, ?2, ?3)
809+
{[?? | Integer.to_string(counter)], counter + 1}
805810
end)
806811
end
807812

test/ecto/adapters/sqlite3/connection/insert_test.exs

+7-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ defmodule Ecto.Adapters.SQLite3.Connection.InsertTest do
66

77
test "insert" do
88
query = insert(nil, "schema", [:x, :y], [[:x, :y]], {:raise, [], []}, [:id])
9-
assert query == ~s{INSERT INTO "schema" ("x","y") VALUES (?,?) RETURNING "id"}
9+
assert query == ~s{INSERT INTO "schema" ("x","y") VALUES (?1,?2) RETURNING "id"}
1010

1111
assert_raise ArgumentError, fn ->
1212
insert(nil, "schema", [:x, :y], [[:x, :y], [nil, :z]], {:raise, [], []}, [:id])
@@ -30,7 +30,7 @@ defmodule Ecto.Adapters.SQLite3.Connection.InsertTest do
3030
end
3131

3232
query = insert(nil, "schema", [:x, :y], [[:x, :y]], {:raise, [], []}, [:id])
33-
assert query == ~s{INSERT INTO "schema" ("x","y") VALUES (?,?) RETURNING "id"}
33+
assert query == ~s{INSERT INTO "schema" ("x","y") VALUES (?1,?2) RETURNING "id"}
3434

3535
assert_raise(
3636
ArgumentError,
@@ -46,19 +46,19 @@ defmodule Ecto.Adapters.SQLite3.Connection.InsertTest do
4646
query = insert(nil, "schema", [:x, :y], [[:x, :y]], {:nothing, [], []}, [])
4747

4848
assert query ==
49-
~s{INSERT INTO "schema" ("x","y") VALUES (?,?) ON CONFLICT DO NOTHING}
49+
~s{INSERT INTO "schema" ("x","y") VALUES (?1,?2) ON CONFLICT DO NOTHING}
5050

5151
query = insert(nil, "schema", [:x, :y], [[:x, :y]], {:nothing, [], [:x, :y]}, [])
5252

5353
assert query ==
54-
~s{INSERT INTO "schema" ("x","y") VALUES (?,?) ON CONFLICT ("x","y") DO NOTHING}
54+
~s{INSERT INTO "schema" ("x","y") VALUES (?1,?2) ON CONFLICT ("x","y") DO NOTHING}
5555

5656
# For :update
5757
update = from("schema", update: [set: [z: "foo"]]) |> plan(:update_all)
5858
query = insert(nil, "schema", [:x, :y], [[:x, :y]], {update, [], [:x, :y]}, [:z])
5959

6060
assert query ==
61-
~s{INSERT INTO "schema" AS s0 ("x","y") VALUES (?,?) ON CONFLICT ("x","y") DO UPDATE SET "z" = 'foo' RETURNING "z"}
61+
~s{INSERT INTO "schema" AS s0 ("x","y") VALUES (?1,?2) ON CONFLICT ("x","y") DO UPDATE SET "z" = 'foo' RETURNING "z"}
6262

6363
# For :unsafe_fragment
6464
update = from("schema", update: [set: [z: "foo"]]) |> plan(:update_all)
@@ -74,7 +74,7 @@ defmodule Ecto.Adapters.SQLite3.Connection.InsertTest do
7474
)
7575

7676
assert query ==
77-
~s{INSERT INTO "schema" AS s0 ("x","y") VALUES (?,?) ON CONFLICT foobar DO UPDATE SET "z" = 'foo' RETURNING "z"}
77+
~s{INSERT INTO "schema" AS s0 ("x","y") VALUES (?1,?2) ON CONFLICT foobar DO UPDATE SET "z" = 'foo' RETURNING "z"}
7878

7979
assert_raise ArgumentError, "Upsert in SQLite3 requires :conflict_target", fn ->
8080
conflict_target = []
@@ -107,7 +107,7 @@ defmodule Ecto.Adapters.SQLite3.Connection.InsertTest do
107107
assert query ==
108108
"""
109109
INSERT INTO "schema" ("x","y") \
110-
VALUES (?,?) \
110+
VALUES (?1,?2) \
111111
ON CONFLICT ("id") \
112112
DO UPDATE SET "x" = EXCLUDED."x","y" = EXCLUDED."y"\
113113
"""

0 commit comments

Comments
 (0)