al2o3cr

al2o3cr

Typecasting tuple results with Ecto

Related but different from Ecto IN clauses with tuples

Is there any way to specify a type for an expression that returns what Postgrex describes as “Anonymous composite types” and decodes to tuples?

This arose in an Ecto fragment:

fragment("array_agg((?, ?))", o.id, o.inserted_at)

which produces an array of {integer, datetime} tuples. The inserted_at values are returned as NaiveDateTime because Postgrex decodes them that way.

Trying to fix that with Ecto.Query.API.type/2 fails:

# Aspirational API - does not work like this
type(fragment("array_agg((?, ?))", o.id, o.inserted_at), {:array, {:integer, :utc_datetime_usec}})

with this error message:

(ArgumentError) unsupported type `{:integer, :utc_datetime_usec}`. The type can either be an atom, a string or a tuple of the form `{:map, t}` or `{:array, t}` where `t` itself follows the same conditions.

and stacktrace:

(ecto_sql 3.5.3) lib/ecto/adapters/postgres/connection.ex:1286: Ecto.Adapters.Postgres.Connection.ecto_to_db/1
(ecto_sql 3.5.3) lib/ecto/adapters/postgres/connection.ex:723: Ecto.Adapters.Postgres.Connection.tagged_to_db/1
(ecto_sql 3.5.3) lib/ecto/adapters/postgres/connection.ex:698: Ecto.Adapters.Postgres.Connection.expr/3
(ecto_sql 3.5.3) lib/ecto/adapters/postgres/connection.ex:1238: Ecto.Adapters.Postgres.Connection.intersperse_map/4
(ecto_sql 3.5.3) lib/ecto/adapters/postgres/connection.ex:319: Ecto.Adapters.Postgres.Connection.select/3
(ecto_sql 3.5.3) lib/ecto/adapters/postgres/connection.ex:113: Ecto.Adapters.Postgres.Connection.all/2
(ecto_sql 3.5.3) lib/ecto/adapters/postgres.ex:102: Ecto.Adapters.Postgres.prepare/2
(ecto 3.5.5) lib/ecto/query/planner.ex:180: Ecto.Query.Planner.query_without_cache/4
(ecto 3.5.5) lib/ecto/query/planner.ex:150: Ecto.Query.Planner.query_prepare/6
(ecto 3.5.5) lib/ecto/query/planner.ex:125: Ecto.Query.Planner.query_with_cache/7
(ecto 3.5.5) lib/ecto/repo/queryable.ex:213: Ecto.Repo.Queryable.execute/4
(ecto 3.5.5) lib/ecto/repo/queryable.ex:17: Ecto.Repo.Queryable.all/3
...

Support for these kinds of data has been added in limited cases (for IN clauses with literals) but I couldn’t find any discussion of typecasting. Has this come up before?

If this feature did exist, what would the syntax look like? A bare tuple of types looks nice, but {:array, {:tuple, [:integer, :utc_datetime_usec]}} would be more in harmony with the other keywords (:array and :map ) and avoid wrangling variable-size tuples. It would match the format already used in the planner, though there is this note about “not wanting to allow fields of this type”.

Trying that syntax in Ecto fails to even compile:

# Aspirational API - does not work like this
type(fragment("array_agg((?, ?))", o.id, o.inserted_at), {:array, {:tuple, [:integer, :utc_datetime_usec]}})

# gets the error
** (Ecto.Query.CompileError) type/2 expects an alias, atom or source.field as second argument, got: `[:integer, :utc_datetime_usec]`
    (ecto 3.5.5) expanding macro: Ecto.Query.select/3
    iex:14: (file)
    (ecto 3.5.5) expanding macro: Ecto.Query.where/3
    iex:14: (file)
    (ecto 3.5.5) expanding macro: Ecto.Query.group_by/3
    iex:14: (file)
    (ecto 3.5.5) expanding macro: Ecto.Query.limit/3
    iex:14: (file)

First Post!

LostKobrakai

LostKobrakai

Does this help?

Where Next?

Popular in Questions Top

LegitStack
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it. I’m very interested in Elixir,...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
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
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
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
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New

We're in Beta

About us Mission Statement