skip to Main Content

I have a function in Elixir using Ecto that preloads associations for a given entity. The current implementation looks like this:

@spec get(integer() | String.t(), list()) :: t() | nil
def get(id, preloads \ []) do
  Shop
  |> Repo.get(id)
  |> Repo.preload(preloads)
end

i use it like this:

      Shop.get(id, [
        :coustomers,
        :products
      ])

and is it possible do make it like this ?:

  Shop.get(id, [
    :coustomers,
    {:limit,:products,3}
  ])

2

Answers


  1. It is possible to limit the number of preloaded records, but it takes more than a one liner and is maybe not as flexible as you would hope or expect:

    products_query = from p in Product, limit: 3, order_by: p.inserted_at
    
    Shop
    |> get(id)
    |> preload([products: products_query]) 
    

    Maybe you can create a function that takes a Module and a number (for the limit) and returns something identical to the products_query above, like:

    def preload_query(module, limit) do
      from a in module, limit: ^limit
    end
    

    And use this as an argument for Shop.get/2:

    Shop.get(id, [:customers, products: preload_query(Product, 3)])
    
    Login or Signup to reply.
  2. I would do something like this:

    defmodule Shops do
      def get_shop(nil), do: nil
    
      def get_shop(shop_id) do
        limited_products =
          Product
          |> where(shop_id: ^shop_id)
          |> limit(3)
    
        Shop
        |> from(as: :shop)
        |> join(:inner, [shop: shop], product in subquery(limited_products), on: true, as: :products)
        |> select([shop: shop, products: products], %{shop | products: products})
        |> Repo.one()
      end
    end
    

    I have not tested this. It is just for illumination.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search