Skip to content

Instantly share code, notes, and snippets.

@poetix
Last active June 2, 2016 09:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save poetix/878dd73ccced0899ac34cdf7fd448eca to your computer and use it in GitHub Desktop.
Save poetix/878dd73ccced0899ac34cdf7fd448eca to your computer and use it in GitHub Desktop.
SQL -> Data Class mapping without reflection
package com.codepoetics.kontinuous
import java.sql.Connection
import java.sql.PreparedStatement
import java.sql.ResultSet
data class Foo(val a: String, val b: Int, val c: Double)
interface RowN {
val selectSql: String
val insertSql: String
}
abstract class TableN<KC, R : RowN>(val tableName: String) {
abstract val row: R
fun <T> col(columnName: String): Col<T> = Col<T>(tableName, columnName)
fun save(conn: Connection, value: KC): Boolean {
val ps = conn.prepareStatement(row.insertSql);
try {
return executeInsert(ps, value)
} finally {
ps.close()
}
}
abstract fun executeInsert(ps: PreparedStatement, value: KC): Boolean
fun fetchAll(conn: Connection): List<KC> {
val ps = conn.prepareStatement(row.selectSql);
try {
val rs = ps.executeQuery()
try {
val results = mutableListOf<KC>()
while (rs.next()) {
results.add(translateRow(rs))
}
return results
} finally {
rs.close()
}
} finally {
ps.close()
}
}
abstract fun translateRow(rs: ResultSet): KC
}
abstract class Table3<A, B, C, KC>(tableName: String): TableN<KC, Row3<A, B, C>>(tableName) {
abstract val ctor: (A, B, C) -> KC
abstract val dtor: KC.(f: (A, B, C) -> Boolean) -> Boolean
fun makeDtor(d: KC.(f: (A, B, C) -> Boolean) -> Boolean): KC.(f: (A, B, C) -> Boolean) -> Boolean = d
fun rowOf(col1: Col<A>, col2: Col<B>, col3: Col<C>): Row3<A, B, C> = Row3(col1, col2, col3)
override fun executeInsert(ps: PreparedStatement, value: KC): Boolean =
value.dtor { a, b, c ->
with(ps) {
setObject(0, a)
setObject(1, b)
setObject(2, c)
}
ps.execute()
}
override fun translateRow(rs: ResultSet): KC =
ctor(rs.getObject(1) as A, rs.getObject(2) as B, rs.getObject(3) as C)
}
data class Col<T>(val tableName: String, val name: String)
data class Row3<A, B, C>(val col1: Col<A>, val col2: Col<B>, val col3: Col<C>): RowN {
override val insertSql: String =
"INSERT INTO ${col1.tableName} (${col1.name}, ${col2.name}, ${col3.name}) VALUES (?, ?, ?)"
override val selectSql: String =
"SELECT ${col1.name}, ${col2.name}, ${col3.name} FROM ${col1.tableName}"
}
val myTable = object : Table3<String, Int, Double, Foo>("mytable") {
val foo = col<String>("foo")
val bar = col<Int>("bar")
val baz = col<Double>("baz")
override val row = rowOf(foo, bar, baz)
override val dtor = makeDtor { f -> f(a, b, c) }
override val ctor = ::Foo
}
fun saveExample(conn: Connection): Boolean = myTable.save(conn, Foo("foo", 12, 3.6))
fun fetchAllExample(conn: Connection): List<Foo> = myTable.fetchAll(conn)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment