Using Dry::Effect resolver with ROM Repositories

Hello!

At my company, we are building an app that will manage the database of our multiples tenants.

This app has its own ROM container for its own database, and we are building a dynamic container resolver for the part that will manage a tenant database.

We store the container inside a simple relation

module Infrastructure
  module Relations
    class EnvironementConnections < ROM::Relation[:memory]
      gateway :memory

      schema(:environement_containers) do
        attribute :environement_id, Types::String.meta(primary_key: true)
        attribute :container, Types.Instance(ROM::Container)
      end
    end
  end
end

Above that, I am building a middleware for injecting the dynamic container

module Application
  module Middlewares
    class EnvironementResolver
      include Dry::Effects::Handler.Resolve
      include Dry::Monads[:maybe]

      def initialize(app, container_resolver:)
        @app = app
        @container_resolver = container_resolver
      end

      def call(env)
        acquire_connection = @container_resolver.for_environement(env['HTTP_MEMORY_ENVIRONEMENT'])

        case acquire_connection
        in Some(connection)
          provide(container: connection.container) { @app.call(env) }
        in None()
          @app.call(env)
        end
      end
    end
  end
end

And then, when calling the repository I want it to be dynamically injected

module MemoryInfrastructure
  module Repositories
    class UserRepository < ROM::Repository[:users]

      include Dry::Effects.Resolve(:container)

      def all
        users.limit(10).to_a
      end

    end
  end
end

The problem is that it didn’t work because ROM::Repository overwrite the new method.

How can I work around that?

I could call manually the class from the controller MemoryInfrastructure::Repositories::UserRepository.new(container).all but I lost the advantage of dynamic injection.

Any idea?

I have found a work around but I strongly dislike it! :frowning:

module MemoryInfrastructure
  module Repositories
    class UserRepository < ROM::Repository[:users]
      class Builder
        include Dry::Effects.Resolve(:container)

        def initialize(*args, **kwargs)
          @args = args
          @kwargs = kwargs
        end

        def build
          UserRepository.new(container, *@args, **@kwargs, is_real: true)
        end
      end

      module ClassMethods
        def new(*args, is_real: false, **kwargs)
          if is_real
            super(*args, **kwargs)
          else
            Builder.new(*args, **kwargs)
          end
        end
      end

      extend ClassMethods

      def all
        users.limit(10).to_a
      end

    end
  end
end

If you have any idea I’m taking it :slight_smile: