Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repo.embedded_load/3 convenience #3269

Closed
narrowtux opened this issue Apr 6, 2020 · 5 comments
Closed

Repo.embedded_load/3 convenience #3269

narrowtux opened this issue Apr 6, 2020 · 5 comments

Comments

@narrowtux
Copy link
Contributor

When I write queries that filter within embedded fields that are backed by JSON, I see no simple way to select the filtered embeds so they're correctly loaded using the ecto type system.

My example goes like this:

      limits_query = from l in License,
        select: %{
          limit: fragment("jsonb_array_elements(?)", l.limits),
          valid_from: l.valid_from,
          valid_until: l.valid_until
        }

      query = from l in subquery(limits_query),
        select: l.limit,
        where: fragment("? >= now()", l.valid_until),
        where: fragment("? <= now()", l.valid_from),
        where: fragment("(? -> 'category') = ?::jsonb", l.limit, ^category)

The License schema has embeds_many :limits, Limit which is backed by a jsonb field.

What I tried to load the resulting json documents into actual %Limit{} structs was to map the results through the Repo.load/2 function like this:

Repo.all(query)
|> Enum.map(&Repo.load(Limit, &1))

However, since the primary key type is Ecto.UUID, it won't actually work with Ecto.UUID.load since that one expects a binary UUID and not a UUID in text form.

So I propose a new convenience function embedded_load(schema, data, format) that uses Ecto.Type.embedded_load/3 internally so I can fix my example like this:

Repo.all(query)
|> Enum.map(&Repo.embedded_load(Limit, &1, :json))

If there's any other way to prevent having to load manually I'd be glad to hear it :)

@josevalim
Copy link
Member

A PR would be welcome!

@narrowtux
Copy link
Contributor Author

I can try, I'm stuck now anyway :D

@josevalim
Copy link
Member

If you want to get unstuck, you can return this select: map(l, :limits) and then extract them out in Elixir land.

@narrowtux
Copy link
Contributor Author

It was actually pretty easy, in repo/schema.ex:

  def embedded_load(_adapter, schema_or_types, data, format) do
    do_load(schema_or_types, data, &Ecto.Type.embedded_load(&1, &2, format))
  end

PR will follow shorltly

narrowtux added a commit to narrowtux/ecto that referenced this issue Apr 6, 2020
@josevalim
Copy link
Member

Closing in favor of PR!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants