Last active
June 2, 2016 09:51
-
-
Save poetix/878dd73ccced0899ac34cdf7fd448eca to your computer and use it in GitHub Desktop.
SQL -> Data Class mapping without reflection
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
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