Skip to content

Commit

Permalink
Add support for nil value in datetime column (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
gshaw authored Dec 14, 2023
1 parent 00ceb86 commit fdb5f41
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ project adheres to [Semantic Versioning][semver].

## Unreleased

- added: Support for encoding nil values in `:utc_datetime`, `:utc_datetime_usec`, `:naive_datetime`, and `:naive_datetime_usec` column dates.

## v0.13.0

- added: Support fragment splicing.
Expand Down
6 changes: 6 additions & 0 deletions lib/ecto/adapters/sqlite3/codec.ex
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ defmodule Ecto.Adapters.SQLite3.Codec do

@text_datetime_format "%Y-%m-%d %H:%M:%S"

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)}
end
Expand All @@ -123,6 +126,9 @@ defmodule Ecto.Adapters.SQLite3.Codec do
"expected datetime type to be either `:iso8601` or `:text_datetime`, but received #{inspect(type)}"
end

def naive_datetime_encode(nil, :iso8601), do: {:ok, nil}
def naive_datetime_encode(nil, :text_datetime), do: {:ok, nil}

def naive_datetime_encode(value, :iso8601) do
{:ok, NaiveDateTime.to_iso8601(value)}
end
Expand Down
10 changes: 10 additions & 0 deletions test/ecto/adapters/sqlite3/codec_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ defmodule Ecto.Adapters.SQLite3.CodecTest do
[dt: ~U[2021-08-25 10:58:59Z]]
end

test "nil" do
assert {:ok, nil} = Codec.utc_datetime_encode(nil, :iso8601)
assert {:ok, nil} = Codec.utc_datetime_encode(nil, :text_datetime)
end

test "iso8601", %{dt: dt} do
dt_str = "2021-08-25T10:58:59"
assert {:ok, ^dt_str} = Codec.utc_datetime_encode(dt, :iso8601)
Expand All @@ -157,6 +162,11 @@ defmodule Ecto.Adapters.SQLite3.CodecTest do
[dt: ~U[2021-08-25 10:58:59Z], dt_str: "2021-08-25T10:58:59"]
end

test "nil" do
assert {:ok, nil} = Codec.naive_datetime_encode(nil, :iso8601)
assert {:ok, nil} = Codec.naive_datetime_encode(nil, :text_datetime)
end

test "iso8601", %{dt: dt} do
dt_str = "2021-08-25T10:58:59"
assert {:ok, ^dt_str} = Codec.naive_datetime_encode(dt, :iso8601)
Expand Down
22 changes: 22 additions & 0 deletions test/ecto/integration/timestamps_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,28 @@ defmodule Ecto.Integration.TimestampsTest do
assert user
end

test "insert and fetch nil values" do
now = DateTime.utc_now()

{:ok, product} =
%Product{}
|> Product.changeset(%{name: "Nil Date Test", approved_at: now, ordered_at: now})
|> TestRepo.insert()

product = TestRepo.get(Product, product.id)
assert product.name == "Nil Date Test"
assert product.approved_at != now
assert product.ordered_at != now
assert product.approved_at == DateTime.truncate(now, :second) |> DateTime.to_naive()
assert product.ordered_at == DateTime.truncate(now, :second)

changeset = Product.changeset(product, %{approved_at: nil, ordered_at: nil})
TestRepo.update(changeset)
product = TestRepo.get(Product, product.id)
assert product.approved_at == nil
assert product.ordered_at == nil
end

test "datetime comparisons" do
account =
%Account{}
Expand Down
1 change: 1 addition & 0 deletions test/support/migration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ defmodule EctoSQLite3.Integration.Migration do
add(:bid, :binary_id)
add(:tags, {:array, :string})
add(:approved_at, :naive_datetime)
add(:ordered_at, :utc_datetime)
add(:price, :decimal)
timestamps()
end
Expand Down
3 changes: 2 additions & 1 deletion test/support/schemas/product.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defmodule EctoSQLite3.Schemas.Product do
field(:bid, :binary_id)
field(:tags, {:array, :string}, default: [])
field(:approved_at, :naive_datetime)
field(:ordered_at, :utc_datetime)
field(:price, :decimal)

belongs_to(:account, Account)
Expand All @@ -23,7 +24,7 @@ defmodule EctoSQLite3.Schemas.Product do

def changeset(struct, attrs) do
struct
|> cast(attrs, [:name, :description, :tags, :account_id, :approved_at])
|> cast(attrs, [:name, :description, :tags, :account_id, :approved_at, :ordered_at])
|> validate_required([:name])
|> maybe_generate_external_id()
end
Expand Down

0 comments on commit fdb5f41

Please sign in to comment.