Ecto: Dynamic built preload when using JOINs

Is there any way to build the bindings and expression for Ecto.Query.preload/2 dynamically?

I am currently using joins to construct my query similar to this:

def preload(queryable, parent_id) do 
  |> join( 
      [{^parent_id, parent}], 
      parameter_list in assoc(parent, :parameter_list_history),  
      on: == true and 
        parameter_list.revision <= parent.parameter_list_revision,
      as: :inventory_parameterlist_history

parent_id is provided by the recursive function that composes the query for my associations.
The reason I am using joins and not just letting Ecto handle the preload is that I need to filter the associations based on a value parameter_list_revision from a parent up in the hierarchy of associations.

This approach works very well to compose the query and it results in something like this:

from d0 in ConfigAdmin.Config.Plant.Draft,
  as: :draft,
  left_join: d1 in assoc(d0, :devices),
  as: :config_device_draft,
  on: == true,
  left_join: p2 in assoc(d1, :parameter_list_history),
  as: :inventory_parameterlist_history,
  on: == true and p2.revision <= d1.parameter_list_revision

My problem arises when I need to call the Ecto.Query.preload/2 function.
This function appears to require the bindings and expression to be defined before compile-time.

In my code I have this now just to test that the rest works as expected:

|>Ecto.Query.preload([config_device_draft: cdd, inventory_parameterlist_history: iph], [ 
    {cdd, [{:parameter_list_history, iph}]}} 

I would like to generate the code above somehow based on my association hierarchy.

I have investigated using macros to do this but I cant seem to grasp the concept good enough…

Any suggestions on how this could be done?
Or if its possible at all, or if there would be a smarter way of doing this?

Thank you,
Morten Lund