0

I am attempting to develop a small component for a Play-based service and am struggling with how to go about the design. I need a service that provides access to "file storage" in various environments. My initial idea is simply to create a trait that represents the two primary operations (write/read) and then autowire the implementation based on configuration at runtime. The interface looks something like the following:

trait StorageService {
  def saveFile(name: String): Sink[ByteString, Future[Try[FileHandle]]]
  def readFile(handle: FileHandle): Source[ByteString]
}

The service allows a user to save a file to disk and returns a FileHandle object that contains all of the information the service needs to identify the specific file. The issue I'm having is that the FileHandle needs different information for each concrete implementation. Now, I can use F-bound polymorphism on the trait to solve this like so:

trait StorageService[A <: FileHandle] {
  def saveFile(name: String): Sink[ByteString, Future[Try[A]]]
  def readFile(handle: A): Source[ByteString]
}

However, the issue here becomes autowiring as I cannot wire the concrete implementations as StorageService providers without specifying the type parameter. Does anyone have a suggestion on how to accomplish this autowiring or perhaps a better design?

Jeffrey Chung
  • 19,319
  • 8
  • 34
  • 54
DaveStance
  • 421
  • 1
  • 4
  • 17

0 Answers0