Using repositories with dry-auto_inject

I have two repositories:

  • nodes
  • texts

There are cases when the result of a call to the text repository requires access to the nodes repository, e.g.:

class TextRepository < Rom::Repository[:texts]
  def initialize(manager:, node_repository:, variant_builder: Model::Variant)
    super(manager.rom)
    @node_repository = node_repository
    @variant_builder = variant_builder
    @text_builder = Content
  end
  
  def by_node_ids(ids, variant=nil)
    query = texts.where(node_id: ids)
    query = query.where(variant_name: variant.compatible_variants) if variant
    query
  end

  def select(selector)
    nodes = @node_repository.select(selector)
    self.by_node_ids(nodes.map(&:db_id), @variant_builder.new(selector[:variant])).to_a
  end
end

So far I have used manual dependency management, as you can see in the initialize method. Yet recently I started using dry-repository and dry-auto_inject and here lays the problem.

To make the NodeRepository available in the TextRepository I would have to declare the NodeRepository in the container and call super in order for the dependencies to be auto-injected. Yet, on the other hand, the TextRepository inherits from Rom::Repository and I have to call super with Rom instance. Those two scenarios are not going to work together. So, since I know that you (@solnic in particular) use dry-auto_inject with rom I would be happy to know the best solution for this kind of a problem.

dry-auto_inject doesn’t work with constructors which accept both positioned args and option hashes, and that’s the type of constructor repos have. We could either tweak dry-auto_inject somehow to work with mixed-style constructors, or just change repo constructors to accept options exclusively.

I guess the second option is simpler to implement but it would impact users of ROM, but from my POV this change would be better.