This example was selected for the following reasons:
Convert relational data ...
CREATE TABLE EXAMPLE(ID INT PRIMARY KEY, DESCRIPTION VARCHAR);
INSERT INTO EXAMPLE(ID, DESCRIPTION) VALUES(0, 'Zero');
INSERT INTO EXAMPLE(ID, DESCRIPTION) VALUES(1, 'One');
INSERT INTO EXAMPLE(ID, DESCRIPTION) VALUES(2, 'Two');
INSERT INTO EXAMPLE(ID, DESCRIPTION) VALUES(3, 'Three');
INSERT INTO EXAMPLE(ID, DESCRIPTION) VALUES(4, 'Four');
... to JSON
[
{"DESCRIPTION":"Zero","ID":0},
{"DESCRIPTION":"One","ID":1},
{"DESCRIPTION":"Two","ID":2},
{"DESCRIPTION":"Three","ID":3},
{"DESCRIPTION":"Four","ID":4}
]
val connectionInfo = new Jdbc.ConnectionInfo("jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1")
val mapper = new ObjectMapper().registerModule(DefaultScalaModule)
def queryToJSON(conn: Jdbc.ConnectionInfo, sql: String) =
Jdbc.withResultsIterator(conn, sql, it => mapper.writeValueAsString(it))
def main(args: Array[String]) {
queryToJSON(connectionInfo, "SELECT * FROM EXAMPLE") match {
case Success(json) => println(json)
case Failure(e) => println(e.getMessage)
}
}
def queryToJSONPartial(conn: Jdbc.ConnectionInfo, sql: String, start: Int, rows: Int) =
Jdbc.withResultsIterator(
conn,
sql,
it => mapper.writeValueAsString(it.drop(start).take(rows))
)
queryToJSONPartial(connectionInfo, "SELECT * FROM EXAMPLE", 2, 2)
Produces
[
{"DESCRIPTION":"Two","ID":2},
{"DESCRIPTION":"Three","ID":3},
]
Connection conn = DriverManager.getConnection("url", "user", "pass");
try {
Statement stmt = conn.createStatement();
try {
ResultSet rs = stmt.executeQuery("SELECT * FROM EX");
try {
while (rs.next()) { ... }
} finally {
rs.close();
}
} finally {
stmt.close();
}
} finally {
conn.close();
}
case class ConnectionInfo(url: String, username: String = "", password: String = "")
def withConnection (connInfo: ConnectionInfo, f: Connection => Unit) {
...
}
def withConnection (connInfo: ConnectionInfo, f: Connection => Unit) {
val conn = DriverManager.getConnection(connInfo.url,
connInfo.username,
connInfo.password)
try {
f(conn)
}
finally {
conn.close()
}
}
def withConnection [T] (connInfo: ConnectionInfo, f: Connection => T): T = {
val conn = DriverManager.getConnection(connInfo.url,
connInfo.username,
connInfo.password)
try {
f(conn)
}
finally {
conn.close()
}
}
def withConnection [T] (connInfo: ConnectionInfo, f: Connection => T): Try[T] = {
val conn = DriverManager.getConnection(connInfo.url,
connInfo.username,
connInfo.password)
val result = Try(f(conn))
conn.close()
result
}
Now we finish the job for Statement and ResultSet
def withStatement [T] (connInfo: ConnectionInfo, f: Statement => T): Try[T] = {
def privFun(conn: Connection) = {
val stmt = conn.createStatement()
try {
f(stmt)
}
finally {
stmt.close()
}
}
withConnection(connInfo, privFun)
}
def withResultSet [T] (connInfo: ConnectionInfo, sql: String, f: ResultSet => T):Try[T]={
def privFun(stmt: Statement) = {
val resultSet = stmt.executeQuery(sql)
try {
f(resultSet)
}
finally {
resultSet.close()
}
}
withStatement(connInfo, privFun)
}
Our risk profile is about the same as before because of the complexity of the ResultSet interface which combines:
There are three appropriate "iterable" collection objects in Scala:
class ResultsIterator(resultSet: ResultSet) extends Iterator[ResultSet] {
def hasNext = resultSet.next()
def next() = resultSet
}
private val columnNames: Seq[String] = {
val rsmd: ResultSetMetaData = resultSet.getMetaData
for (i <- 1 to rsmd.getColumnCount) yield rsmd.getColumnName(i)
}
private def buildRowMap(resultSet: ResultSet): Map[String, AnyRef] = {
(
for (c <- columnNames) yield c -> resultSet.getObject(c)
).toMap
}
class ResultsIterator (resultSet: ResultSet) extends Iterator[Map[String, AnyRef]] {
val columnNames = { … }
private def buildRowMap(resultSet: ResultSet) = { ... }
def hasNext = resultSet.next()
def next() = buildRowMap(resultSet)
}
private def getNextRow(resultSet: ResultSet): Option[Map[String, AnyRef]] = {
if (resultSet.next())
Some(buildRowMap(resultSet))
else
None
}
class ResultsIterator (resultSet: ResultSet) extends Iterator[Map[String, AnyRef]]
{
val columnNames = { … }
private def buildRowMap(resultSet: ResultSet) = { … }
private def getNextRow(resultSet: ResultSet) = { … }
var nextRow = getNextRow(resultSet)
def hasNext = nextRow.isDefined
def next() = {
val rowData = nextRow.get
nextRow = getNextRow(resultSet)
rowData
}
}
def withResultsIterator [T] (connInfo: ConnectionInfo,
sql: String,
itFun: ResultsIterator => T): Try[T] =
withResultSet(connInfo, sql, resultSet => itFun(new ResultsIterator(resultSet)))
val connectionInfo = new Jdbc.ConnectionInfo("jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1")
val mapper = new ObjectMapper()registerModule(DefaultScalaModule)
def queryToJSON(conn: Jdbc.ConnectionInfo, sql: String) =
Jdbc.withResultsIterator(conn, sql, it => mapper.writeValueAsString(it))
def main(args: Array[String]) {
queryToJSON(connectionInfo, "SELECT * FROM EXAMPLE") match {
case Success(json) => println(json)
case Failure(e) => println(e.getMessage)
}
}
https://github.com/MartinSnyder/scala-jdbc
Requires git, jdk8
git clone https://github.com/MartinSnyder/scala-jdbc.git
gradlew test run