Skip to content

Commit

Permalink
Prepare for Ecto 3.11 (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-rychlewski authored Dec 4, 2023
1 parent f9d8acd commit 290e96a
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 25 deletions.
5 changes: 4 additions & 1 deletion integration_test/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ ExUnit.start(
:selected_as_with_having,

# Distinct with options not supported
:distinct_count
:distinct_count,

# Values list
:values_list
]
)
8 changes: 0 additions & 8 deletions lib/ecto/adapters/sqlite3.ex
Original file line number Diff line number Diff line change
Expand Up @@ -376,14 +376,6 @@ defmodule Ecto.Adapters.SQLite3 do
end
end

# when we have an e.g., max(created_date) function
# Ecto does not truly know the return type, hence :maybe
# see Ecto.Query.Planner.collect_fields
@impl Ecto.Adapter
def loaders({:maybe, :naive_datetime}, type) do
[&Codec.naive_datetime_decode/1, type]
end

@impl Ecto.Adapter
def loaders(_, type) do
[type]
Expand Down
1 change: 1 addition & 0 deletions lib/ecto/adapters/sqlite3/codec.ex
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ defmodule Ecto.Adapters.SQLite3.Codec do

def blob_encode(value), do: {:ok, {:blob, value}}

def bool_encode(nil), do: {:ok, nil}
def bool_encode(false), do: {:ok, 0}
def bool_encode(true), do: {:ok, 1}

Expand Down
37 changes: 28 additions & 9 deletions lib/ecto/adapters/sqlite3/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ defmodule Ecto.Adapters.SQLite3.Connection do
group_by = group_by(query, sources)
having = having(query, sources)
window = window(query, sources)
combinations = combinations(query)
combinations = combinations(query, as_prefix)
order_by = order_by(query, sources)
limit = limit(query, sources)
offset = offset(query, sources)
Expand Down Expand Up @@ -1147,22 +1147,27 @@ defmodule Ecto.Adapters.SQLite3.Connection do
[" OFFSET " | expr(expression, sources, query)]
end

defp combinations(%{combinations: combinations}) do
Enum.map(combinations, &combination/1)
defp combinations(%{combinations: combinations}, as_prefix) do
Enum.map(combinations, &combination(&1, as_prefix))
end

defp combination({:union, query}), do: [" UNION ", all(query)]
defp combination({:union_all, query}), do: [" UNION ALL ", all(query)]
defp combination({:except, query}), do: [" EXCEPT ", all(query)]
defp combination({:intersect, query}), do: [" INTERSECT ", all(query)]
defp combination({:union, query}, as_prefix), do: [" UNION ", all(query, as_prefix)]

defp combination({:except_all, query}) do
defp combination({:union_all, query}, as_prefix),
do: [" UNION ALL ", all(query, as_prefix)]

defp combination({:except, query}, as_prefix), do: [" EXCEPT ", all(query, as_prefix)]

defp combination({:intersect, query}, as_prefix),
do: [" INTERSECT ", all(query, as_prefix)]

defp combination({:except_all, query}, _) do
raise Ecto.QueryError,
query: query,
message: "SQLite3 does not support EXCEPT ALL"
end

defp combination({:intersect_all, query}) do
defp combination({:intersect_all, query}, _) do
raise Ecto.QueryError,
query: query,
message: "SQLite3 does not INTERSECT ALL"
Expand Down Expand Up @@ -1306,6 +1311,12 @@ defmodule Ecto.Adapters.SQLite3.Connection do
end

def expr(%Ecto.SubQuery{query: query}, sources, parent_query) do
combinations =
Enum.map(query.combinations, fn {type, combination_query} ->
{type, put_in(combination_query.aliases[@parent_as], {parent_query, sources})}
end)

query = put_in(query.combinations, combinations)
query = put_in(query.aliases[@parent_as], {parent_query, sources})
[?(, all(query, subquery_as_prefix(sources)), ?)]
end
Expand All @@ -1326,10 +1337,18 @@ defmodule Ecto.Adapters.SQLite3.Connection do
|> parens_for_select
end

def expr({:values, _, _}, _, _query) do
raise ArgumentError, "SQLite3 adapter does not support values lists"
end

def expr({:literal, _, [literal]}, _sources, _query) do
quote_name(literal)
end

def expr({:splice, _, [{:^, _, [_, length]}]}, _sources, _query) do
Enum.intersperse(List.duplicate(??, length), ?,)
end

