Skip to content

Commit fdb5f41

Browse files
authored
Add support for nil value in datetime column (#136)
1 parent 00ceb86 commit fdb5f41

File tree

6 files changed

+43
-1
lines changed

6 files changed

+43
-1
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ project adheres to [Semantic Versioning][semver].
77

88
## Unreleased
99

10+
- added: Support for encoding nil values in `:utc_datetime`, `:utc_datetime_usec`, `:naive_datetime`, and `:naive_datetime_usec` column dates.
11+
1012
## v0.13.0
1113

1214
- added: Support fragment splicing.

lib/ecto/adapters/sqlite3/codec.ex

+6
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ defmodule Ecto.Adapters.SQLite3.Codec do
110110

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

113+
def utc_datetime_encode(nil, :iso8601), do: {:ok, nil}
114+
def utc_datetime_encode(nil, :text_datetime), do: {:ok, nil}
115+
113116
def utc_datetime_encode(%{time_zone: "Etc/UTC"} = value, :iso8601) do
114117
{:ok, NaiveDateTime.to_iso8601(value)}
115118
end
@@ -123,6 +126,9 @@ defmodule Ecto.Adapters.SQLite3.Codec do
123126
"expected datetime type to be either `:iso8601` or `:text_datetime`, but received #{inspect(type)}"
124127
end
125128

129+
def naive_datetime_encode(nil, :iso8601), do: {:ok, nil}
130+
def naive_datetime_encode(nil, :text_datetime), do: {:ok, nil}
131+
126132
def naive_datetime_encode(value, :iso8601) do
127133
{:ok, NaiveDateTime.to_iso8601(value)}
128134
end

test/ecto/adapters/sqlite3/codec_test.exs

+10
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ defmodule Ecto.Adapters.SQLite3.CodecTest do
132132
[dt: ~U[2021-08-25 10:58:59Z]]
133133
end
134134

135+
test "nil" do
136+
assert {:ok, nil} = Codec.utc_datetime_encode(nil, :iso8601)
137+
assert {:ok, nil} = Codec.utc_datetime_encode(nil, :text_datetime)
138+
end
139+
135140
test "iso8601", %{dt: dt} do
136141
dt_str = "2021-08-25T10:58:59"
137142
assert {:ok, ^dt_str} = Codec.utc_datetime_encode(dt, :iso8601)
@@ -157,6 +162,11 @@ defmodule Ecto.Adapters.SQLite3.CodecTest do
157162
[dt: ~U[2021-08-25 10:58:59Z], dt_str: "2021-08-25T10:58:59"]
158163
end
159164

165+
test "nil" do
166+
assert {:ok, nil} = Codec.naive_datetime_encode(nil, :iso8601)
167+
assert {:ok, nil} = Codec.naive_datetime_encode(nil, :text_datetime)
168+
end
169+
160170
test "iso8601", %{dt: dt} do
161171
dt_str = "2021-08-25T10:58:59"
162172
assert {:ok, ^dt_str} = Codec.naive_datetime_encode(dt, :iso8601)

test/ecto/integration/timestamps_test.exs

+22
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,28 @@ defmodule Ecto.Integration.TimestampsTest do
123123
assert user
124124
end
125125

126+
test "insert and fetch nil values" do
127+
now = DateTime.utc_now()
128+
129+
{:ok, product} =
130+
%Product{}
131+
|> Product.changeset(%{name: "Nil Date Test", approved_at: now, ordered_at: now})
132+
|> TestRepo.insert()
133+
134+
product = TestRepo.get(Product, product.id)
135+
assert product.name == "Nil Date Test"
136+
assert product.approved_at != now
137+
assert product.ordered_at != now
138+
assert product.approved_at == DateTime.truncate(now, :second) |> DateTime.to_naive()
139+
assert product.ordered_at == DateTime.truncate(now, :second)
140+
141+
changeset = Product.changeset(product, %{approved_at: nil, ordered_at: nil})
142+
TestRepo.update(changeset)
143+
product = TestRepo.get(Product, product.id)
144+
assert product.approved_at == nil
145+
assert product.ordered_at == nil
146+
end
147+
126148
test "datetime comparisons" do
127149
account =
128150
%Account{}

test/support/migration.ex

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ defmodule EctoSQLite3.Integration.Migration do
3131
add(:bid, :binary_id)
3232
add(:tags, {:array, :string})
3333
add(:approved_at, :naive_datetime)
34+
add(:ordered_at, :utc_datetime)
3435
add(:price, :decimal)
3536
timestamps()
3637
end

test/support/schemas/product.ex

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ defmodule EctoSQLite3.Schemas.Product do
1414
field(:bid, :binary_id)
1515
field(:tags, {:array, :string}, default: [])
1616
field(:approved_at, :naive_datetime)
17+
field(:ordered_at, :utc_datetime)
1718
field(:price, :decimal)
1819

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

2425
def changeset(struct, attrs) do
2526
struct
26-
|> cast(attrs, [:name, :description, :tags, :account_id, :approved_at])
27+
|> cast(attrs, [:name, :description, :tags, :account_id, :approved_at, :ordered_at])
2728
|> validate_required([:name])
2829
|> maybe_generate_external_id()
2930
end

0 commit comments

Comments
 (0)