Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions lib/ecto/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ defmodule Ecto.Schema do
used by `belongs_to` associations. It must be set in the same
module that defines the `belongs_to`. Defaults to `:id`;

* `@timestamps_opts` - configures the default timestamps type
used by `timestamps`. Defaults to `[type: :naive_datetime]`;
* `@timestamps_opts` - configures the default timestamps options
used by the [`timestamps`](`timestamps/1`) macro. Defaults to `[type: :naive_datetime]`;

* `@derive` - the same as `@derive` available in `Kernel.defstruct/1`
as the schema defines a struct behind the scenes;
Expand Down Expand Up @@ -730,6 +730,11 @@ defmodule Ecto.Schema do
* `:inserted_at` - the Ecto schema name of the field for insertion times or `false`
* `:updated_at` - the Ecto schema name of the field for update times or `false`
* `:inserted_at_source` - the name of the database column for insertion times or `false`
* `:inserted_at_writable` - the value of the Ecto schema `:writable` option for the
`inserted_at` field generated by this macro. Raises if `:never` is provided,
as Ecto must be able to automatically set the field at insertion.
* `:inserted_at_on_writable_violation` - the value of the Ecto schema `:on_writable_violation`
option for the `inserted_at` field generated by this macro.
* `:updated_at_source` - the name of the database column for update times or `false`
* `:type` - the timestamps type, defaults to `:naive_datetime`.
* `:autogenerate` - a module-function-args tuple used for generating
Expand Down Expand Up @@ -2110,6 +2115,23 @@ defmodule Ecto.Schema do

if inserted_at do
opts = if source = timestamps[:inserted_at_source], do: [source: source], else: []

opts = if writable = timestamps[:inserted_at_writable] do
if writable == :never do
raise ArgumentError, ":inserted_at_writable option cannot be set to :never as `inserted_at` will never be populated"
end

Keyword.put(opts, :writable, writable)
else
opts
end

opts = if on_writable_violation = timestamps[:inserted_at_on_writable_violation] do
Keyword.put(opts, :on_writable_violation, on_writable_violation)
else
opts
end

Ecto.Schema.__field__(mod, inserted_at, type, opts)
end

Expand Down
34 changes: 34 additions & 0 deletions test/ecto/schema_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,40 @@ defmodule Ecto.SchemaTest do
[{[:updated_at], {:m, :f, [:a]}}]
end

defmodule TimestampsWritableDefault do
use Ecto.Schema

schema "timestamps" do
timestamps()
end
end

defmodule TimestampsWritableCustom do
use Ecto.Schema

schema "timestamps" do
timestamps(inserted_at_writable: :insert, inserted_at_on_writable_violation: :raise)
end
end

test "timestamps with writable options" do
assert TimestampsWritableDefault.__schema__(:updatable_fields) == {[:updated_at, :inserted_at, :id], []}
assert TimestampsWritableDefault.__schema__(:on_writable_violation, :inserted_at) == :nothing

assert TimestampsWritableCustom.__schema__(:updatable_fields) == {[:updated_at, :id], [:inserted_at]}
assert TimestampsWritableCustom.__schema__(:on_writable_violation, :inserted_at) == :raise

assert_raise ArgumentError, ":inserted_at_writable option cannot be set to :never as `inserted_at` will never be populated", fn ->
defmodule TimestampsWritableNever do
use Ecto.Schema

schema "timestamps" do
timestamps(inserted_at_writable: :never)
end
end
end
end

defmodule TimestampsCustom do
use Ecto.Schema

Expand Down
Loading