An Ecto SQLite3 adapter.
0

Configure Feed

Select the types of activity you want to include in your feed.

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

authored by

Matthew Johnston and committed by
GitHub
(Oct 28, 2024, 10:08 AM -0500) 3d69b84e b39bcbaf

+25 -20
+18 -13
lib/ecto/adapters/sqlite3/connection.ex
··· 267 267 ] 268 268 end 269 269 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 272 279 273 280 [ 274 281 "INSERT INTO ", 275 282 quote_table(prefix, table), 276 283 insert_as(on_conflict), 277 - " (", 278 - fields, 279 - ") ", 280 - insert_all(rows, on_conflict), 284 + values, 281 285 on_conflict(on_conflict, header), 282 286 returning(returning) 283 287 ] ··· 766 770 ] 767 771 end 768 772 769 - def insert_all(rows, on_conflict), do: insert_all(rows, on_conflict, 1) 773 + def insert_all(rows), do: insert_all(rows, 1) 770 774 771 - def insert_all(%Ecto.Query{} = query, _on_conflict, _counter) do 775 + def insert_all(%Ecto.Query{} = query, _counter) do 772 776 [all(query)] 773 777 end 774 778 775 - def insert_all(rows, _on_conflict, counter) do 779 + def insert_all(rows, counter) do 776 780 [ 777 781 "VALUES ", 778 782 intersperse_reduce( ··· 797 801 {%Ecto.Query{} = query, params_counter}, counter -> 798 802 {[?(, all(query), ?)], counter + params_counter} 799 803 804 + {:placeholder, placeholder_index}, counter -> 805 + {[?? | placeholder_index], counter} 806 + 800 807 _, 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} 805 810 end) 806 811 end 807 812
+7 -7
test/ecto/adapters/sqlite3/connection/insert_test.exs
··· 6 6 7 7 test "insert" do 8 8 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"} 10 10 11 11 assert_raise ArgumentError, fn -> 12 12 insert(nil, "schema", [:x, :y], [[:x, :y], [nil, :z]], {:raise, [], []}, [:id]) ··· 30 30 end 31 31 32 32 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"} 34 34 35 35 assert_raise( 36 36 ArgumentError, ··· 46 46 query = insert(nil, "schema", [:x, :y], [[:x, :y]], {:nothing, [], []}, []) 47 47 48 48 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} 50 50 51 51 query = insert(nil, "schema", [:x, :y], [[:x, :y]], {:nothing, [], [:x, :y]}, []) 52 52 53 53 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} 55 55 56 56 # For :update 57 57 update = from("schema", update: [set: [z: "foo"]]) |> plan(:update_all) 58 58 query = insert(nil, "schema", [:x, :y], [[:x, :y]], {update, [], [:x, :y]}, [:z]) 59 59 60 60 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"} 62 62 63 63 # For :unsafe_fragment 64 64 update = from("schema", update: [set: [z: "foo"]]) |> plan(:update_all) ··· 74 74 ) 75 75 76 76 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"} 78 78 79 79 assert_raise ArgumentError, "Upsert in SQLite3 requires :conflict_target", fn -> 80 80 conflict_target = [] ··· 107 107 assert query == 108 108 """ 109 109 INSERT INTO "schema" ("x","y") \ 110 - VALUES (?,?) \ 110 + VALUES (?1,?2) \ 111 111 ON CONFLICT ("id") \ 112 112 DO UPDATE SET "x" = EXCLUDED."x","y" = EXCLUDED."y"\ 113 113 """