Merge pull request #116 from cy6erGn0m/3cf1fd5377f4cf6c719c93f513bbd2b96a1213b3

kotlin-jdbc: Additional extenstions to work with ResultSet
This commit is contained in:
James Strachan
2012-08-02 03:38:06 -07:00
3 changed files with 171 additions and 2 deletions
@@ -3,9 +3,47 @@ package kotlin.jdbc
import java.sql.*
import kotlin.template.StringTemplate
import java.math.BigDecimal
import java.util.Map
import java.util.Properties
private fun Map<String, String>.toProperties() : Properties {
val p = Properties()
this.keySet().forEach {
p.put(it, this[it])
}
return p
}
/**
* Helper method to process a statement on this collection
* create connection for the specified jdbc url with no credentials
*/
fun getConnection(url : String) : Connection = DriverManager.getConnection(url).sure()
/**
* create connection for the specified jdbc url and properties
*/
fun getConnection(url : String, info : Map<String, String>) : Connection = DriverManager.getConnection(url, info.toProperties())!!
/**
* create connection for the specified jdbc url and credentials
*/
fun getConnection(url : String, user : String, password : String) : Connection = DriverManager.getConnection(url, user, password)!!
/**
* Executes specified block with connection and close connection after this
*/
fun Connection.use(block : (Connection) -> Any?) : Unit {
try {
block(this)
} finally {
this.close()
}
}
/**
* Helper method to process a statement on this connection
*/
fun <T> Connection.statement(block: (Statement) -> T): T {
val statement = createStatement()
@@ -4,6 +4,18 @@ import java.sql.*
import java.util.ArrayList
import java.util.Collection
import java.util.List
import java.util.Map
/**
* Executes the specfied block with result set and then closes it
*/
public fun <R> ResultSet.use(block : (ResultSet) -> R) : R {
try {
return block(this)
} finally {
this.close()
}
}
/**
* Creates an iterator through a [[ResultSet]]
@@ -18,6 +30,56 @@ fun ResultSet.iterator() : Iterator<ResultSet> {
}
}
/**
* Returns iterable that calls to the specified mapper function for each row
*/
fun <T> ResultSet.getMapped(fn : (ResultSet) -> T) : jet.Iterable<T> {
val rs = this
val iterator = object : Iterator<T>{
public override val hasNext : Boolean
get() = rs.next()
public override fun next() : T = fn(rs)
}
return object : jet.Iterable<T> {
public override fun iterator(): Iterator<T> = iterator
}
}
/**
* Returns array with column names
*/
fun ResultSet.getColumnNames() : jet.Array<String> {
val meta = getMetaData().sure()
return jet.Array<String>(meta.getColumnCount(), {meta.getColumnName(it + 1) ?: it.toString()})
}
/**
* Return array filled with values from current row in the cursor. Values will have the same order as column's order
* @columnNames you can specify column names to extract otherwise all columns will be extracted
*/
fun ResultSet.getValues(columnNames : jet.Array<String> = getColumnNames()) : jet.Array<Any?> {
return jet.Array<Any?>(columnNames.size, {
this[columnNames[it]]
})
}
/**
* Return map filled with values from current row in the cursor. Uses column names as keys for result map.
* @param columnNames you can specify column names to extract otherwise all columns will be extracted
*/
fun ResultSet.getValuesAsMap(columnNames : jet.Array<String> = getColumnNames()) : java.util.Map<String, Any?> {
val result = java.util.HashMap<String, Any?>(columnNames.size)
columnNames.forEach {
result[it] = this[it]
}
return result
}
/**
* Returns the value at the given column index (starting at 1)
*/
@@ -47,3 +109,26 @@ fun <T> ResultSet.mapTo(result: Collection<T>, fn: (ResultSet) -> T) : Collectio
}
return result
}
private fun ResultSet.ensureHasRow() : ResultSet {
if (!next()) {
throw IllegalStateException("There are no rows left in cursor")
}
return this
}
/**
* Returns int value from the cursor at first column. May be useful to get result of count(*)
*/
fun ResultSet.singleInt() : Int = ensureHasRow().getInt(1)
/**
* Returns long value from the cursor at first column.
*/
fun ResultSet.singleLong() : Long = ensureHasRow().getLong(1)
/**
* Returns double value from the cursor at first column.
*/
fun ResultSet.singleDouble() : Double = ensureHasRow().getDouble(1)
@@ -7,6 +7,8 @@ import junit.framework.TestCase
import org.h2.jdbcx.JdbcDataSource
import javax.sql.DataSource
import org.h2.jdbcx.JdbcConnectionPool
import kotlin.nullable.forEach
import java.sql.ResultSet
public val dataSource : DataSource = createDataSource()
@@ -40,4 +42,48 @@ class JdbcTest : TestCase() {
}
}
}
}
fun testGetValuesAsMap() {
dataSource.query("select * from foo") {
for (row in it) {
println(row.getValuesAsMap())
}
}
}
fun testStringFormat() {
dataSource.query(kotlin.template.StringTemplate(array("select * from foo where id = ", 1))) {
for (row in it) {
println(row.getValuesAsMap())
}
}
}
fun testMapIterator() {
val mapper = { (rs : ResultSet) ->
"id: ${rs["id"]}"
}
dataSource.query("select * from foo") {
for (row in it.getMapped(mapper)) {
println(row)
}
}
}
fun testCount() {
dataSource.query("select count(*) from foo") {
println("count: ${it.singleInt()}")
}
}
fun testFormatCursor() {
dataSource.query("select * from foo") {
println(it.getColumnNames().toList().makeString("\t"))
for (row in it) {
println(it.getValues().makeString("\t"))
}
}
}
}