added a few experimental alternatives implementations of string templates for string/html/jdbc etc for KT-1565 seems there's a few ways we could do it...

This commit is contained in:
James Strachan
2012-03-12 20:46:44 +00:00
parent 3748507ac1
commit f927b38a14
17 changed files with 563 additions and 25 deletions
@@ -8,11 +8,7 @@ import java.sql.*
fun <T> Connection.statement(block: (Statement) -> T): T {
val statement = createStatement()
if (statement != null) {
try {
return block(statement)
} finally {
statement.close()
}
return statement.use(block)
} else {
throw IllegalStateException("No Statement returned from $this")
}
@@ -0,0 +1,27 @@
package kotlin.jdbc
/**
* Helper method to process a statement on this collection
*/
import java.sql.PreparedStatement
import java.sql.ResultSet
fun PreparedStatement.update(): Int {
try {
return this.executeUpdate()
} finally {
close()
}
}
fun <T> PreparedStatement.query(block: (ResultSet) -> T): T {
try {
val resultSet = this.executeQuery()
if (resultSet == null) {
throw IllegalStateException("No ResultSet returned from $this")
} else {
return block(resultSet)
}
} finally {
close()
}
}
@@ -0,0 +1,17 @@
package kotlin.jdbc
/**
* Helper method to process a statement on this collection
*/
import java.sql.Statement
/**
* Uses the statement with the given block then closes the statement
*/
fun <T> Statement.use(block : (Statement) -> T) : T {
try {
return block(this)
} finally {
close()
}
}
@@ -1,37 +1,38 @@
package test.kotlin.jdbc
import kotlin.jdbc.*
import kotlin.test.*
import kotlin.jdbc. *
import kotlin.test. *
import junit.framework.TestCase
import org.h2.jdbcx.JdbcDataSource
import javax.sql.DataSource
import org.h2.jdbcx.JdbcConnectionPool
fun createDataSource(): DataSource {
val pool = JdbcConnectionPool.create("jdbc:h2:mem:KotlinJdbcTest;DB_CLOSE_DELAY=-1", "user", "password")
if (pool == null) {
val dataSource = createDataSource()
fun createDataSource() : DataSource {
val dataSource = JdbcConnectionPool.create("jdbc:h2:mem:KotlinJdbcTest;DB_CLOSE_DELAY=-1", "user", "password")
if (dataSource == null) {
throw IllegalStateException("No DataSource created")
} else {
return pool
}
}
class JdbcTest : TestCase() {
val dataSource = createDataSource()
fun testDatabase() {
dataSource.update("create table foo (id int primary key, name varchar(100))")
assertEquals(1, dataSource.update("insert into foo (id, name) values (1, 'James')"))
assertEquals(1, dataSource.update("insert into foo (id, name) values (2, 'Andrey')"))
// lets query using integer lookups
return dataSource
}
}
class JdbcTest : TestCase() {
fun testQueryWithIndexColumnAccess() {
dataSource.query("select * from foo") {
for (row in it) {
println("id ${row[1]} and name: ${row[2]}")
}
}
}
fun testQueryWithNamedColumnAccess() {
// query using names
dataSource.query("select * from foo") {
for (row in it) {
@@ -0,0 +1,95 @@
package test.kotlin.jdbc.experiment1
import kotlin.template.experiment1.*
import kotlin.jdbc.*
import kotlin.test.*
import kotlin.util.arrayList
import junit.framework.TestCase
import javax.sql.DataSource
import test.kotlin.jdbc.createDataSource
import java.sql.Connection
import java.sql.PreparedStatement
import java.sql.ResultSet
fun DataSource.update(fn: (PreparedStatementBuilder) -> Unit): Int {
return use{ it.update(fn) }
}
fun <T> DataSource.query(fn: (PreparedStatementBuilder) -> Unit, resultBlock: (ResultSet) -> T): T {
return use{ it.query(fn, resultBlock) }
}
fun Connection.update(fn: (PreparedStatementBuilder) -> Unit): Int {
val preparedStatement = prepare(fn)
return preparedStatement.update()
}
fun <T> Connection.query(fn: (PreparedStatementBuilder) -> Unit, resultBlock: (ResultSet) -> T): T {
val preparedStatement = prepare(fn)
return preparedStatement.query(resultBlock)
}
fun Connection.prepare(fn: (PreparedStatementBuilder) -> Unit): PreparedStatement {
val builder = PreparedStatementBuilder(this)
fn(builder)
return builder.statement()
}
trait Binding {
fun bind(statement: PreparedStatement): Unit
}
class PreparedStatementBuilder(val connection: Connection) {
val sql = StringBuilder()
val tasks = arrayList<Binding>()
private var parameterIndex = 0
fun text(value: String): Unit {
// we assume all text is escaped already
sql.append(value)
}
fun expression(value: String): Unit {
sql.append("?")
tasks.add(object: Binding {
override fun bind(statement : PreparedStatement) {
statement.setString(nextParameterIndex(), value)
}
})
}
// TODO bind other kinds!
fun statement(): PreparedStatement {
val answer = connection.prepareStatement(sql.toString())
if (answer == null) {
throw IllegalStateException("No PreparedStatement returned from $connection")
} else {
for (task in tasks) {
task.bind(answer)
}
return answer
}
}
protected fun nextParameterIndex(): Int = ++parameterIndex
}
class JdbcTemplateTest : TestCase() {
//val dataSource = createDataSource()
fun testTemplateInsert() {
val id = 1
/*
dataSource.update {
it.text("select * from foo where id = ")
it.expression(id)
}
*/
}
}