diff --git a/CHANGELOG.md b/CHANGELOG.md index 136f8f3..5734b72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is loosely based on [Keep a Changelog][keepachangelog], and this project adheres to [Semantic Versioning][semver]. ## Unreleased +- fixed: Handle datetime serialization format via `:datetime_type` config. ## v0.17.1 - changed: Bump minimum ecto to `3.12`. diff --git a/lib/ecto/adapters/sqlite3/codec.ex b/lib/ecto/adapters/sqlite3/codec.ex index 3cd5375..61df7d7 100644 --- a/lib/ecto/adapters/sqlite3/codec.ex +++ b/lib/ecto/adapters/sqlite3/codec.ex @@ -114,12 +114,16 @@ defmodule Ecto.Adapters.SQLite3.Codec do end @text_datetime_format "%Y-%m-%d %H:%M:%S" + @iso8601_format "%Y-%m-%dT%H:%M:%S" + + def datetime_format(:text_datetime), do: @text_datetime_format + def datetime_format(_), do: @iso8601_format def utc_datetime_encode(nil, :iso8601), do: {:ok, nil} def utc_datetime_encode(nil, :text_datetime), do: {:ok, nil} def utc_datetime_encode(%{time_zone: "Etc/UTC"} = value, :iso8601) do - {:ok, NaiveDateTime.to_iso8601(value)} + {:ok, Calendar.strftime(value, @iso8601_format)} end def utc_datetime_encode(%{time_zone: "Etc/UTC"} = value, :text_datetime) do @@ -135,7 +139,7 @@ defmodule Ecto.Adapters.SQLite3.Codec do def naive_datetime_encode(nil, :text_datetime), do: {:ok, nil} def naive_datetime_encode(value, :iso8601) do - {:ok, NaiveDateTime.to_iso8601(value)} + {:ok, Calendar.strftime(value, @iso8601_format)} end def naive_datetime_encode(value, :text_datetime) do diff --git a/lib/ecto/adapters/sqlite3/connection.ex b/lib/ecto/adapters/sqlite3/connection.ex index 790d1c7..e0a6760 100644 --- a/lib/ecto/adapters/sqlite3/connection.ex +++ b/lib/ecto/adapters/sqlite3/connection.ex @@ -1369,10 +1369,14 @@ defmodule Ecto.Adapters.SQLite3.Connection do [quote_name(name)] end + @datetime_type Application.compile_env(:ecto_sqlite3, :datetime_type, :iso8601) + defp expr({:datetime_add, _, [datetime, count, interval]}, sources, query) do + format = Ecto.Adapters.SQLite3.Codec.datetime_format(@datetime_type) + [ "CAST (", - "strftime('%Y-%m-%d %H:%M:%f000Z'", + "strftime('#{format}'", ",", expr(datetime, sources, query), ",", diff --git a/test/ecto/adapters/sqlite3/connection/datetime_add_test.exs b/test/ecto/adapters/sqlite3/connection/datetime_add_test.exs index 9fd62dc..583ab8a 100644 --- a/test/ecto/adapters/sqlite3/connection/datetime_add_test.exs +++ b/test/ecto/adapters/sqlite3/connection/datetime_add_test.exs @@ -11,7 +11,7 @@ defmodule Ecto.Adapters.SQLite3.Connection.DatetimeAddTest do |> select([], true) |> plan() - assert ~s{SELECT 1 FROM "schema" AS s0 WHERE (CAST (strftime('%Y-%m-%d %H:%M:%f000Z',s0.\"foo\",1 || ' month') AS TEXT) > s0."bar")} == + assert ~s{SELECT 1 FROM "schema" AS s0 WHERE (CAST (strftime('%Y-%m-%dT%H:%M:%S',s0.\"foo\",1 || ' month') AS TEXT) > s0."bar")} == all(query) end @@ -22,7 +22,7 @@ defmodule Ecto.Adapters.SQLite3.Connection.DatetimeAddTest do |> select([], true) |> plan() - assert ~s{SELECT 1 FROM "schema" AS s0 WHERE (CAST (strftime('%Y-%m-%d %H:%M:%f000Z',CAST(s0.\"foo\" AS TEXT),1 || ' month') AS TEXT) > s0."bar")} == + assert ~s{SELECT 1 FROM "schema" AS s0 WHERE (CAST (strftime('%Y-%m-%dT%H:%M:%S',CAST(s0.\"foo\" AS TEXT),1 || ' month') AS TEXT) > s0."bar")} == all(query) end end diff --git a/test/ecto/integration/timestamps_test.exs b/test/ecto/integration/timestamps_test.exs index 00b1362..1ea3e6c 100644 --- a/test/ecto/integration/timestamps_test.exs +++ b/test/ecto/integration/timestamps_test.exs @@ -181,6 +181,31 @@ defmodule Ecto.Integration.TimestampsTest do |> TestRepo.all() end + test "using built in ecto functions" do + account = insert_account(%{name: "Test"}) + + insert_product(%{ + account_id: account.id, + name: "Foo", + inserted_at: seconds_ago(1) + }) + + insert_product(%{ + account_id: account.id, + name: "Bar", + inserted_at: seconds_ago(3) + }) + + assert [ + %{name: "Foo"}, + ] = + Product + |> select([p], p) + |> where([p], p.inserted_at >= ago(2, "second")) + |> order_by([p], desc: p.inserted_at) + |> TestRepo.all() + end + defp insert_account(attrs) do %Account{} |> Account.changeset(attrs) @@ -192,4 +217,9 @@ defmodule Ecto.Integration.TimestampsTest do |> Product.changeset(attrs) |> TestRepo.insert!() end + + defp seconds_ago(seconds) do + now = DateTime.utc_now() + DateTime.add(now, -seconds, :second) + end end