improvement: decode an interval as a Duration by default - #815
improvement: decode an interval as a Duration by default#815matt-beanland wants to merge 1 commit into
Conversation
|
|
||
| # `interval_decode_type` can only be set at `Postgrex.Types.define/3`, never in repo | ||
| # configuration, so an `interval` column needs this module to load as a `Duration`. | ||
| Postgrex.Types.define( |
There was a problem hiding this comment.
This could theoretically break any custom code that a user has. In other cases, we require the user to do this in their own application so that they have a single authoritative source of truth. I think we will have to do that here as well otherwise risk anyone who has custom interval handling code that is also using AshPostgres.
There was a problem hiding this comment.
Yes, agreed. The default is gone, and a repo's types: is never touched.
Now:
-
The error message teaches - A
%Postgrex.Interval{}reachingAsh.Type.Durationnow appends
thePostgrex.Types.define/3call and the repo config to the message, instead of a cast
error naming neither. -
The tests show how -
AshPostgres.TestRepoconfigures its own types module exactly as
the docs instruct, so the documented path is the one CI exercises rather than only
describes. -
The solution is pinned - Tests assert an
intervalloads as aDuration, that
months and days survive separately, and that a repo configuring its owntypes:keeps it.
(GitHub has followed this comment onto the test-support module — the file it was on is
deleted.)
7611cb5 to
db6bca7
Compare
Contributor checklist
Leave anything that you believe does not apply unchecked.
Summary
Part of #553 (doesn't close it because operators are outstanding)
A
:durationattribute cannot be read on Postgres. The value encodes into theintervalcolumn fine, but theRETURNINGrow loads back as a%Postgrex.Interval{}, whichAsh.Type.Durationrefuses, then the create fails with anAsh.Error.Unknownand the insert is rolled back, leaving nothing stored.postgrex can already decode an interval as a
Duration, butinterval_decode_typeis only settable atPostgrex.Types.define/3, never in repo configuration, and ash_postgres shipped no types module. This addsAshPostgres.PostgrexTypesand applies it inAshPostgres.Repo.init/2withKeyword.put_new, so a repo defining its own module for other extensions keeps it.The migration generator needs no change: a
:durationattribute already generatesadd(:field, :duration), which Ecto renders asinterval. In PostgresINTERVALandINTERVAL(6)are identical with microsecond precision.This changes interval decoding for every repo, not only
:durationattributes: raw queries and any custom interval-mapped type will receive aDurationrather than a%Postgrex.Interval{}. There is no Ash:durationdata to migrate, since loading one currently fails.Best paired with ash#2851 — without it, a
units-constrained duration is readable but not re-writable once persisted.Tested with Postgres 19.