174 lines
5.6 KiB
Elixir
174 lines
5.6 KiB
Elixir
defmodule Ecto.Integration.SQLTest do
|
|
use Ecto.Integration.Case, async: Application.compile_env(:ecto, :async_integration_tests, true)
|
|
|
|
alias Ecto.Integration.PoolRepo
|
|
alias Ecto.Integration.TestRepo
|
|
alias Ecto.Integration.Barebone
|
|
alias Ecto.Integration.Post
|
|
alias Ecto.Integration.CorruptedPk
|
|
alias Ecto.Integration.Tag
|
|
import Ecto.Query, only: [from: 2]
|
|
|
|
test "fragmented types" do
|
|
datetime = ~N[2014-01-16 20:26:51]
|
|
TestRepo.insert!(%Post{inserted_at: datetime})
|
|
query = from p in Post, where: fragment("? >= ?", p.inserted_at, ^datetime), select: p.inserted_at
|
|
assert [^datetime] = TestRepo.all(query)
|
|
end
|
|
|
|
test "fragmented schemaless types" do
|
|
TestRepo.insert!(%Post{visits: 123})
|
|
assert [123] = TestRepo.all(from p in "posts", select: type(fragment("visits"), :integer))
|
|
end
|
|
|
|
@tag :array_type
|
|
test "fragment array types" do
|
|
text1 = "foo"
|
|
text2 = "bar"
|
|
result = TestRepo.query!("SELECT $1::text[]", [[text1, text2]])
|
|
assert result.rows == [[[text1, text2]]]
|
|
end
|
|
|
|
@tag :array_type
|
|
test "Converts empty array correctly" do
|
|
result = TestRepo.query!("SELECT array[1,2,3] = $1", [[]])
|
|
assert result.rows == [[false]]
|
|
|
|
result = TestRepo.query!("SELECT array[]::integer[] = $1", [[]])
|
|
assert result.rows == [[true]]
|
|
|
|
%{id: tag_id} = TestRepo.insert!(%Tag{uuids: []})
|
|
query = from t in Tag, where: t.uuids == []
|
|
assert [%{id: ^tag_id}] = TestRepo.all(query)
|
|
end
|
|
|
|
test "query!/4 with dynamic repo" do
|
|
TestRepo.put_dynamic_repo(:unknown)
|
|
assert_raise RuntimeError, ~r/:unknown/, fn -> TestRepo.query!("SELECT 1") end
|
|
end
|
|
|
|
test "query!/4" do
|
|
result = TestRepo.query!("SELECT 1")
|
|
assert result.rows == [[1]]
|
|
end
|
|
|
|
test "query!/4 with iodata" do
|
|
result = TestRepo.query!(["SELECT", ?\s, ?1])
|
|
assert result.rows == [[1]]
|
|
end
|
|
|
|
test "disconnect_all/2" do
|
|
assert :ok = PoolRepo.disconnect_all(0)
|
|
end
|
|
|
|
test "to_sql/3" do
|
|
{sql, []} = TestRepo.to_sql(:all, Barebone)
|
|
assert sql =~ "SELECT"
|
|
assert sql =~ "barebones"
|
|
|
|
{sql, [0]} = TestRepo.to_sql(:update_all, from(b in Barebone, update: [set: [num: ^0]]))
|
|
assert sql =~ "UPDATE"
|
|
assert sql =~ "barebones"
|
|
assert sql =~ "SET"
|
|
|
|
{sql, []} = TestRepo.to_sql(:delete_all, Barebone)
|
|
assert sql =~ "DELETE"
|
|
assert sql =~ "barebones"
|
|
end
|
|
|
|
test "raises when primary key is not unique on struct operation" do
|
|
schema = %CorruptedPk{a: "abc"}
|
|
TestRepo.insert!(schema)
|
|
TestRepo.insert!(schema)
|
|
TestRepo.insert!(schema)
|
|
|
|
assert_raise Ecto.MultiplePrimaryKeyError,
|
|
~r|expected delete on corrupted_pk to return at most one entry but got 3 entries|,
|
|
fn -> TestRepo.delete!(schema) end
|
|
end
|
|
|
|
test "Repo.insert! escape" do
|
|
TestRepo.insert!(%Post{title: "'"})
|
|
|
|
query = from(p in Post, select: p.title)
|
|
assert ["'"] == TestRepo.all(query)
|
|
end
|
|
|
|
test "Repo.update! escape" do
|
|
p = TestRepo.insert!(%Post{title: "hello"})
|
|
TestRepo.update!(Ecto.Changeset.change(p, title: "'"))
|
|
|
|
query = from(p in Post, select: p.title)
|
|
assert ["'"] == TestRepo.all(query)
|
|
end
|
|
|
|
@tag :insert_cell_wise_defaults
|
|
test "Repo.insert_all escape" do
|
|
TestRepo.insert_all(Post, [%{title: "'"}])
|
|
|
|
query = from(p in Post, select: p.title)
|
|
assert ["'"] == TestRepo.all(query)
|
|
end
|
|
|
|
test "Repo.update_all escape" do
|
|
TestRepo.insert!(%Post{title: "hello"})
|
|
|
|
TestRepo.update_all(Post, set: [title: "'"])
|
|
reader = from(p in Post, select: p.title)
|
|
assert ["'"] == TestRepo.all(reader)
|
|
|
|
query = from(Post, where: "'" != "")
|
|
TestRepo.update_all(query, set: [title: "''"])
|
|
assert ["''"] == TestRepo.all(reader)
|
|
end
|
|
|
|
test "Repo.delete_all escape" do
|
|
TestRepo.insert!(%Post{title: "hello"})
|
|
assert [_] = TestRepo.all(Post)
|
|
|
|
TestRepo.delete_all(from(Post, where: "'" == "'"))
|
|
assert [] == TestRepo.all(Post)
|
|
end
|
|
|
|
test "load" do
|
|
inserted_at = ~N[2016-01-01 09:00:00]
|
|
TestRepo.insert!(%Post{title: "title1", inserted_at: inserted_at, public: false})
|
|
|
|
result = Ecto.Adapters.SQL.query!(TestRepo, "SELECT * FROM posts", [])
|
|
posts = Enum.map(result.rows, &TestRepo.load(Post, {result.columns, &1}))
|
|
assert [%Post{title: "title1", inserted_at: ^inserted_at, public: false}] = posts
|
|
end
|
|
|
|
test "returns true when table exists" do
|
|
assert Ecto.Adapters.SQL.table_exists?(TestRepo, "posts")
|
|
end
|
|
|
|
test "returns false table doesn't exists" do
|
|
refute Ecto.Adapters.SQL.table_exists?(TestRepo, "unknown")
|
|
end
|
|
|
|
test "returns result as a formatted table" do
|
|
TestRepo.insert_all(Post, [%{title: "my post title", counter: 1, public: nil}])
|
|
|
|
# resolve correct query for each adapter
|
|
query = from(p in Post, select: [p.title, p.counter, p.public])
|
|
{query, _} = Ecto.Adapters.SQL.to_sql(:all, TestRepo, query)
|
|
|
|
table =
|
|
query
|
|
|> TestRepo.query!()
|
|
|> Ecto.Adapters.SQL.format_table()
|
|
|
|
assert table == "+---------------+---------+--------+\n| title | counter | public |\n+---------------+---------+--------+\n| my post title | 1 | NULL |\n+---------------+---------+--------+"
|
|
end
|
|
|
|
test "format_table edge cases" do
|
|
assert Ecto.Adapters.SQL.format_table(nil) == ""
|
|
assert Ecto.Adapters.SQL.format_table(%{columns: nil, rows: nil}) == ""
|
|
assert Ecto.Adapters.SQL.format_table(%{columns: [], rows: []}) == ""
|
|
assert Ecto.Adapters.SQL.format_table(%{columns: [], rows: [["test"]]}) == ""
|
|
assert Ecto.Adapters.SQL.format_table(%{columns: ["test"], rows: []}) == "+------+\n| test |\n+------+\n+------+"
|
|
assert Ecto.Adapters.SQL.format_table(%{columns: ["test"], rows: nil}) == "+------+\n| test |\n+------+\n+------+"
|
|
end
|
|
end
|