nicnilov

nicnilov

Difficulty employing Duration to PostgreSQL :interval with solution

This is not so much a question but rather an answer to an issue which took me some time to figure out, and maybe a suggestion to improve the docs. Please see the end of the message for the solution.


Using Elixir 1.17.3, Ecto 3.12.4, Postgrex 0.19.3:

I’m working on some calendar-related functionality and needed to represent a duration. I had this in my migration:

create table(...) do
  ...
  add :default_duration, :interval
  ...

However, it was not clear to me how should I define my schema. For starters I was looking to make the field load as just a Postgrex.Interval, which seems to be the default and should not require any extra configuration.

I could not just do this:

schema "..." do
  ...  
  field :default_duration, :interval
  ...

as there is no :interval Ecto type. When I did this:

  field :default_duration, :duration

it compiled, but an attempt to load a record resulted in an error:

(ArgumentError) cannot load `%Postgrex.Interval{months: 0, days: 0, secs: 1800, microsecs: 0}` as type :duration for field :default_duration...

I tried field :default_duration, Postgrex.Interval, field :default_duration, Postgrex.Duration, even field :default_duration, Postgrex.Extensions.Interval with the same result.

Following the Ecto.Schema docs, Postgrex docs, Postgrex.Types.html#define/3 docs I tried to configure Postgrex to use the interval_decode_type: Duration, however the docs seemed rather sparse and it was not clear how exactly it should be done. I tried this in my lib/my_app/postgrex_types.ex:

Postgrex.Types.define(MyApp.PostgrexTypes, [], interval_decode_type: Duration)

However it is also additionally required passing types: MyApp.PostgrexTypes to Postgrex.start_link/1, and since I don’t start Postgrex manually, it was not clear to me how this bit could be passed to it in addition to all the existing Repo config.


It was not until I inadvertently looked into Ecto.Adapters.Postgres and saw the Extensions clause when it finally became clear. So, in order to employ the Duration Elixir type on a Postgres :interval field without registering any new extensions, the following worked:

In lib/my_app/postgres_types.ex:

Postgrex.Types.define(MyApp.PostgresTypes, Ecto.Adapters.Postgres.extensions(), interval_decode_type: Duration)

In config/config.exs:

config :my_app, MyApp.Repo,
  ...
  types: MyApp.PostgresTypes

At this point a schema field defined as

  field :default_duration, :duration

started returning the desired Duration struct:

  ...
  default_duration: %Duration{minute: 30, microsecond: {0, 6}},
  ...

Maybe the solution is so obvious no one really had an issue before - I didn’t find any complaints online. But maybe the Ecto.Schema | Primitive types should be updated to include a more explicit example.

Most Liked

christhekeele

christhekeele

I disagree, per your own point that

I’d say this extends to documentation on postgre(s|x) exclusive features: that information should live in adapter-specific docs, which could be improved for this specific stlib Duration feature of Postgrex the author (and later, I) was struggling with.

Or are you simply referring to Ecto documenting somewhere the information that schema and migration DSLs are not guaranteed to align? I agree that might be helpful to newcomers to Ecto! Just pointing out that that concept is unrelated to this post.

I think you might be confused about what exactly the author was struggling with: the correct incantation of Postgrex.Types.define/3 to get schemas to hydrate :duration fields into stdlib Duration structs instead of Postgrex.Duration ones. It’s a feature that Postgrex documents exists, but does not provide enough information to leverage. It’s unrelated to schema/migration DSL differences or any confusion around that.

D4no0

D4no0

OK, this makes more sense now. I always thought that postgrex was strictly doing the plumbing between ecto ↔ postgres, this is the first time I hear about it offering extensions for postgres specific types that can be used in ecto, even though logically that makes perfect sense.

nicnilov

nicnilov

I apologize for not making my original post clear enough to highlight the main point, and thank @christhekeele for explaining it with such precision. While I agree the Postgrex documentation should be improved, I don’t expect to do it myself, so the task is up for grabs for anyone who wants it.

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New

Other popular topics Top

JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 53690 245
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New

We're in Beta

About us Mission Statement