The value of PostgreSQL’s date
type can be between 4713 BC and 5874897 AD, but Ecto.Schema
uses Elixir.Date
to represent Ecto’s :date
primitive type, so future dates (e.g., where the year exceeds 4 digits) cannot be entered using the defaults, even though PostgreSQL would have no issue with it:
f=# \d+ fictional_date
Table "public.fictional_date"
Column | Type | Collation | Nullable | Default | Storage |
-------------+--------+-----------+----------+--------------------------------------------+---------+
id | bigint | | not null | nextval('fictional_date_id_seq'::regclass) | plain |
future_date | date | | | | plain |
indexes:
"fictional_date_pkey" PRIMARY KEY, btree (id)
Access method: heap
f=# table fictional_date;
id | future_date
---+---------------
1 | 12345-12-24
2 | 123456-12-24
3 | 1234567-12-24
e (11 rows)
If I wanted to implement a custom date field (e.g., PostgresDate
) that allows the same values as PostgreSQL’s date
type, then would the steps below be appropriate to do it?
-
Migrations
It would be ok to use the line
add :future_date, :date
in a migration, because, according to the
Ecto.Migration
documentation’s Field Types section:Ecto primitive types are mapped to the appropriate database type by the various database adapters
In this case,
:date
will be used as is byEcto.Adapters.Postgres
. (Now, this adapter usesPostgrex
which in turn usesElixir.Date
to represent:date
, so do I need to define a customPostgrex
type as well?..) -
Schemas
The
Ecto.Schema
documentation’s Custom types section is very clear that I would need to implement eitherEcto.Type
orEcto.ParameterizedType
behaviours.-
The
type()
callback section brings a date-specific example, so I would return:date
, I guess. -
A
dump()
callback implementation should convert “the given term into an Ecto native type”, which is:date
in my case. The example is straightforward (i.e.,type/0
returns:map
anddump/1
returns anElixir.Map
), but I can’t return anElixir.Date
because the issue is with it to begin with.
-
I stopped here because I have a feeling that I’m overthinking it. I couldn’t find an example implementation yet, so examples are welcome!