Skip to content

Commit a82e18a

Browse files
committed
completes update_all/2 API
1 parent 1037a5f commit a82e18a

File tree

2 files changed

+63
-7
lines changed

2 files changed

+63
-7
lines changed

lib/sqlite_ecto/query.ex

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ defmodule Sqlite.Ecto.Query do
3737
end
3838

3939
def update_all(query, values) do
40+
if query.joins != [] do
41+
raise ArgumentError, "JOINS are not supported on UPDATE statements by SQLite"
42+
end
43+
44+
sources = create_names(query, :update)
45+
{table, _name, _model} = elem(sources, 0)
46+
47+
fields = Enum.map_join(values, ", ", fn {field, expr} ->
48+
"#{quote_id(field)} = #{expr(expr, sources)}"
49+
end)
50+
where = where(query.wheres, sources)
51+
assemble ["UPDATE", quote_id(table), "SET", fields, where]
4052
end
4153

4254
def delete_all(query) do
@@ -370,15 +382,19 @@ defmodule Sqlite.Ecto.Query do
370382

371383
## Generic Query Helpers
372384

373-
defp create_names(%{sources: sources}) do
374-
create_names(sources, 0, tuple_size(sources)) |> List.to_tuple()
385+
defp create_names(%{sources: sources}, stmt \\ :select) do
386+
create_names(sources, 0, tuple_size(sources), stmt) |> List.to_tuple()
375387
end
376-
defp create_names(sources, pos, limit) when pos < limit do
388+
defp create_names(sources, pos, limit, stmt) when pos < limit do
377389
{table, model} = elem(sources, pos)
378-
id = String.first(table) <> Integer.to_string(pos)
379-
[{table, id, model} | create_names(sources, pos + 1, limit)]
390+
if stmt == :select do
391+
id = String.first(table) <> Integer.to_string(pos)
392+
else
393+
id = nil
394+
end
395+
[{table, id, model} | create_names(sources, pos + 1, limit, stmt)]
380396
end
381-
defp create_names(_, pos, pos), do: []
397+
defp create_names(_, pos, pos, _stmt), do: []
382398

383399
defp select(%Ecto.Query.SelectExpr{fields: fields}, distinct, sources) do
384400
fields = Enum.map_join(fields, ", ", fn (f) ->
@@ -405,7 +421,11 @@ defmodule Sqlite.Ecto.Query do
405421

406422
defp expr({{:., _, [{:&, _, [idx]}, field]}, _, []}, sources) when is_atom(field) do
407423
{_, name, _} = elem(sources, idx)
408-
"#{name}.#{quote_id(field)}"
424+
if name do
425+
"#{name}.#{quote_id(field)}"
426+
else
427+
quote_id(field)
428+
end
409429
end
410430

411431
defp expr({:in, _, [left, right]}, sources) when is_list(right) do

test/sqlite_ecto_test.exs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,4 +504,40 @@ defmodule Sqlite.Ecto.Test do
504504
assert SQL.all(query) ==
505505
"SELECT m0.\"id\", m2.\"id\" FROM \"model\" AS m0 INNER JOIN \"model2\" AS m1 ON TRUE INNER JOIN \"model2\" AS m2 ON TRUE"
506506
end
507+
508+
test "update all" do
509+
query = Model |> Queryable.to_query |> normalize
510+
assert SQL.update_all(query, [x: 0]) == ~s{UPDATE "model" SET "x" = 0}
511+
512+
query = from(e in Model, where: e.x == 123) |> normalize
513+
assert SQL.update_all(query, [x: 0]) == ~s{UPDATE "model" SET "x" = 0 WHERE ( "x" = 123 )}
514+
515+
query = Model |> Queryable.to_query |> normalize
516+
assert SQL.update_all(query, [x: 0, y: "123"]) == ~s{UPDATE "model" SET "x" = 0, "y" = '123'}
517+
518+
query = Model |> Queryable.to_query |> normalize
519+
assert SQL.update_all(query, [x: quote(do: ^0)]) == ~s{UPDATE "model" SET "x" = ?}
520+
521+
assert_raise ArgumentError, "JOINS are not supported on UPDATE statements by SQLite", fn ->
522+
query = Model |> join(:inner, [p], q in Model2, p.x == q.z) |> normalize
523+
assert SQL.update_all(query, [x: 0])
524+
end
525+
end
526+
527+
# test "delete all" do
528+
# query = Model |> Queryable.to_query |> normalize
529+
# assert SQL.delete_all(query) == ~s{DELETE FROM "model" AS m0}
530+
#
531+
# query = from(e in Model, where: e.x == 123) |> normalize
532+
# assert SQL.delete_all(query) ==
533+
# ~s{DELETE FROM "model" AS m0 WHERE (m0."x" = 123)}
534+
#
535+
# query = Model |> join(:inner, [p], q in Model2, p.x == q.z) |> normalize
536+
# assert SQL.delete_all(query) ==
537+
# ~s{DELETE FROM "model" AS m0 USING "model2" AS m1 WHERE m0."x" = m1."z"}
538+
#
539+
# query = from(e in Model, where: e.x == 123, join: q in Model2, on: e.x == q.z) |> normalize
540+
# assert SQL.delete_all(query) ==
541+
# ~s{DELETE FROM "model" AS m0 USING "model2" AS m1 WHERE m0."x" = m1."z" AND (m0."x" = 123)}
542+
# end
507543
end

0 commit comments

Comments
 (0)