Created
September 16, 2011 16:26
-
-
Save taku0/1222477 to your computer and use it in GitHub Desktop.
オレオレJDBCラッパのプロトタイプ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.sql.ResultSet | |
import java.sql.PreparedStatement | |
import java.sql.Connection | |
import java.sql.Types | |
trait RowParser[A] extends ((ResultSet, Int) => A) { | |
def arity: Int | |
def apply(resultSet: ResultSet, index: Int): A | |
} | |
object RowParser { | |
implicit object IntParser extends RowParser[Int] { | |
def arity = 1 | |
def apply(resultSet: ResultSet, index: Int) = { | |
resultSet.getInt(index) | |
} | |
} | |
implicit def functionToParser1[A1, R](f: A1 => R)(implicit parser1: RowParser[A1]): RowParser[R] = { | |
new RowParser[R] { | |
def arity = parser1.arity | |
def apply(resultSet: ResultSet, index: Int) = { | |
f(parser1(resultSet, index)) | |
} | |
} | |
} | |
implicit def functionToParser2[A1, A2, R](f: (A1, A2) => R)(implicit parser1: RowParser[A1], parser2: RowParser[A2]): RowParser[R] = { | |
new RowParser[R] { | |
def arity = parser1.arity + parser2.arity | |
def apply(resultSet: ResultSet, index: Int) = { | |
f(parser1(resultSet, index), | |
parser2(resultSet, index + parser1.arity)) | |
} | |
} | |
} | |
} | |
trait ParameterSetter { | |
def arity: Int | |
def setTo(index: Int, statement: PreparedStatement) | |
def setNull(index: Int, statement: PreparedStatement) | |
} | |
object ParameterSetter { | |
implicit def fromInt(value: Int): ParameterSetter = new ParameterSetter { | |
def arity = 1 | |
def setTo(index: Int, statement: PreparedStatement) { | |
statement.setInt(index, value) | |
} | |
def setNull(index: Int, statement: PreparedStatement) { | |
statement.setNull(index, Types.INTEGER) | |
} | |
} | |
implicit def fromOption1[A1 <% ParameterSetter](option: Option[A1]): ParameterSetter = { | |
new ParameterSetter { | |
def arity = { | |
(null.asInstanceOf[A1]).arity | |
} | |
def setTo(index: Int, statement: PreparedStatement) = { | |
option match { | |
case Some(a1) => { | |
a1.setTo(index, statement) | |
} | |
case None => { | |
setNull(index, statement) | |
} | |
} | |
} | |
def setNull(index: Int, statement: PreparedStatement) = { | |
(null.asInstanceOf[A1]).setNull(index, statement) | |
} | |
} | |
} | |
implicit def fromOption2[A1 <% ParameterSetter, A2 <% ParameterSetter](option: Option[(A1, A2)]): ParameterSetter = { | |
new ParameterSetter { | |
def arity = { | |
(null.asInstanceOf[A1]).arity + (null.asInstanceOf[A2]).arity | |
} | |
def setTo(index: Int, statement: PreparedStatement) = { | |
option match { | |
case Some((a1, a2)) => { | |
a1.setTo(index, statement) | |
a2.setTo(index + a1.arity, statement) | |
} | |
case None => { | |
setNull(index, statement) | |
} | |
} | |
} | |
def setNull(index: Int, statement: PreparedStatement) = { | |
val a1 = null.asInstanceOf[A1] | |
val a2 = null.asInstanceOf[A2] | |
a1.setNull(index, statement) | |
a2.setNull(index + a1.arity, statement) | |
} | |
} | |
} | |
} | |
class RichConnection(connection: Connection) { | |
def queryIterable[A](sql: String, setters: ParameterSetter*)(implicit parser: RowParser[A]): Iterable[A] = { | |
val statement = connection.prepareStatement(sql) | |
try { | |
setParameters(statement, setters) | |
val resultSet = statement.executeQuery | |
val builder = Iterable.newBuilder[A] | |
while (resultSet.next()) { | |
builder += parser(resultSet, 1) | |
} | |
builder.result | |
} finally { | |
statement.close() | |
} | |
} | |
def executeUpdate[A](sql: String, setters: ParameterSetter*): Int = { | |
val statement = connection.prepareStatement(sql) | |
try { | |
setParameters(statement, setters) | |
statement.executeUpdate() | |
} finally { | |
statement.close() | |
} | |
} | |
protected def setParameters(statement: PreparedStatement, setters: Seq[ParameterSetter]) { | |
var index = 1 | |
for (setter <- setters) { | |
setter.setTo(index, statement) | |
index += setter.arity | |
} | |
} | |
} | |
case class Foo(a: Int, b: Int) | |
object Foo { | |
implicit val parser: RowParser[Foo] = (apply _) | |
implicit def toSetter(foo: Foo): ParameterSetter = unapply(foo) | |
} | |
case class Bar(a: Foo, b: Int) | |
object Bar { | |
implicit val parser = (apply _): RowParser[Bar] | |
implicit def toSetter(bar: Bar): ParameterSetter = unapply(bar) | |
} | |
case class Buz(a: Int, b: Bar) | |
object Buz { | |
implicit val parser = (apply _): RowParser[Buz] | |
implicit def toSetter(buz: Buz): ParameterSetter = unapply(buz) | |
} | |
object Main extends App { | |
println(implicitly[RowParser[Buz]].arity) | |
println((null.asInstanceOf[Buz]).arity) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment