Question

We have a trait that among other things contains an execute[T <: Record](Seq[(Session) => T]): Seq[T] method, where Record is the supertrait of all traits that we're retrieving from the database

trait DbTrait {
  val threadCount: Int
  val db: Database
  protected def getGroupSize(size: Int, threadCount: Int) {
    (size / threadCount) + if(size % threadCount == 0) 0 else 1
  }
  def execute[T <: Record](funs: Seq[(Session) => T]): Seq[T]
}

trait DbTraitSingle extends DbTrait {
  val threadCount = 1
  def execute[T <: Record](funs: Seq[(Session) => T]): Seq[T] =
    db.withSession{session: Session => funs.map(f => f(session))}
}

trait DbTraitMulti extends DbTrait {
  val threadCount = 4
  def execute[T <: Record](funs: Seq[(Session) => T): Seq[T] =
    funs.grouped(getGroupSize(funs.size, threadCount)).map(funs => Future {
      db.withSession{session: Session => funs.map(f => f(session))}
    }.toList.flatten
}

and so on. Ideally we'd like to be able to create something like a

def executePoly2[T1 <: Record, T2 <: Record]
  (tuple: Tuple2[(Session) => T1, (Session) => T2]): Tuple2[T1, T2]

for arbitrary tuples (i.e. an executePoly3, executePoly4, etc), but there are two problems:

  1. Is there a way to reduce the amount of boilerplate here, or would we be stuck creating 22 different method signatures?
  2. Is there a type-safe way to split up a tuple similar to the seq.grouped method call, or are we stuck having special cases for all of the different threadCount values (which at present doesn't exceed 4)?
Was it helpful?

Solution

You can get to something very easy to use using the Shapeless library by Miles Sabin. See what they can do with a Tuple. Specifically abstracting over arity.

 import syntax.std.tuple._
 import poly._

 var myProducedTuple = myTuple map (_(session))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top