def expr({:selected_as, _, [name]}, _sources, _query) do
[quote_name(name)]
end
Expand Down
4 changes: 2 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ defmodule EctoSQLite3.MixProject do
defp deps do
[
{:decimal, "~> 1.6 or ~> 2.0"},
{:ecto_sql, "~> 3.10"},
{:ecto, "~> 3.10"},
{:ecto_sql, "~> 3.11"},
{:ecto, "~> 3.11"},
{:exqlite, "~> 0.9"},
{:ex_doc, "~> 0.27", only: [:dev], runtime: false},
{:jason, ">= 0.0.0", only: [:dev, :test, :docs]},
Expand Down
4 changes: 2 additions & 2 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"earmark_parser": {:hex, :earmark_parser, "1.4.37", "2ad73550e27c8946648b06905a57e4d454e4d7229c2dafa72a0348c99d8be5f7", [:mix], [], "hexpm", "6b19783f2802f039806f375610faa22da130b8edc21209d0bff47918bb48360e"},
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
"ecto_sql": {:hex, :ecto_sql, "3.10.2", "6b98b46534b5c2f8b8b5f03f126e75e2a73c64f3c071149d32987a5378b0fdbd", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "68c018debca57cb9235e3889affdaec7a10616a4e3a80c99fa1d01fdafaa9007"},
"ecto": {:hex, :ecto, "3.11.0", "ff8614b4e70a774f9d39af809c426def80852048440e8785d93a6e91f48fec00", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7769dad267ef967310d6e988e92d772659b11b09a0c015f101ce0fff81ce1f81"},
"ecto_sql": {:hex, :ecto_sql, "3.11.0", "c787b24b224942b69c9ff7ab9107f258ecdc68326be04815c6cce2941b6fad1c", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "77aa3677169f55c2714dda7352d563002d180eb33c0dc29cd36d39c0a1a971f5"},
"elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
"ex_doc": {:hex, :ex_doc, "0.30.9", "d691453495c47434c0f2052b08dd91cc32bc4e1a218f86884563448ee2502dd2", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "d7aaaf21e95dc5cddabf89063327e96867d00013963eadf2c6ad135506a8bc10"},
"exqlite": {:hex, :exqlite, "0.16.0", "d9a8d22493f135736cfc9a542cf5298dfa276c198f688ea4b08bd2c03f2a79d3", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "0ff541e1ead5cfde1206e3c2de8d746a7bf627fcc4afa606601be89f75d0057e"},
Expand Down
4 changes: 2 additions & 2 deletions test/ecto/adapters/sqlite3/connection/cte_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ defmodule Ecto.Adapters.SQLite3.Connection.CteTest do
~s{WITH RECURSIVE "tree" AS } <>
~s{(SELECT sc0."id" AS "id", 1 AS "depth" FROM "categories" AS sc0 WHERE (sc0."parent_id" IS NULL) } <>
~s{UNION ALL } <>
~s{SELECT c0."id", t1."depth" + 1 FROM "categories" AS c0 } <>
~s{INNER JOIN "tree" AS t1 ON t1."id" = c0."parent_id") } <>
~s{SELECT sc0."id", st1."depth" + 1 FROM "categories" AS sc0 } <>
~s{INNER JOIN "tree" AS st1 ON st1."id" = sc0."parent_id") } <>
~s{SELECT s0."x", t1."id", CAST(t1."depth" AS INTEGER) } <>
~s{FROM "schema" AS s0 } <>
~s{INNER JOIN "tree" AS t1 ON t1."id" = s0."category_id"}
Expand Down
11 changes: 11 additions & 0 deletions test/ecto/adapters/sqlite3/connection/select_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,17 @@ defmodule Ecto.Adapters.SQLite3.Connection.SelectTest do
|> all()
end
end

test "splicing" do
query =
Schema
|> select([r], r.x)
|> where([r], fragment("? in (?,?,?)", r.x, ^1, splice(^[2, 3, 4]), ^5))
|> plan()

assert all(query) ==
~s{SELECT s0."x" FROM "schema" AS s0 WHERE (s0."x" in (?,?,?,?,?))}
end
end

describe "literals" do
Expand Down
26 changes: 26 additions & 0 deletions test/ecto/adapters/sqlite3/connection/union_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,30 @@ defmodule Ecto.Adapters.SQLite3.Connection.UnionTest do
~s{UNION ALL SELECT s0."z" FROM "schema" AS s0 ORDER BY s0."z" LIMIT 60 OFFSET 30 } <>
~s{ORDER BY rand LIMIT 5 OFFSET 10} == all(query)
end

test "parent binding subquery and combination" do
right_query =
from(c in "right_categories", where: c.id == parent_as(:c).id, select: c.id)

left_query =
from(c in "left_categories", where: c.id == parent_as(:c).id, select: c.id)

union_query = union(left_query, ^right_query)

query =
from(c in "categories",
as: :c,
where: c.id in subquery(union_query),
select: c.id
)
|> plan()

assert all(query) ==
~s{SELECT c0."id" FROM "categories" AS c0 } <>
~s{WHERE (} <>
~s{c0."id" IN } <>
~s{(SELECT sl0."id" FROM "left_categories" AS sl0 WHERE (sl0."id" = c0."id") } <>
~s{UNION } <>
~s{SELECT sr0."id" FROM "right_categories" AS sr0 WHERE (sr0."id" = c0."id")))}
end
end
3 changes: 2 additions & 1 deletion test/ecto/adapters/sqlite3_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ defmodule Ecto.Adapters.SQLite3ConnTest do
@uuid_regex ~R/^[[:xdigit:]]{8}\b-[[:xdigit:]]{4}\b-[[:xdigit:]]{4}\b-[[:xdigit:]]{4}\b-[[:xdigit:]]{12}$/

setup do
original_binary_id_type = Application.get_env(:ecto_sqlite3, :binary_id_type)
original_binary_id_type =
Application.get_env(:ecto_sqlite3, :binary_id_type, :string)

on_exit(fn ->
Application.put_env(:ecto_sqlite3, :binary_id_type, original_binary_id_type)
Expand Down

0 comments on commit 290e96a

Please sign in to comment.