When I create models that have a time field with default: "now()' on test, all have the same time

On test, I create models that have a timestamp field with default: fragment("now()"), and all have the same time.

create table(:orders) do
  add :placed_at, :timestamptz, null: false, default: fragment("now()")
end

schema "orders" do
    field(:placed_at, Timex.Ecto.DateTime)
end

{:ok, order0} = Order.create()
Process.sleep(1000)
{:ok, order1} = Order.create()

order0 |> IO.inspect
=>
 %Order{
  __meta__: #Ecto.Schema.Metadata<:loaded, "orders">,
  id: 1,
  placed_at: #DateTime<2018-02-14 02:46:36.723875Z>, # the same
}}

order1 |> IO.inspect
=>
{:ok,
 %Order{
  __meta__: #Ecto.Schema.Metadata<:loaded, "orders">,
  id: 2,
  placed_at: #DateTime<2018-02-14 02:46:36.723875Z>, # the same
}}

It doesn’t happen on dev environment.
Time fields without default, ex: timestamps(), have no problem.

Within a Postgres transaction the value of now() does not change, it’s set to the time at the start of the transaction. Would that account for your test scenario?

1 Like

When you created your schema, you set the default to now. now was evaluated the moment the migration was ran and will always be the same. placed_at will not be not generated every time there’s a new insert like you are expected. You’ll need to either insert it manually in your create/0 function or you can optionally use a Postgres trigger. Updating the function would be the simplest solution.

def create do
  %Order{placed_at: DateTime.utc_now()}
end
1 Like

Exactly!

When I create two order, order_match is created via trigger of database.

I want to test a function that queries order_matchs filtering with datetime, but I can’t because matching_time of order_match are all the same. (matching_time is created by “now()”)

Postgres provides clock_timestamp that is not tied to the beginning of the current transaction. You could also pass the timestamp to the DB from Elixir and obtain it using DateTime.utc_now().