Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions integration_test/exqlite/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ ExUnit.start(
# that converts the string JSON representaiton into a map
:map_type_schemaless,

# we should be able to fully/correctly support these, but don't currently
:with_conflict_target,
:without_conflict_target,

# right now in lock_for_migrations() we do effectively nothing, this is because
# SQLite is single-writer so there isn't really a need for us to do anything.
# ecto assumes all implementing adapters need >=2 connections for migrations
Expand Down
58 changes: 32 additions & 26 deletions lib/ecto/adapters/exqlite/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,11 @@ defmodule Ecto.Adapters.Exqlite.Connection do
insert(prefix, table, header, rows, on_conflict, returning, [])
end

def insert(prefix, table, [], [[]], _on_conflict, returning, []) do
def insert(prefix, table, [], [[]], on_conflict, returning, []) do
[
"INSERT INTO ",
quote_table(prefix, table),
insert_as(on_conflict),
" DEFAULT VALUES",
returning(returning)
]
Expand All @@ -256,6 +257,7 @@ defmodule Ecto.Adapters.Exqlite.Connection do
[
"INSERT INTO ",
quote_table(prefix, table),
insert_as(on_conflict),
" (",
fields,
") ",
Expand Down Expand Up @@ -639,49 +641,45 @@ defmodule Ecto.Adapters.Exqlite.Connection do
## Query generation
##

def on_conflict({:raise, _, []}, _header), do: []
defp on_conflict({:raise, _, []}, _header), do: []

def on_conflict({:nothing, _, targets}, _header) do
defp on_conflict({:nothing, _, targets}, _header) do
[" ON CONFLICT ", conflict_target(targets) | "DO NOTHING"]
end

def on_conflict({:replace_all, _, []}, _header) do
defp on_conflict({:replace_all, _, {:constraint, _}}, _header) do
raise ArgumentError, "Upsert in SQLite3 does not support ON CONSTRAINT"
end

defp on_conflict({:replace_all, _, []}, _header) do
raise ArgumentError, "Upsert in SQLite3 requires :conflict_target"
end

def on_conflict({:replace_all, _, {:constraint, _}}, _header) do
raise ArgumentError, "Upsert in SQLite3 does not support ON CONSTRAINT"
defp on_conflict({:replace_all, _, targets}, header) do
[" ON CONFLICT ", conflict_target(targets), "DO " | replace(header)]
end

def on_conflict({:replace_all, _, targets}, header) do
[
" ON CONFLICT ",
conflict_target(targets),
"DO " | replace_all(header)
]
defp on_conflict({fields, _, targets}, _header) when is_list(fields) do
[" ON CONFLICT ", conflict_target(targets), "DO " | replace(fields)]
end

def on_conflict({query, _, targets}, _header) do
[
" ON CONFLICT ",
conflict_target(targets),
"DO " | update_all(query, "UPDATE SET ")
]
defp on_conflict({query, _, targets}, _header) do
[" ON CONFLICT ", conflict_target(targets), "DO " | update_all(query, "UPDATE SET ")]
end

def conflict_target([]), do: ""
defp conflict_target([]), do: ""

def conflict_target(targets) do
defp conflict_target(targets) do
[?(, intersperse_map(targets, ?,, &quote_name/1), ?), ?\s]
end

def replace_all(header) do
defp replace(fields) do
[
"UPDATE SET "
| intersperse_map(header, ?,, fn field ->
quoted = quote_name(field)
[quoted, " = ", "EXCLUDED." | quoted]
end)
"UPDATE SET " |
intersperse_map(fields, ?,, fn field ->
quoted = quote_name(field)
[quoted, " = ", "EXCLUDED." | quoted]
end)
]
end

Expand Down Expand Up @@ -721,6 +719,14 @@ defmodule Ecto.Adapters.Exqlite.Connection do
end)
end

defp insert_as({%{sources: sources}, _, _}) do
{_expr, name, _schema} = create_name(sources, 0, [])
[" AS " | name]
end
defp insert_as({_, _, _}) do
[]
end

binary_ops = [
==: " = ",
!=: " != ",
Expand Down