joseraya
1/13/2017 - 10:28 PM

Proof of concept of a ResultSet to case class mapper in scala

Proof of concept of a ResultSet to case class mapper in scala

import java.sql.ResultSet

object ResultSetReaders {

  trait Reader[T] {
    def fromResultSet(column: Int, rs: ResultSet): T
  }

  implicit val stringReader = new Reader[String] {
    override def fromResultSet(column: Int, rs: ResultSet): String = {
      rs.getString(column)
    }
  }

  implicit val intReader = new Reader[Int] {
    override def fromResultSet(column: Int, rs: ResultSet): Int = {
      rs.getInt(column)
    }
  }
}

import ResultSetReaders._

object Mapper {
  def apply[T, V, R](constructor: (T, V) => R)(implicit evT: Reader[T], evV: Reader[V]): ResultSet => R = {
    (rs: ResultSet) => {
      constructor(
        evT.fromResultSet(1, rs),
        evV.fromResultSet(2, rs)
      )
    }
  }

  def apply[T, V, W, R](constructor: (T, V, W) => R)(implicit evT: Reader[T], evV: Reader[V], evW: Reader[W]): ResultSet => R = {
    (rs: ResultSet) => {
      constructor(
        evT.fromResultSet(1, rs),
        evV.fromResultSet(2, rs),
        evW.fromResultSet(3, rs)
      )
    }
  }
}

object SequenceMapper {
  def apply[T, V, R](constructor: (T, V) => R)(implicit evT: Reader[T], evV: Reader[V]): ResultSet => Seq[R] = {
    buildSequenceMapper(Mapper(constructor))
  }
  
  def apply[T, V, W, R](constructor: (T, V, W) => R)(implicit evT: Reader[T], evV: Reader[V], evW: Reader[W]): ResultSet => Seq[R] = {
    buildSequenceMapper(Mapper(constructor))
  }

  private def buildSequenceMapper[T,R](mapper:ResultSet => R): (ResultSet) => Seq[R] = {
    (rs:ResultSet) => {
      val result = scala.collection.mutable.ListBuffer.empty[R]
      while (rs.next()) {
        result.append(mapper(rs))
      }
      result
    }
  }
}

val rs = new org.h2.tools.SimpleResultSet()
rs.addColumn("name", java.sql.Types.VARCHAR, 80, 0)
rs.addColumn("points", java.sql.Types.INTEGER, 80, 0)

rs.addRow("Jose", new Integer(4))

case class Score(name: String, points: Int)

val personMapper: (ResultSet) => Seq[Score] = SequenceMapper(Score.apply _)

val s = personMapper(rs).head

val rs3 = new org.h2.tools.SimpleResultSet()
rs3.addColumn("name", java.sql.Types.VARCHAR, 80, 0)
rs3.addColumn("points", java.sql.Types.INTEGER, 80, 0)
rs3.addColumn("ranking", java.sql.Types.INTEGER, 80, 0)

rs3.addRow("Jose", new Integer(4), new Integer(2))

case class ScoreWithRanking(name: String, points: Int,ranking: Int)

val rankingMapper: (ResultSet) => Seq[ScoreWithRanking] = SequenceMapper(ScoreWithRanking.apply _)

rankingMapper(rs3).head